Building RPM package from cross-compiled binaries Go app tarballs - go

I'm trying to create my first RPM packages cross-compiled with Go.
Here is the Makefile which contains all the required information:
APPNAME?=helloworld
VERSION?=v1.0.0
APPANDVER := ${APPNAME}-$(VERSION)
# Build flags
LDFLAGS := -ldflags "-s -w -X=main.VERSION=$(VERSION)"
# Temporary directory for common files when creating tarballs
RELEASETMPDIR := $(shell mktemp -d -t ${APPNAME}-${VERSION}-release-XXXXXX)
# Cross-compile to these CPUs
# https://golang.org/doc/install/source#environment
LINUX_ARCHS := amd64 arm arm64 ppc64 ppc64le
default: release-bin
main.go:
#echo 'package main' > $#
#echo 'import "fmt"' >> $#
#echo '// Replaced with version when building' >> $#
#echo 'var VERSION = "v0.0.0"' >> $#
#echo 'func main() {' >> $#
#echo ' fmt.Println("Hello, world!")' >> $#
#echo '}' >> $#
#go fmt $#
README.md:
#echo 'This is a README for $(APPNAME) $(VERSION)' > $#
#echo '$(APPNAME) simply prints "Hello, world!"' >> $#
LICENSE:
#echo 'You can do what ever you want with $(APPNAME).' > $#
#echo 'You have all the responsibility!' >> $#
# Build for all listed architectures
linux-build: main.go
#for arch in $(LINUX_ARCHS); do \
echo "GNU/Linux build... $$arch"; \
CGO_ENABLED=0 GOOS=linux GOARCH=$$arch go build $(LDFLAGS) -v -o ./bin/linux-$$arch/${APPNAME} . ; \
done
# Copy common files used in binary tarball releases
copycommon: README.md LICENSE
#echo "Copying common files to temporary release directory '$(RELEASETMPDIR)'.."
#mkdir "$(RELEASETMPDIR)/bin"
#cp -v "LICENSE" "$(RELEASETMPDIR)"
#cp -v "README.md" "$(RELEASETMPDIR)"
#mkdir --parents "$(PWD)/release/${VERSION}"
# Create binary release tarballs for each CPU architecture
compress-linux: linux-build
#for arch in $(LINUX_ARCHS); do \
echo "GNU/Linux tar... $$arch"; \
cp -v "$(PWD)/bin/linux-$$arch/${APPNAME}" "$(RELEASETMPDIR)/bin"; \
cd "$(RELEASETMPDIR)"; \
tar --numeric-owner --owner=0 --group=0 -zcvf "$(PWD)/release/${VERSION}/$(APPANDVER)-linux-$$arch.tar.gz" . ; \
rm "$(RELEASETMPDIR)/bin/${APPNAME}"; \
done
# Move all to temporary directory and compress with common files
compress-everything: copycommon compress-linux
#echo "$# ..."
rm -rf "$(RELEASETMPDIR)/*"
# Create tarballs which has common files and different bin/${APPNAME} per CPU architecture
release-bin: linux-build compress-everything
#echo "release done..."
# Linux distributions
release-ldistros: ldistro-rpm
#echo "Linux distros release done..."
release/linux/rpm:
#mkdir --parents ./release/linux/rpm
# RPM spec file (probably wrong)
release/linux/rpm/package.spec: release/linux/rpm
#echo 'Name: ${APPNAME}' > $#
#echo 'Version: %{_version}' >> $#
#echo 'Release: 1%{?dist}' >> $#
#echo 'Summary: Hello world' >> $#
#echo 'URL: https://example.org/${APPANDVER}/' >> $#
#echo 'Group: Applications/Utilities' >> $#
#echo 'License: Apache-2.0' >> $#
#echo '%description' >> $#
#echo '${APPNAME} is a command line program which prints "Hello, world!"' >> $#
#echo '%setup -q' >> $#
#echo '%clean' >> $#
#echo '%files' >> $#
#echo '%license /usr/share/licenses/%{NAME}/LICENSE' >> $#
#echo '%doc /usr/share/doc/%{NAME}/README.md' >> $#
#echo '/usr/bin/${APPNAME}' >> $#
#echo '%install' >> $#
#echo 'install -Dm755 "usr/bin/%{NAME}" -t "/usr/bin"' >> $#
# Create RPM package for each CPU architecture from tarballs (probably wrong)
ldistro-rpm: "release/linux/rpm/package.spec
#for arch in $(LINUX_ARCHS); do \
echo "Generating RPM... $$arch"; \
tempdir=$$(mktemp -d -t $(APPANDVER)-rpm-XXXXXX) ; \
echo " >> Using temporary directory $$tempdir" ; \
cd "$$tempdir" ; \
mkdir --parents {SOURCES,RPMS,SPECS,SRPMS,BUILD,tmp} ; \
cp "$(PWD)/release/linux/rpm/package.spec" "SPECS/${APPNAME}" ; \
cd "BUILD"; \
echo " >> Extracting source binary package.." ; \
tar -xzf "$(PWD)/release/${VERSION}/$(APPANDVER)-linux-$$arch.tar.gz" . ; \
echo " >> Generating directory structure in temp dir.." ; \
mkdir --parents ./usr/bin/ ; \
mv ./bin/${APPNAME} ./usr/bin/ ; \
rm -rf ./bin ; \
mkdir --parents ./usr/share/licenses/${APPNAME}/ ; \
mv LICENSE ./usr/share/licenses/${APPNAME} ; \
mkdir --parents ./usr/share/doc/${APPNAME}/ ; \
mv README.md ./usr/share/doc/${APPNAME} ; \
cd .. ; \
echo " >> Building RPM package.." ; \
sudo rpmbuild -vv --nosignature --nodebuginfo --dbpath "$$tempdir" --root "$$tempdir" --buildroot "./BUILD" --target $$arch --define "_tmppath /tmp" --define "_topdir ." --define "_version ${VERSION}" --define "_buildhost localhost" --define "_rpmfilename $(APPANDVER)-$$arch.rpm" -bb "SPECS/${APPNAME}" && \
rpm -qlp --info "./RPMS/$(APPANDVER)-$$arch.rpm" && \
cp "./RPMS/$(APPANDVER)-$$arch.rpm" "$(PWD)/release/${VERSION}/" ; \
echo "------------------------------------------------------------"; \
done
Create bin/$os-$cpuarch/$appname binaries:
% make linux-build
Create the binary source tarballs to release/$version/$appname-$version-$os-$cpuarch.tar.gz:
% make compress-everything
Created file tree structure inside tarballs:
bin/$appname (different for each architecture)
LICENSE
README.md
This structure is locked in as there are also different OS tarballs too. Different OS build targets are removed in this minimized example for readability reasons.
Generate RPMs for each CPU architecture:
% make ldistro-rpm
The current problem is that during RPM build the actual executables are being installed to the running system. AFAIK this should not happen. What I might be missing from the spec file or ldistro-rpm target? Also some rpmbuild examples seemed to only use -bb parameter but I couldn't find examples or figure out how to modify the spec file so that could work. The ldistro-rpm target seems overly complicated. Should some commands be in the spec file's %install, %prep, etc? Can you somehow use the Source0 in the spec file and point it to the tarball instead of generating the directory structure in the ldistro-rpm target?

