Build

Warning!!

ALL THE FOLLOWING INSTRUCTIONS ASSUME THAT YOU ARE IN YOUR CONTAINER UNDER THE DEVEL USER !!! refer to this section to enter your container.

Build environment

Your home directory comes with some precreated directories:

  • gitsources: where your project/application sources git clone resides.
  • gitpkgs: where is the repository holding your packaged project is. This holds a tarball of your project source as well as its associated spec files and patches.
  • rpmbuild: this directory will hold all your RPM package build results, after the rpmbuild command has run

The container comes with a generic aarch64 ready build environment. To be in a cross-compiling environment you have to source a script to setup your environment for cross-compilation (cross-compiler and libraries paths). Execute the following:

[devel@redpesk-builder rpmbuild]$ . /usr/aarch64-linux-gnu/bin/cross-profile-setup-sdk-aarch64.sh

After sourcing the generic cross environment, you can export or source your project specific environment. Example :

[devel@redpesk-builder rpmbuild]$ export CROSS_COMPILE="aarch64-linux-gnu-"
[devel@redpesk-builder rpmbuild]$ export ARCH="arm64"

Crossbuild your project

Here is an example of how to crossbuild an AGL binding:

cd gitsources
git clone https://github.com/redpesk-samples/helloworld-binding.git
cd helloworld-binding
dnf-aarch64 -y builddep conf.d/packaging/helloworld-binding.spec
mkdir rpmbuild
cd rpmbuild
. /usr/aarch64-linux-gnu/bin/cross-profile-setup-sdk-aarch64.sh
# Project specific environment can be sourced/exported here if needed
cmake ..
# if there a "no version found" error, specify the version, for example:
cmake .. -DVERSION=8.99.6

If everything goes as planned, you will have an output like that:

Distribution detected (separated by ';' choose one of them) redpesk
Include: /usr/share/cmake/Modules/CMakeAfbTemplates/cmake/cmake.d/01-build_options.cmake
Include: /usr/share/cmake/Modules/CMakeAfbTemplates/cmake/cmake.d/02-variables.cmake
-- Check gcc_minimal_version (found gcc version 8.1.1) 	(found g++ version 8.1.1)
Include: /usr/share/cmake/Modules/CMakeAfbTemplates/cmake/cmake.d/03-macros.cmake
Include: /usr/share/cmake/Modules/CMakeAfbTemplates/cmake/cmake.d/04-extra_targets.cmake
.. Warning: RSYNC_TARGET RSYNC_PREFIX not defined 'make remote-target-populate' not instanciated
.. Warning: RSYNC_TARGET not defined 'make widget-target-install' not instanciated
-- Configuring done
-- Generating done
-- Build files have been written to: /home/devel/gitsources/helloworld-binding/build

Then you can continue with a make:

make -j
Scanning dependencies of target test-files
Scanning dependencies of target prepare_package
Scanning dependencies of target helloworld-skeleton
Scanning dependencies of target htdocs
Scanning dependencies of target prepare_package_test
Scanning dependencies of target helloworld-subscribe-event
Scanning dependencies of target fixture-files
Scanning dependencies of target helloworld-config
[  7%] Generating package
[  7%] Building C object helloworld-skeleton/CMakeFiles/helloworld-skeleton.dir/helloworld-service-binding.c.o
[ 11%] Generating htdocs
[ 14%] Generating package-test
Scanning dependencies of target autobuild
[ 18%] Generating test-files
[ 22%] Generating fixture-files
[ 25%] Generating package-test/htdocs
[ 29%] Generating helloworld-config
[ 33%] Building C object helloworld-subscribe-event/CMakeFiles/helloworld-subscribe-event.dir/helloworld-event-service-binding.c.o
[...]
[ 96%] Generating package/lib/afb-helloworld-skeleton.so
[ 96%] Built target project_populate_helloworld-skeleton
[ 96%] Built target helloworld-subscribe-event
Scanning dependencies of target project_populate_helloworld-subscribe-event
[100%] Generating package/lib/afb-helloworld-subscribe-event.so
[100%] Built target project_populate_helloworld-subscribe-event
Scanning dependencies of target populate
[100%] Built target populate
Scanning dependencies of target helloworld-binding_build_done
++ Debug from afb-binder --port=1234  --ldpaths=package --workdir=. --roothttp=../htdocs --token= --verbose
[100%] Built target helloworld-binding_build_done

(Cross)Build the RPM packages

