IPFire is expandable by using Pakfire, its built-in package management system. There are some useful add-ons that can be installed this way, but in some cases, you will need to create your own. The following instructions shows an example of how to build a custom add-on called newItem.

Requirements

To build an add-on for IPFire, you will need to build a "build system" and include the source code of the add-on you want to build.

See Requirements for Building Add-ons

Basic principles

The basic build process for Linux software is usually the same for each program:

But to compile a package for IPFire (it actually is a LFS requirement) you have to insert the build sequence in the general compilation framework. To do this:

  • Write a compilation script for the package and put it in lfs/
  • Link the script adding a line to make.sh
  • Define which, produced by the build, will be in your package.

Each of these steps will be detailed below.

1) Download the source

Become familiar with building and installing the new package in a standard Linux environment. Experiments in the IPFire build environment can be time-consuming and error-prone.

It is strongly advised to create a separate standard Linux based system. A virtual machine is fine. Download the source code and install the package on that Linux distribution first. Keep track of what was done including:

  • the URL of the downloaded package
  • all package dependencies
  • the command entered to unpack the package
  • the minimum set of commands needed to configure, compile and install the package
  • any changes to patch the code or configuration files
  • other downloads to complete the installation

If there are package dependencies, stop now and start building those first.

If there is a prerequisite depending on a standard IPFire package, start from existing package and build on the results.

2) Copy source code to cache

Start by placing a copy of the new add-on source code into the ~/myProject/ipfire-2.x/cache directory. The /cache includes the existing sources for all of the various IPFire packages. This file might be compressed as .xz, .tar.gz or a .zip file. The file name used in examples below is newItem.tar.gz.

Note - This process assumes a "normal" unprivileged user. Make sure to prepend sudo to build commands.

sudo cp -v /path/newItem.tar.gz ~/myProject/ipfire-2.x/cache

3) Create the LFS build fragment file

The next step is to write a build fragment for LFS. This file requires a well defined structure that we need to customize.

A generic template is available on the IPFire 2.x - LFS Template Wiki page or copy one of the existing files from the ~/myProject/ipfire-2.x/lfs directory. Create a name for the LFS template, e.g, newItem. And changes will be needed for a few lines in the LFS template. See the LFS Definitions here.

After making the needed changes copy (or save) the LFS file in the ~/myProject/ipfire-2.x/lfs directory.

sudo cp -v /path/newItem ~/myProject/ipfire-2.x/lfs

4) Linking in the build script

When creating a new add-on, a new line must be added in the make.sh script. Edit the ~/myProject/ipfire-2.x/make.sh file and then add the new line near the end of the buildipfire() function.

nano ~/myProject/ipfire-2.x/make.sh

And then search for buildipfire() or search for buildinstaller().

. . .
buildipfire() {
  LOGFILE="$BASEDIR/log/_build.ipfire.log"
  export LOGFILE
  lfsmake2 configroot
  lfsmake2 initscripts
  lfsmake2 backup
. . .
  lfsmake2 pmacct
  lfsmake2 squid-asnbl
  lfsmake2 qemu-ga
  lfsmake2 gptfdisk
  lfsmake2 <newItem>      # <-- insert this line.  It matches the filename in lfs
}

buildinstaller() {
. . .

5) New add-on compilation

The Add-on preparation is now complete and we can try to compile our package. Enter these commands to build:

cd ~/myProject/ipfire-2.x
sudo ./make.sh build

At the end of the Building IPFire section see something like:

If/when something goes wrong:

  • Look for errors and important messages near the end of console messages
  • No errors on the very first build?
    • Forgot to add lfsmake2 <newItem> to make.sh file
  • Did the drive fill up?
   error: [Errno 28] No space left on device
   make: *** [oci-python-sdk:82: /usr/src/log/oci-python-sdk-2.54.0] Error 1
  • Does the rootfiles file need to be updated?
  • Is something missing (like the lfs file)?

TBD

6) Package definition

At this point we are almost there. You still need to define which files need to be in the packages.

The IPFire build system is very kind and will prepare a file containing all files added or removed by the make build script. At the very end of the compilation you will see something like:

This file have the same name as your filename (e.g., newItem) and is located in the log directory. Copy it into config/rootfiles/packages but also rename it to the lfs filename you used before:

cp -v ~/myProject/ipfire-2.x/log/newItem-1.0.0 ~/myProject/ipfire-2.x/config/rootfiles/packages/newItem

Now open the file in a text editor. It contains a list of all files added, removed or changed by your make install (a changed file will appear as added and deleted).

You will need to remove the prepended plus (+) or minus (-) sign and, possibly, to comment out some files.