#echo 'install -Dm755 "usr/bin/%{NAME}" -t "/usr/bin"'
Is where you are installing to /usr/bin You should install to $RPM_BUILD_ROOT/usr/bin instead.

Related

makefile "C:\Program" not recognized as internal or external command

I am trying to run make after downloading source for lua, but I am getting an error that says
'C:/Program' is not recognized as an internal or external command,
operable program or batch file
make: *** [guess] Error 1
I understand that some people got this error due to not placing any quotation marks around the path, but right now I am just running make without specifying any path. How should I go around this?
---EDIT--
This is the makefile I tried to run
# Makefile for installing Lua
# See doc/readme.html for installation and customization instructions.
# == CHANGE THE SETTINGS BELOW TO SUIT YOUR ENVIRONMENT =======================
# Your platform. See PLATS for possible values.
PLAT= guess
# Where to install. The installation starts in the src and doc directories,
# so take care if INSTALL_TOP is not an absolute path. See the local target.
# You may want to make INSTALL_LMOD and INSTALL_CMOD consistent with
# LUA_ROOT, LUA_LDIR, and LUA_CDIR in luaconf.h.
INSTALL_TOP= /usr/local
INSTALL_BIN= '$(INSTALL_TOP)/bin'
INSTALL_INC= '$(INSTALL_TOP)/include'
INSTALL_LIB= '$(INSTALL_TOP)/lib'
INSTALL_MAN= '$(INSTALL_TOP)/man/man1'
INSTALL_LMOD= '$(INSTALL_TOP)/share/lua/$V'
INSTALL_CMOD= '$(INSTALL_TOP)/lib/lua/$V'
# How to install. If your install program does not support "-p", then
# you may have to run ranlib on the installed liblua.a.
INSTALL= install -p
INSTALL_EXEC= $(INSTALL) -m 0755
INSTALL_DATA= $(INSTALL) -m 0644
#
# If you don't have "install" you can use "cp" instead.
# INSTALL= cp -p
# INSTALL_EXEC= $(INSTALL)
# INSTALL_DATA= $(INSTALL)
# Other utilities.
MKDIR= mkdir -p
RM= rm -f
# == END OF USER SETTINGS -- NO NEED TO CHANGE ANYTHING BELOW THIS LINE =======
# Convenience platforms targets.
PLATS= guess aix bsd c89 freebsd generic linux linux-readline macosx mingw posix solaris
# What to install.
TO_BIN= lua luac
TO_INC= lua.h luaconf.h lualib.h lauxlib.h lua.hpp
TO_LIB= liblua.a
TO_MAN= lua.1 luac.1
# Lua version and release.
V= 5.4
R= $V.2
# Targets start here.
all: $(PLAT)
$(PLATS) help test clean:
#cd src && $(MAKE) $#
install: dummy
cd src && $(MKDIR) $(INSTALL_BIN) $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_MAN) $(INSTALL_LMOD) $(INSTALL_CMOD)
cd src && $(INSTALL_EXEC) $(TO_BIN) $(INSTALL_BIN)
cd src && $(INSTALL_DATA) $(TO_INC) $(INSTALL_INC)
cd src && $(INSTALL_DATA) $(TO_LIB) $(INSTALL_LIB)
cd doc && $(INSTALL_DATA) $(TO_MAN) $(INSTALL_MAN)
uninstall:
cd src && cd $(INSTALL_BIN) && $(RM) $(TO_BIN)
cd src && cd $(INSTALL_INC) && $(RM) $(TO_INC)
cd src && cd $(INSTALL_LIB) && $(RM) $(TO_LIB)
cd doc && cd $(INSTALL_MAN) && $(RM) $(TO_MAN)
local:
$(MAKE) install INSTALL_TOP=../install
# make may get confused with install/ if it does not support .PHONY.
dummy:
# Echo config parameters.
echo:
#cd src && $(MAKE) -s echo
#echo "PLAT= $(PLAT)"
#echo "V= $V"
#echo "R= $R"
#echo "TO_BIN= $(TO_BIN)"
#echo "TO_INC= $(TO_INC)"
#echo "TO_LIB= $(TO_LIB)"
#echo "TO_MAN= $(TO_MAN)"
#echo "INSTALL_TOP= $(INSTALL_TOP)"
#echo "INSTALL_BIN= $(INSTALL_BIN)"
#echo "INSTALL_INC= $(INSTALL_INC)"
#echo "INSTALL_LIB= $(INSTALL_LIB)"
#echo "INSTALL_MAN= $(INSTALL_MAN)"
#echo "INSTALL_LMOD= $(INSTALL_LMOD)"
#echo "INSTALL_CMOD= $(INSTALL_CMOD)"
#echo "INSTALL_EXEC= $(INSTALL_EXEC)"
#echo "INSTALL_DATA= $(INSTALL_DATA)"
# Echo pkg-config data.
pc:
#echo "version=$R"
#echo "prefix=$(INSTALL_TOP)"
#echo "libdir=$(INSTALL_LIB)"
#echo "includedir=$(INSTALL_INC)"
# Targets that do not create files (not all makes understand .PHONY).
.PHONY: all $(PLATS) help test clean install uninstall local dummy echo pc
# (end of Makefile)

