4.2. Adding New Packages¶
PTXdist provides a huge amount of applications sufficient for the most embedded use cases. But there is still need for some fancy new packages. This section describes the steps and the background on how to integrate new packages into the project.
At first a summary about possible application types which PTXdist can handle:
- host type: This kind of package is built to run on the build host. Most of the time such a package is needed if another target-relevant package needs to generate some data. For example the glib package depends on its own to create some data. But if it is compiled for the target, it can’t do so. That’s why a host glib package is required to provide these utilities runnable on the build host. It sounds strange to build a host package, even if on the build host such utilities are already installed. But this way ensures that there are no dependencies regarding the build host system.
- target type: This kind of package is built for the target.
- cross type: This kind of package is built for the build host, but creates architecture specific data for the target.
- src-autoconf-prog: This kind of package is built for the target. It is intended for development, as it does not handle a released archive but a plain source project instead. Creating such a package will also create a small autotools based source template project on demand to give the developer an easy point to start. This template is prepared to build a single executable program. For further details refer section Creating an Executable Template.
- src-autoconf-lib: This kind of package is built for the target. It is intended for development, as it does not handle a released archive but a plain source project instead. Creating such a package will also create a small autotools/libtool based source template project on demand to give the developer an easy point to start. This template is prepared to build a single shared library. For further details refer section Creating a Library Template.
- src-autoconf-proglib: This kind of package is built for the target. It is intended for development, as it does not handle a released archive but a plain source project instead. Creating such a package will also create a small autotools/libtool based template project on demand to give the developer an easy point to start. This template is prepared to build a single shared library and a single executable program. The program will be linked against the shared library. For further details refer section Creating an Executable with a Library Template.
- file: This kind of package is intended to add a few simple files into the build process. We assume these files do not need any processing, they are ready to use and must only be present in the build process or at run-time (HTML files for example). Refer to the section Adding Binary Only Files for further details on how to use it.
- src-make-prog: This kind of package is built for the target. It’s intended for development, as it does not handle a released archive but a plain source project instead. Creating such a package will also create a simple makefile-based template project the developer can use as a starting point for development.
- src-cmake-prog: This kind of package is built for the target. It’s intended for developments based on the cmake buildsystem. Various projects are using cmake instead of make and can be built with this package type. PTXdist will prepare it to compile sources in accordance to the target libraries and their settings. Creating such a package will also create a simple template project to be used as a starting point for development.
- src-qmake-prog: This kind of package is built for the target. It’s intended for developments based on the qmake buildsystem. If the developer is going to develop a QT based application, this rule is prepared to compile sources in accordance to the target libraries and their settings. Creating such a package will also create a simple template project to be used as a starting point for development.
- src-meson-prog: This kind of package is built for the target. It’s intended for developments based on the meson buildsystem. Various projects are using meson today and can be built with this package type. PTXdist will prepare it to compile sources in accordance to the target libraries and their settings. Creating such a package will also create a simple template project to be used as a starting point for development.
- font: This package is a helper to add X font files to the root filesystem. This package does not create an additional IPKG, instead it adds the font to the existing font IPKG. This includes the generation of the directory index files, required by the Xorg framework to recognize the font file.
- src-linux-driver: This kind of package builds an out of tree kernel driver. It also creates a driver template to give the developer an easy point to start.
- kernel: PTXdist comes with the ability to handle one kernel in its platform. This type of package enables us to handle more than one kernel in the project.
- barebox: PTXdist comes with the ability to handle one bootloader in its platform. This type of package enables us to handle more than one bootloader in the project.
- image-tgz: This kind of package creates a tar ball from a list of packages. It is often uses as an input for other image packages.
- image-genimage: This kind of package can handle all kind of image generation for almost every target independent of its complexity.
- blspec-entry: PTXdist comes with the ability to handle one bootspec in its platform. This type of package enables us to handle more than one bootspec in the project.
Rule File Creation¶
To create such a new package, we create a project local rules/
directory first. Then we run
$ ptxdist newpackage <package type>
If we omit the <package type
>, PTXdist will list all available
package types.
In our first example, we want to add a new target type archive package. When running the
$ ptxdist newpackage target
command, PTXdist asks a few questions about this package. This information is the basic data PTXdist must know about the package.
ptxdist: creating a new 'target' package:
ptxdist: enter package name.......: foo
ptxdist: enter version number.....: 1.1.0
ptxdist: enter URL of basedir.....: http://www.foo.com/download/src
ptxdist: enter suffix.............: tar.gz
ptxdist: enter package author.....: My Name <me@my-org.com>
ptxdist: enter package section....: project_specific
What we have to answer:
- package name: As this kind of package handles a source archive,
the correct answer here is the basename of the archive’s file name.
If its full name is
foo-1.1.0.tar.gz
, thenfoo
is the basename to enter here. - version number: Most source archives are using a release or
version number in their file name. If its full name is
foo-1.1.0.tar.gz
, then1.1.0
is the version number to enter here. - URL of basedir: This URL tells PTXdist where to download the
source archive from the web (if not already done). If the full URL to
download the archive is
http://www.foo.com/download/src/foo-1.1.0.tar.gz
, the basedir parthttp://www.foo.com/download/src
is to be entered here. - suffix: Archives are using various formats for distribution.
PTXdist uses the suffix entry to select the matching extraction
tool. If the archive’s full name is
foo-1.1.0.tar.gz
, thentar.gz
is the suffix to enter here. - package author: If we intend to contribute this new package to
PTXdist mainline, we should add our name here. This name will be used
in the copyright note of the rule file and will also be added to the
generated ipkg. When you run
ptxdist setup
prior to this call, you can enter your name and your email address, so PTXdist will use it as the default (very handy if you intend to add many new packages). - package section: We can enter here the menu section name where our new package menu entry should be listed. In the first step we can leave the default name unchanged. It’s a string in the menu file only, so changing it later on is still possible.
Make it Work¶
Generating the rule file is only one of the required steps to get a new package. The next steps to make it work are to check if all stages are working as expected and to select the required parts to get them installed in the target root filesystem. Also we must find a reasonable location where to add our new menu entry to configure the package.
The generated skeleton starts to add the new menu entry in the main
configure menu (if we left the section name unchanged). Running
ptxdist menuconfig
will show it on top of all other menus entries.
Important
To be able to implement and test all the other required steps for adding a new package, we first must enable the package for building. (Fine tuning the menu can happen later on.)
The rule file skeleton still lacks some important information. Let’s
take a look into some of the top lines of the generated rule file
./rules/foo.make
:
FOO_VERSION := 1.1.0
FOO_MD5 :=
FOO := foo-$(FOO_VERSION)
FOO_SUFFIX := tar.gz
FOO_URL := http://www.foo.com/download/src/$(FOO).$(FOO_SUFFIX)
FOO_SOURCE := $(SRCDIR)/$(FOO).$(FOO_SUFFIX)
FOO_DIR := $(BUILDDIR)/$(FOO)
FOO_LICENSE := unknown
We can find these lines with different content in most or all of the other rule files PTXdist comes with. Up to the underline character is always the package name and after the underline character is always PTXdist specific. What does it mean:
*_VERSION
brings in the version number of the release and is used for the download and IPKG/OPKG package generation.*_MD5
to be sure the correct package has been downloaded, PTXdist checks the given MD5 sum against the archive content. If both sums do not match, PTXdist rejects the archive and fails the currently running build.*_SUFFIX
defines the archive type, to make PTXdist choosing the correct extracting tool.*_URL
defines the full qualified URL into the web for download. If alternative download locations are known, they can be listed in this variable, delimiter character is the space.*_SOURCE
tells PTXdist where to store the downloaded package.*_DIR
points to the directory this package will be built later on by PTXdist.*_LICENSE
enables the user to get a list of licenses she/he is using in her/his project (licenses of the enabled packages). See Tracking licensing information in packages below for detailed information.
After enabling the menu entry, we can start to check the get and extract stages, calling them manually one after another.
Note
The shown commands below expect that PTXdist downloads the
archives to a global directory named global_src
. This is not the
default setting, but we recommend to use a global directory to share all
archives between PTXdist based projects. Advantage is every download
happens only once. Refer to the setup
command PTXdist provides.
$ ptxdist get foo
---------------------------
target: foo-1.1.0.tar.gz
---------------------------
--2009-12-21 10:54:45-- http://www.foo.com/download/src/foo-1.1.0.tar.gz
Length: 291190 (284K) [application/x-gzip]
Saving to: `/global_src/foo-1.1.0.tar.gz.XXXXOGncZA'
100%[======================================>] 291,190 170K/s in 1.7s
2009-12-21 10:54:48 (170 KB/s) - `/global_src/foo-1.1.0.tar.gz' saved [291190/291190]
This command should start to download the source archive. If it fails, we should check our network connection, proxy setup or if the given URL in use is correct.
Note
Sometimes we do not know the content of all the other variables in the rule file. To get an idea what content a variable has, we can ask PTXdist about it:
$ ptxdist print FOO_URL
http://www.foo.com/download/src/foo-1.1.0.tar.gz
The next step would be to extract the archive. But as PTXdist checks the
MD5 sum in this case, this step will fail, because the FOO_MD5
variable is still empty. Let’s fill it:
$ md5sum /global_src/foo-1.1.0.tar.gz
9a09840ab775a139ebb00f57a587b447
This string must be assigned to the FOO_MD5 in our new foo.make
rule file:
FOO_MD5 := 9a09840ab775a139ebb00f57a587b447
We are now prepared for the next step:
$ ptxdist extract foo
-----------------------
target: foo.extract
-----------------------
extract: archive=/global_src/foo-1.1.0.tar.gz
extract: dest=/home/jbe/my_new_prj/build-target
PATCHIN: packet=foo-1.1.0
PATCHIN: dir=/home/jbe/my_new_prj/build-target/foo-1.1.0
PATCHIN: no patches for foo-1.1.0 available
Fixing up /home/jbe/my_new_prj/build-target/foo-1.1.0/configure
finished target foo.extract
In this example we expect an autotoolized source package. E.g. to
prepare the build, the archive comes with a configure
script. This
is the default case for PTXdist. So, there is no need to modify the rule
file and we can simply run:
$ ptxdist prepare foo
-----------------------
target: foo.prepare
-----------------------
[...]
checking build system type... i686-host-linux-gnu
checking host system type... arm-v7a-linux-gnueabihf
checking whether to enable maintainer-specific portions of Makefiles... no
checking for a BSD-compatible install... /usr/bin/install -c
checking whether build environment is sane... yes
checking for a thread-safe mkdir -p... /bin/mkdir -p
checking for gawk... gawk
checking whether make sets $(MAKE)... yes
checking for arm-v7a-linux-gnueabihf-strip... arm-v7a-linux-gnueabihf-strip
checking for arm-v7a-linux-gnueabihf-gcc... arm-v7a-linux-gnueabihf-gcc
checking for C compiler default output file name... a.out
[...]
configure: creating ./config.status
config.status: creating Makefile
config.status: creating ppa_protocol/Makefile
config.status: creating config.h
config.status: executing depfiles commands
finished target foo.prepare
At this stage things can fail:
- A wrong or no MD5 sum was given
- The
configure
script is not cross compile aware - The package depends on external components (libraries for example)
If the configure
script is not cross compile aware, we are out of
luck. We must patch the source archive in this case to make it work.
Refer to the section Modifying Autotoolized Packages on how to use
PTXdist’s features to simplify this task.
If the package depends on external components, these components might
be already part of PTXdist. In this case we just have to add this
dependency into the menu file and we are done. But if PTXdist cannot
fulfill this dependency, we also must add it as a separate package
first.
If the prepare stage has finished successfully, the next step is to compile the package.
$ ptxdist compile foo
-----------------------
target: foo.compile
-----------------------
make[1]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make all-recursive
make[2]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[3]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
[...]
make[3]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[2]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[1]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
finished target foo.compile
At this stage things can fail:
- The build system is not cross compile aware (it tries to execute just created target binaries for example)
- The package depends on external components (libraries for example)
not detected by
configure
- Sources are ignoring the endianness of some architectures or using
header files from the build host system (from
/usr/include
for example) - The linker uses libraries from the build host system (from
/usr/lib
for example) by accident
In all of these cases we must patch the sources to make them work. Refer to section Patching Packages on how to use PTXdist’s features to simplify this task.
In this example we expect the best case: everything went fine, even for cross compiling. So, we can continue with the next stage: install
$ ptxdist install foo
-----------------------
target: foo.install
-----------------------
make[1]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[2]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[3]: Entering directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
test -z "/usr/bin" || /bin/mkdir -p "/home/jbe/my_new_prj/build-target/foo-1.1.0/usr/bin"
/usr/bin/install -c 'foo' '/home/jbe/my_new_prj/build-target/foo-1.1.0/usr/bin/foo'
make[3]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[2]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
make[1]: Leaving directory `/home/jbe/my_new_prj/build-target/foo-1.1.0'
finished target foo.install
----------------------------
target: foo.install.post
----------------------------
finished target foo.install.post
This install stage does not install anything to the target root filesystem. It is mostly intended to install libraries and header files other programs should link against later on.
The last stage – targetinstall – is the one that defines the package’s
components to be forwarded to the target’s root filesystem. Due to the
absence of a generic way, this is the task of the developer. So, at this
point of time we must run our favourite editor again and modify our new
rule file ./rules/foo.make
.
The skeleton for the targetinstall stage looks like this:
# ----------------------------------------------------------------------------
# Target-Install
# ----------------------------------------------------------------------------
$(STATEDIR)/foo.targetinstall:
@$(call targetinfo)
@$(call install_init, foo)
@$(call install_fixup, foo,PACKAGE,foo)
@$(call install_fixup, foo,PRIORITY,optional)
@$(call install_fixup, foo,VERSION,$(FOO_VERSION))
@$(call install_fixup, foo,SECTION,base)
@$(call install_fixup, foo,AUTHOR,"My Name <me@my-org.com>")
@$(call install_fixup, foo,DEPENDS,)
@$(call install_fixup, foo,DESCRIPTION,missing)
@$(call install_copy, foo, 0, 0, 0755, $(FOO_DIR)/foobar, /dev/null)
@$(call install_finish, foo)
@$(call touch)
The “header” of this stage defines some information IPKG needs. The
important part that we must modify is the call to the install_copy
macro (refer to section Rule File Macro Reference for more details
about this kind of macros). This call instructs PTXdist to include the
given file (with UID, GID and permissions) into the IPKG, which means to
install this file to the target’s root filesystem.
From the previous install stage we know this package installs an
executable called foo
to location /usr/bin
. We can do the same
for our target by changing the install_copy line to:
@$(call install_copy, foo, 0, 0, 0755, $(FOO_DIR)/foo, /usr/bin/foo)
To check it, we just run:
$ ptxdist targetinstall foo
-----------------------------
target: foo.targetinstall
-----------------------------
install_init: preparing for image creation...
install_init: @ARCH@ -> i386 ... done
install_init: preinst not available
install_init: postinst not available
install_init: prerm not available
install_init: postrm not available
install_fixup: @PACKAGE@ -> foo ... done.
install_fixup: @PRIORITY@ -> optional ... done.
install_fixup: @VERSION@ -> 1.1.0 ... done.
install_fixup: @SECTION@ -> base ... done.
install_fixup: @AUTHOR@ -> "My Name <me\@my-org.com>" ... done.
install_fixup: @DESCRIPTION@ -> missing ... done.
install_copy:
src=/home/jbe/my_new_prj/build-target/foo-1.1.0/foo
dst=/usr/bin/foo
owner=0
group=0
permissions=0755
xpkg_finish: collecting license (unknown) ... done.
xpkg_finish: creating ipkg package ... done.
finished target foo.targetinstall
----------------------------------
target: foo.targetinstall.post
----------------------------------
finished target foo.targetinstall.post
After this command, the target’s root filesystem contains a file called
/usr/bin/foo
owned by root, its group is also root and everyone has
execution permissions, but only the user root has write permissions.
One last task of this port is still open: A reasonable location for
the new menu entry in PTXdist’s menu hierarchy. PTXdist arranges its
menus on the meaning of each package. Is it a network related tool? Or
a scripting language? Or a graphical application?
Each of these global meanings has its own submenu, where we can add
our new entry to. We just have to edit the head of our new menu file
./rules/foo.in
to add it to a specific global menu. If our new
package is a network related tool, the head of the menu file should
look like:
## SECTION=networking
We can grep through the other menu files from the PTXdist main
installation rules/
directory to get an idea what section names are
available:
rules/ $ find . -name \*.in | xargs grep "## SECTION"
./acpid.in:## SECTION=shell_and_console
./alsa-lib.in:## SECTION=system_libraries
./alsa-utils.in:## SECTION=multimedia_sound
./apache2.in:## SECTION=networking
./apache2_mod_python.in:## SECTION=networking
[...]
./xkeyboard-config.in:## SECTION=multimedia_xorg_data
./xorg-app-xev.in:## SECTION=multimedia_xorg_app
./xorg-app-xrandr.in:## SECTION=multimedia_xorg_app
./host-eggdbus.in:## SECTION=hosttools_noprompt
./libssh2.in:## SECTION=networking
Porting a new package to PTXdist is (almost) finished now.
To check it right away, we simply run these two commands:
$ ptxdist clean foo
rm -rf /home/jbe/my_new_prj/state/foo.*
rm -rf /home/jbe/my_new_prj/packages/foo_*
rm -rf /home/jbe/my_new_prj/build-target/foo-1.1.0
$ ptxdist targetinstall foo
[...]
Important
Discover somehow hidden dependencies with one more last check!
Up to this point all the development of the new package was done in an already built BSP. Doing so sometimes somehow hidden dependencies cannot be seen: everything seems fine, the new package builds always successfully and the results are working on the target.
So to check for this kind of dependencies there is still one more final check to do (even if its boring and takes time):
$ ptxdist clean
[...]
$ ptxdist targetinstall foo
[...]
This will re-start with a clean BSP and builds exactly the new package and its (known) dependencies. If this builds successfully as well we are really done with the new package.