Warning!!

ALL THE FOLLOWING INSTRUCTIONS ASSUME THAT YOU ARE IN YOUR CONTAINER UNDER THE DEVEL USER !!! refer to this section to enter your container.

# prerequisite: install needed libraries
sudo dnf install redpesk-utils

In this section, you can see how to crossbuild RPM packages. It is possible to use the previous example agl-service-helloworld but we choose another exemple: Mustache We are going to use an intermediate git repository meant for packaging, we will name it gitpkg.

Inside the gitpkg, there are 3 types of files: the spec file, one or several patches (if needed) and a source archive tarball.

First step: populate package sources repository (gitpkg)

# create your project gitpkg and go inside
mkdir ~/gitpkgs/mustach && cd ~/gitpkgs/mustach
# add the specfile in the mustach gitpkg
cat << EOF > mustach.spec
%global _privatelibs libmustach[.]so\(\).*
%global __requires_exclude ^(%{_privatelibs})$

Name:           mustach
Version:        0.0.1
Release:        0%{?dist}
Summary:        mustach is a C implementation of the mustache template specification

License:        APL2.0
URL:            https://gitlab.com/jobol/mustach.git
Source0:        %{name}-%{version}.tar.gz

BuildRequires:  valgrind

%global debug_package %{nil}

%description
C implementation of mustache templating

%prep
%autosetup -p1

%build
make PREFIX=%{_prefix} LIBDIR=%{_libdir}

%install
%make_install PREFIX=%{_prefix} LIBDIR=%{_libdir}

%check
%if "x%{?_crossroot}" == "x"
make test
%endif

%files
%doc
%{_bindir}/%{name}
%{_includedir}/%{name}/mustach-json-c.h
%{_includedir}/%{name}/mustach.h
%{_libdir}/libmustach.so
%{_libdir}/libmustach.so.0
%{_libdir}/libmustach.so.0.99

%license

%changelog
EOF
# init the git repository
git init
# stage spec file changes
git add *.spec

NB: You can refer to the RPM packaging guide to know more about creating a spec file.

Second step: apply your modifications

In general, you have typically 2 usecases you want to support: an internal project OR an existing upstream project.

This second step differs depending on the usecase. We are gonna see how, with our Mustache example.

1st case : Internal project

In this case, you have access to directly modify the project source code by cloning it, and creating the archive from the path where you cloned the sources.

cd ~/gitsources/
# clone sources
git clone https://gitlab.com/jobol/mustach.git
cd mustach
# modify the project sources (in this example, we add a library)
sed -i 's/LDLIBS += -ljson-c/LDLIBS += -ljson-c -lm/' Makefile
# this line lets us modify the Makefile automatically in this example
# but files can be modified the usual way, for instance with a text editor.

git commit Makefile -sm "Fix add missing lib at link"

cd ~/gitpkgs/mustach
# create the archive from the project sources
iotpkg archive --path-source ~/gitsources/mustach/ --commit master

# move project sources to the correct directory
cp *.tar.gz ~/rpmbuild/SOURCES/
2nd case : Existing upstream project

In this case, you can’t modify the project sources directly. You thus have to create the archive from a URL, and create a patch to apply your modifications, instead of directly modifying the application/project source code.

cd ~/gitpkgs/mustach

# retrieve the archive from a URL
iotpkg archive --path-source https://gitlab.com/jobol/mustach.git --commit master

# create the patch
cat << EOF > 0001-Fix-add-missing-lib-at-link.patch
diff --git a/Makefile b/Makefile
index 3e0fd17..e58d589 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ SOVER = .0
 SOVEREV = .0.99

 CFLAGS += -fPIC -Wall -Wextra
-LDLIBS += -ljson-c
+LDLIBS += -ljson-c -lm

 lib_OBJ  = mustach.o mustach-json-c.o
 tool_OBJ = mustach.o mustach-json-c.o mustach-tool.o
EOF

# modify the spec file to take into account the patch
sed -i '/Source0/a Patch0:         0001-Fix-add-missing-lib-at-link.patch' mustach.spec
# this line lets us add the `Patch` line to the spec file automatically in this example
# but a normal text editor can be used as well

# copy sources and patches to the correct directory
cp *.tar.gz *patch ~/rpmbuild/SOURCES/

Third step: build the RPM