Copy list of files to specific paths with Makefile

Scratching my head for a while now, but I would like to copy an arbitrary list of files with paths to under specified path in system.
File layout:
data/a/file1.ext1
data/b/randomfile.ext2
data/c/file3.ext3
data/c/subdir/randomfile.2
Running make -f Makefile deploy DESTDIR=/path/to/somewhere copies those files to:
$(DESTDIR)/a/file1.ext1
$(DESTDIR)/b/randomfile.ext2
$(DESTDIR)/c/file3.ext3
$(DESTDIR)/c/subdir/randomfile.2
Makefile:
$FILES = \
a/file1.ext1 \
b/randomfile.ext2 \
c/file3.ext3 \
c/subdir/randomfile.2
ifneq ($(filter env_check,$(MAKECMDGOALS)),$())
ifndef DESTDIR
$(error DESTDIR not defined)
endif
endif
# lots of currently broken rules :(
# check whether target directory has certain structure
# check whether all the files listed in $(FILES) are in repository
Are you looking for something like this?
FILES := ...
DST_FILES := $(addprefix $(DESTDIR)/,$(FILES))
ifneq ($(filter env_check,$(MAKECMDGOALS)),$())
ifndef DESTDIR
$(error DESTDIR not defined)
endif
endif
all: $(DST_FILES)
$(DST_FILES) : ${DESTDIR}/% : %
#echo "$< ==> $#"
#[[ -e $< ]] || (echo "some error for $<" && false)
#mkdir -p $(dir $#)
#cp $< $#
[Edit]:
Although the version somewhat worked, I still needed to do following adjustments:
Files in source repository are stored under data directory - fixed by using $addprefix call
When file in $(DESTDIR) already existed, it was never copied - used the .FORCE target. (Another option would be --always-make commandline option).
Eventually, the working Makefile looks like that:
# File are stored under data/
FILES= \
foo/file1.ext \
bar/file2.txe \
bar/dir/file3.txt
ifneq ($(filter env_check,$(MAKECMDGOALS)),$())
ifndef DESTDIR
$(error DESTDIR not defined)
endif
endif
.PHONY: deploy help
help:
#echo "Deploy stuff"
# Check whether certain directories in the output are present
env_check:
#test -d $(DESTDIR)/WEB-INF -a -d $(DESTDIR)/META-INF || \
( echo "DESTDIR: \"$(DESTDIR)\" is not proper deployment path" && exit 1 )
DST_FILES := $(addprefix $(DESTDIR)/, $(FILES))
# We need to add our path prefix to local files and FORCE to always do the copying
$(DST_FILES) : $(addprefix $(DESTDIR), %) : $(addprefix data,%) .FORCE
#cp -pv $< $#
.FORCE:
deploy: env_check $(DST_FILES)
#echo "Deployment done..."