Rule-of-thumb

  • remove entire line that begins with a minus (-) sign
  • remove just the plus (+) sign at the beginning of the line. Do not remove the entire line!
  • comment out, by prepending with a hash (#) sign, all lines pointing to directories.
  • comment out, by prepending with a hash (#) sign, all lines pointing to "useless" files.

Useless and un-needed files

  • manpages are usually located in /usr/share/man
  • pkg-config files are usually located in /usr/lib/pkgconfig
  • *.so files are usually located in /usr/lib
  • *.a files are usually located in /usr/lib
  • *.la files are usually located in /usr/lib
  • *.h files or header files are usually located in /usr/include
  • *.m4 files are usually located in /usr/share/aclocal
Note!
If your new rootfile contains files which are located in /usr/local this is really bad. Nothing should go there. If files are located there for example library files this cause a lot of trouble because in the most cases they are not found by the program. To avoid this you should always use --prefix=/usr.

Pakfire install, uninstall, update routines

Last bit of customization is about the installation/removal routines. Pakfire provides a set of standard scripts for install, uninstall and upgrade; they can be found in ~/myProject/ipfire-2.x/src/paks/default.
If these are not enough, for any reason, you can customize them.

Required steps are:

  • copy src/paks/default to src/paks/< newItem >
  • edit:
    ~/myProject/ipfire-2.x/src/paks/< newItem >/install.sh,
    ~/myProject/ipfire-2.x/src/paks/< newItem >/uninstall.sh,
    ~/myProject/ipfire-2.x/src/paks/< newItem >/update.sh

Final build

Finally you have to restart the build to produce the final product using the following commands:

sudo ./make.sh clean
sudo ./make.sh build

Testing the install, uninstall, update routines and add-on itself

You should now have a brand new packages/<newItem>-<version>-#.ipfire, so in this example we would have packages/newItem.ipfire

To test send the .ipfire file to an already-installed IPFire. Currently there is no easy way to install the pak using pakfire itself, though this is easily done manually via scp/ssh by extracting the package, copying the ROOTFILE to the pakfire db/rootfiles dir as your add-on name (required for uninstall) and executing the install.sh/upgrade.sh and uninstall.sh manually.

Thoroughly test the install/upgrade and uninstall scripts as well as the actual add-on.

#   enter these two commands on your personal computer
scp -P 222 newItem-1.0.0-2.ipfire root@ipfire.localdomain:/tmp
newItem-1.0.0-2.ipfire                          100%   19MB   9.6MB/s   00:02

ssh -p 222 root@ipfire.localdomain
Last login: Thu Nov 18 08:51:10 2010 from vmrunner.condarelli.it

#   enter the next commands on the IPFire terminal or console
cd /opt/pakfire/tmp/

cp -v cp /tmp/newItem-1.0.0-2.ipfire /opt/pakfire/tmp

tar xvf /tmp/newItem-1.0.0-2.ipfire

ls -l
total 39426
-rw-r--r-- 1 root root 20080640 2010-11-17 18:33 files
-rw-r--r-- 1 root root 20111360 2010-11-18 08:50 newItem-1.0.0-2.ipfire
-rwxr-xr-x 1 root root     1735 2010-11-17 18:33 install.sh
-rw-r--r-- 1 root root    13306 2010-11-17 18:33 ROOTFILES
-rwxr-xr-x 1 root root     1717 2010-11-17 18:33 uninstall.sh
-rwxr-xr-x 1 root root     1691 2010-11-17 18:33 update.sh

cp ROOTFILES /opt/pakfire/db/rootfiles/newItem

#   to install `newItem`
NAME=newItem ./install.sh
Extracting files...
bin/
bin/usb_printerid
...
usr/lib/cups/
usr/lib/cups/filter/
usr/lib/cups/filter/command2foo2lava-pjl
...Finished.
Stopping CUPS Printserver...                                                               [  OK  ]
Starting CUPS Printserver...                                                               [  OK  ]

#   to update `newItem`
NAME=newItem ./update.sh
Stopping CUPS Printserver...                                                               [  OK  ]
Removing files...
removed '/usr/lib/cups/filter/command2foo2lava-pjl'
removed directory '/usr/lib/cups/filter'
removed directory '/usr/lib/cups'
...
removed '/bin/usb_printerid'
...Finished.
Extracting files...
bin/
bin/usb_printerid
...
usr/lib/cups/
usr/lib/cups/filter/
usr/lib/cups/filter/command2foo2lava-pjl
...Finished.
Stopping CUPS Printserver...                                                               [  OK  ]
Starting CUPS Printserver...                                                               [  OK  ]

#   to remove `newItem`
NAME=newItem ./uninstall.sh
Stopping CUPS Printserver...                                                               [  OK  ]
Removing files...
removed '/usr/lib/cups/filter/command2foo2lava-pjl'
removed directory '/usr/lib/cups/filter'
removed directory '/usr/lib/cups'
...
removed '/bin/usb_printerid'
...Finished.

rm *
rm: remove regular file 'files.tar.xz'? y
rm: remove regular file 'install.sh'? y
rm: remove regular file 'ROOTFILES'? y
rm: remove regular file 'uninstall.sh'? y
rm: remove regular file 'update.sh'? y

rm /opt/pakfire/db/rootfiles/newItem
rm: remove regular file '/opt/pakfire/db/rootfiles/newItem'? y

logout
Bye bye.
Connection to ipfire closed.

After an invocation of NAME=newItem ./install.sh or NAME=newItem ./update.sh, the Package is installed and ready to run.

Note!
If there's something wrong and you need to modify some of the files in the upstream archive (i.e.: the archive downloaded from ${DL_FROM}/${DL_FILE}), you will need to prepare a patch and to add the information in the recipe. I plan to write a page on that; it will be linked here.

Next Step: Sharing with others

TODO: How can your package be added to the pakfire list in ipfire?
Pakfire build services??
How to change Branches (stable, testing, unstable) Process to submit??

How can someone install an unhosted, unofficial pakfire? Only using the testing steps?
FIXME / TBD

The End

That's all, Folks!