cd ~/gitpkgs/mustach
# install required packages before building (valgrind in this example)
dnf-aarch64 -y builddep mustach.spec
# Source the environment to crossbuild
. /usr/aarch64-linux-gnu/bin/cross-profile-setup-sdk-aarch64.sh
# build the RPM with the following command
rpmbuild -bb --nodeps --target aarch64 *.spec
# output of rpmbuild command (Second case here)
Building target platforms: aarch64
Building for target aarch64
Executing(%prep): /bin/sh -e /var/tmp/rpm-tmp.JGBdm5
+ umask 022
+ cd /home/devel/rpmbuild/BUILD
+ cd /home/devel/rpmbuild/BUILD
+ rm -rf mustach-0.0.0+20200406+0+gdc2a8a4f
+ /usr/bin/gzip -dc /home/devel/rpmbuild/SOURCES/mustach-0.0.0+20200406+0+gdc2a8a4f.tar.gz
+ /usr/bin/tar -xof -
+ STATUS=0
+ '[' 0 -ne 0 ']'
+ cd mustach-0.0.0+20200406+0+gdc2a8a4f
+ /usr/bin/chmod -Rf a+rX,u+w,g-w,o-w .
+ /usr/bin/cat /home/devel/rpmbuild/SOURCES/0001-Fix-add-missing-lib-at-link.patch
+ /usr/bin/patch -p1 -s --fuzz=0 --no-backup-if-mismatch
+ exit 0
Executing(%build): /bin/sh -e /var/tmp/rpm-tmp.O0PGnQ
+ umask 022
+ cd /home/devel/rpmbuild/BUILD
+ cd mustach-0.0.0+20200406+0+gdc2a8a4f
+ make
[...]
Processing files: mustach-0.0.0+20200406+0+gdc2a8a4f-0.rpd28.aarch64
Provides: libmustach.so.0.99()(64bit) mustach = 0.0.0+20200406+0+gdc2a8a4f-0.rpd28 mustach(aarch-64) = 0.0.0+20200406+0+gdc2a8a4f-0.rpd28
Requires(rpmlib): rpmlib(CompressedFileNames) <= 3.0.4-1 rpmlib(FileDigests) <= 4.6.0-1 rpmlib(PayloadFilesHavePrefix) <= 4.0-1
Requires: libc.so.6()(64bit) libc.so.6(GLIBC_2.17)(64bit) libjson-c.so.4()(64bit) libmustach.so()(64bit) rtld(GNU_HASH)
Checking for unpackaged file(s): /usr/lib/rpm/check-files /home/devel/rpmbuild/BUILDROOT/mustach-0.0.0+20200406+0+gdc2a8a4f-0.rpd28.aarch64
Wrote: /home/devel/rpmbuild/RPMS/mustach-0.0.0+20200406+0+gdc2a8a4f-0.rpd28.aarch64.rpm
Executing(%clean): /bin/sh -e /var/tmp/rpm-tmp.YwggY9
+ umask 022
+ cd /home/devel/rpmbuild/BUILD
+ cd mustach-0.0.0+20200406+0+gdc2a8a4f
+ /usr/bin/rm -rf /home/devel/rpmbuild/BUILDROOT/mustach-0.0.0+20200406+0+gdc2a8a4f-0.rpd28.aarch64
+ exit 0

You can see the RPM has been created in the corresponding directory

ls ~/rpmbuild/RPMS/
# list of rpm files for this example (Second case here)
mustach-0.0.0+20200406+0+gdc2a8a4f-0.rpd28.aarch64.rpm

Fourth step: commit your modifications

The source archive (file xxx-version.tar.gz) must be part of gitpkg. It’s a bad idea to directly add this archive gitpkg git repo. This is why we will use a git extension, named Git LFS (for Large File Storage) to manage this binary. For more information on git LFS, please refer to https://git-lfs.github.com

Here are the commands to add your source archive into the gitpkg :

# Setup Git LFS (only once)
git lfs install

# Select the file types you'd like Git LFS to manage (only once)
git lfs track *.tar.gz

# Now make sure .gitattributes is tracked (only once)
git add .gitattributes

# Now, just commit and push to gitpkg as you normally would with git, the LFS
extension will automatically work behind the scenes

# Add the specfile
git add *spec
# Add patch file(s)
git add *patch
# Add the archive
git add *tar.gz

# Commit
git commit -sam "Initial commit"

# If you have a running operational redpesk stack
git remote add origin http://<your_gitlab_url>
# Push changes into the gitpkg repository
git push