Restart udev on Makefile

I've made a simple Makefile for an application and after install I need to restart udev rules.
INSTALLDIR=/pkt/bin
OS:=$(shell uname -v)
LBITS:=$(shell getconf LONG_BIT)
LIBDIR=/usr/lib
ifeq ($(LBITS),64)
LIBDIR64=/usr/lib64
else
LIBDIR64=/usr/lib
endif
all: usbupdater
configuracion.o: configuracion.cpp
g++ -c configuracion.cpp
main.o: main.cpp
g++ -c main.cpp
usbupdater: main.o configuracion.o
#echo "$(PATH)"
#echo "$(LIBDIR)"
g++ main.o configuracion.o $(LIBDIR)/libReadINI.a $(LIBDIR64)/chilkat/li
bchilkat-9.4.1.a -lpthread -lresolv -o usbupdater
clean:
rm -rf *.o *.cgh $(INSTALLDIR)/usbupdater
install:
mv usbupdater $(INSTALLDIR)/usbupdater
cp -rf 99-persistent-usb.rules /etc/udev/rules.d/99-persistent-usb.rules
postinstall:
#echo "$(OS)"
ifeq ($(findstring Debian,$(OS)),Debian) \
#echo "Estoy dentro del if"
$(shell '/etc/init.d/udev' restart) \
else \
#echo "Estoy dentro del else"
$(shell ls -l) \
endif
The problem is that when I type make postinstall is shows me this error:
#1 SMP Debian 3.2.46-1+deb7u1
ifeq (Debian,Debian) \
#echo "Estoy dentro del if"
/bin/sh: 1: Syntax error: word unexpected (expecting ")")
make: *** [postinstall] Error 2
I don't know where the problem is. I compare the result of uname -v with Debian to perform udev restart or udevcontrol reload_rules if it is an Opensuse OS.
Thanks in advance and sorry for my English.
ifeq is a make command. All lines in the makefile (in a recipe context) are passed to the shell. So make is passing ifeq to the shell and the shell is telling you that it has no idea what you're talking about.
You should write this using shell syntax, not make syntax.
Also it's rarely useful to use $(shell ...) functions inside a make recipe. The make recipe will be run by the shell, so when you use $(shell ...) you're just doubling the amount of shells that are running. Plus a command like $(shell ls -l) is not going to work, because $(shell ...) is like backtick and replaces the function with the stdout of the command. That'll be an error in this situation.
I would write it as:
postinstall:
#echo "$(OS)"
#case '$(OS)' in \
(*Debian*) \
echo "Estoy dentro del if"; \
/etc/init.d/udev restart ;; \
(*) \
echo "Estoy dentro del else"; \
ls -l ;; \
esac
You can't use make internal commands (like ifeq) within rule definition block. Use either shell's if or use ifeq outside of rule to generate some variables values, like
ifeq($(blah-blah), blah)
BUILD_CMD:=foo
endif
Also worth noting that else statement isn't exactly standard and may be missing in some versions of make.
Why do you want this, btw? I'd consider really bad practice if make install does something other then just installing (copying) files.

Mini Makefile always rebuild using compass

I have this small Makefile here
SHELL = /bin/sh
.PHONY: clean all
all: ../../htdocs/css
../../htdocs/css: ../sass
cd ../../ && compass compile -e `cat .env | cut -d " " -f 1`
clean:
rm -f ../../htdocs/css/*
It does always rebuild. The directory '../../htdocs/css' does exist. Any ideas?

error in makefile

I am using gnu Make 3.82 and have an annoying problem.
I have a rule setting dependencies between directories.
OBJDIR=../obj
$(objdir)/%.o: %.C
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
In order to do this, the obj directory must exist.
I want to mkdir the directory as a prerequisite
$(objdir)/%.o: %.C $(objdir)
$(COMPILE) -MM -MT$(objdir)/$(notdir $#) $< -o $(DEPDIR)/$(notdir $(basename $<).d )
$(COMPILE) -o $(objdir)/$(notdir $# ) -c $<
$(objdir):
mkdir $(objdir)
This doesn't work, because it fails when the directory is there and then the make stops
I tried shell
if [ ! -d $(objdir) ] ; then \
mkdir $(objdir) \
fi
but obviously I've got something wrong. What's the best way of doing this?
One simple way is to use:
mkdir -p ../obj
It doesn't fail when the directory exists.
I usually create a macro, MKPATH, for this:
MKPATH = mkdir -p
and then reference the macro in the rule:
$(objdir):
$(MKPATH) $(objdir)
That way, I can change the behaviour without changing the makefile if it becomes necessary.
Your shell fragment:
if [ ! -d $(objdir) ] ; then
mkdir $(objdir)
fi
does not work as written because make executes each line separately.
You could write (note the added semi-colon):
if [ ! -d $(objdir) ] ; then \
$(MKPATH) $(objdir) ; \
fi
Or:
if [ ! -d $(objdir) ] ; then $(MKPATH) $(objdir); fi
Or:
[ -d $(objdir) ] || $(MKPATH) $(objdir)
Note that the command line must be successful overall, so do not try:
[ ! -d $(objdir) ] && $(MKPATH) $(objdir)
If the directory exists, the first alternative fails, but the shell exits with a non-zero status, thus failing...and causing the build to fail.
mkdir
"mkdir -p"
Change:
$(objdir): mkdir $(objdir)
to =>
$(objdir):
mkdir -p $(objdir)
If that particular mkdir does not have -p then:
$(objdir):
test -d $(objdir) || mkdir $(objdir)
Makefiles
Keep the target: and the comands (mkdir, etc) on seperate lines.
Also, in make, to ignore failed commands, prefix command with minus:
$(objdir):
-mkdir $(objdir)
Commands (if-then-else; for loops, etc) with multiple lines require adding `\;' to represent newlines to the shell:
$(objdir):
if [ ! -d $(objdir) ] ; then \
mkdir $(objdir) ; \
fi
This particular usage of if-then-else can also written as:
$(objdir):
if [ ! -d $(objdir) ] ; then mkdir $(objdir) ; fi
The following Makefile that demonstrates each point above
all: setup dirs report
# Create an intefering dir1
# Remove dir2. It is work to be done later.
setup:
#mkdir -p dir1
#if test -d dir2 ; then rmdir dir2 ; fi
# Continue (with dir2), even though dir1 re-creation fails
dirs:
-mkdir dir1
mkdir -v dir2
# Show we're still running
report:
#echo DIRS:
#for d in dir?; do \
test -d $$d || break ; \
echo -n "$$d " ; \
done
#echo
Output from running running make:
mkdir dir1
mkdir: cannot create directory `dir1': File exists
make: [dirs] Error 1 (ignored)
mkdir -v dir2
mkdir: created directory `dir2'
DIRS:
dir1 dir2

Resources