Extending Nard

icon git

Subdivided repositories

The product recipe can reference both local application archives and remote separate repositories. Want to play with latest bleeding edge wpa_supplicant for WiFi? No problem, just link it's Git repo in your custom product recipe and it will be downloaded during build:

$ cat nard/platform/my_product/Rules.mk
    PKGS_APPS += wpa_supplicant/http//w1.fi/hostap.git     # No ":"

It will override any parent wpa_supplication version in the inheritance chain. Notice the format! It's a standard web URL with the colon character removed from "http://".

inheritance override

A list of all supported recipe reference formats:

# Local file nard/apps/myapp/myapp-2.0.tar.gz
PKGS_APPS += myapp/myapp-2.0

# Remote file via HTTP
PKGS_APPS += myapp/http//example.com/myapp.tar.gz
PKGS_APPS += myapp/http//example.com/myapp-2.0.tar.gz

# Remote file via FTP
PKGS_APPS += myapp/ftp//example.com/myapp.tar.bz2

# Read-only Git
PKGS_APPS += myapp/git//example.com/proj/myapp.git

# Read-only Git via HTTP, specific branch, tag or commit hash
PKGS_APPS += myapp/http//example.com/proj/myapp.git^branch

# Read-write Git via HTTPS
PKGS_APPS += myapp/https//github.com/proj/myapp.git

# Read-write Git via SSH, specific branch, tag or commit hash
#   note there is no ":" after the domain name.
PKGS_APPS += myapp/git@github.com/proj/myapp.git^branch

The file nard/apps/openLightingArchitecture/README contains further examples.


icon new application

New applications

Adding a new application requires some general knowledge about Make, shell scripts and gcc. However, have you ever written a Makefile you'll be fine. Start with creating a directory and download the package. It's advised to name the directory in same manner as the downloaded file:

$ cd /your/path/nard
$ mkdir -p apps/mpg123
$ cd apps/mpg123
$ wget http://www.mpg123.de/download/mpg123-1.21.0.tar.bz2

Extract your downloaded tarball and inspect how to build it. Does it have a configure script? Is there a Makefile already?

$ tar -xf mpg123-1.21.0.tar.bz2
$ cd mpg123-1.21.0
$ ls -l
  drwxr-xr-x 2  248 2014-09-28 23:31 build
  drwxr-xr-x 3  632 2014-09-28 23:31 doc
  drwxr-xr-x 2  240 2014-09-28 23:31 m4
  drwxr-xr-x 2   96 2014-09-28 23:31 man1
  drwxr-xr-x 5  176 2014-09-28 23:31 ports
  drwxr-xr-x 2  168 2014-09-28 23:31 scripts
  drwxr-xr-x 5 1.6K 2014-09-28 23:31 src
  -rw-r--r-- 1  47K 2014-09-28 23:28 aclocal.m4
  -rw-r--r-- 1 7.8K 2014-09-28 23:27 AUTHORS
  -rw-r--r-- 1  109 2014-09-28 23:27 ChangeLog
  -rwxr-xr-x 1 598K 2014-09-28 23:28 configure         (1)
  -rw-r--r-- 1  75K 2014-09-28 23:27 configure.ac
  -rw-r--r-- 1  40K 2014-09-28 23:27 COPYING
  -rw-r--r-- 1  459 2014-09-28 23:27 equalize.dat
  -rw-r--r-- 1 5.5K 2014-09-28 23:27 INSTALL           (2)
  -rw-r--r-- 1  235 2014-09-28 23:27 libmpg123.pc.in
  -rw-r--r-- 1  490 2014-09-28 23:27 makedll.sh
  -rw-r--r-- 1 4.0K 2014-09-28 23:27 Makefile.am
  -rw-r--r-- 1  35K 2014-09-28 23:28 Makefile.in
  -rw-r--r-- 1 1.9K 2014-09-28 23:30 mpg123.spec
  -rw-r--r-- 1 1.9K 2014-09-28 23:27 mpg123.spec.in
  -rw-r--r-- 1  68K 2014-09-28 23:27 NEWS
  -rw-r--r-- 1 4.2K 2014-09-28 23:27 NEWS.libmpg123
  -rw-r--r-- 1  12K 2014-09-28 23:27 README
  -rw-r--r-- 1 1.8K 2014-09-28 23:27 TODO
  -rwxr-xr-x 1 3.4K 2014-09-28 23:27 windows-builds.sh

We can see there is a configure (1) script bundled. The file INSTALL (2) likely holds some valuable information too.


Lets invoke the configure script to see what are our options:

$ ./configure --help
      […snip…]
  Installation directories:
    --prefix=PREFIX        architecture-independent files
    --exec-prefix=EPREFIX  architecture-dependent files
  System types:
    --build=BUILD          build on BUILD [guessed]
    --host=HOST            cross-compile for HOST
      […snip…]

There are a whole lots of options for tweaking the build. (Most of them removed here for clearity.) The important options tend to be prefix, sysconfdir, host, sysroot, CFLAGS and CPPFLAGS which we'll set in our custom cross-compile Makefile.


Let's create a Makefile by using an existing as a template:

$ cd /your/path/nard                               # Top level dir
$ cp nard/apps/ser2net/Makefile nard/apps/mpg123

Open the created nard/apps/mpg123/Makefile in a text editor and find the target $(PKG_VER)/.nard-build. Modify the build command to:

cd $(PKG_VER) && ./configure       \
    CFLAGS="$(CROSS_CFLAGS)"       \
    CPPFLAGS="$(CROSS_CFLAGS)"     \
    --prefix=/usr                  \
    --sysconfdir=/etc              \
    --host=$(CROSS_TUPLE)          \
    --with-sysroot=$(PATH_SYSROOT)
$(MAKE) -C "$(PKG_VER)" -j $(CPUS)

Next open the product recipe in a text editor:

$ emacs nard/platform/skeleton/Rules.mk

Add a line to the PKGS_APPS list. Note the format of the existing lines! First the application directory name, followed by a slash and last the application directory name again with a trailing version number. This should resolve to your downloaded tarball. For example, by adding:
  PKGS_APPS += mpg123/mpg123-1.21.0
there should be a corresponding file:
  nard/apps/mpg123/mpg123-1.21.0.tar.bz2
which will be automatically extracted during the build.


Now try build, push and test:

$ make
$ make upgrade                    # Wait while remote reboots
$ make ssh "mpg123 /dev/null"     # Remote start of our new program
    [oss.c:172] error: Can't open default sound device!
    [audio.c:643] error: failed to open audio device
    [audio.c:180] error: No working output from this list: oss
    make: *** [ssh] Error 99

Hmm, that didn't work… Wait, what is that on the first line of error: "oss.c"?
OSS is deprecated and not available in Nard. We need mpg123 to use ALSA only.


Going back to the mpg123 sources we run ./configure --help once more and search for clues… It turns out we also need the configure options --with-audio=alsa --with-default-audio=alsa in our nard/apps/mpg123/Makefile:

cd $(PKG_VER) && ./configure       \
    CFLAGS="$(CROSS_CFLAGS)"       \
    CPPFLAGS="$(CROSS_CFLAGS)"     \
    --prefix=/usr                  \
    --sysconfdir=/etc              \
    --host=$(CROSS_TUPLE)          \
    --with-sysroot=$(PATH_SYSROOT) \
    --with-audio=alsa              \
    --with-default-audio=alsa
$(MAKE) -C "$(PKG_VER)" -j $(CPUS)

With the modified Makefile we try again:

$ make
    checking build system type... i686-pc-linux-gnu
    checking host system type... arm-unknown-linux-gnueabi
        […snip…]
    Limiting outputs to build according to your preference: alsa
    checking for snd_pcm_open in -lasound... no
    configure: error: One of your requested audio modules failed!
    make: *** [mpg123-1.21.0/.nard-build] Error 1

Failed build. The ALSA audio library couldn't be found!


Although ALSA is available in Nard we need to enable it as well:

  1. Check your product recipe nard/platform/skeleton/Rules.mk and verify it contains: PKGS_APPS += salsa-lib/salsa-lib-0.1.3
  2. Add paths to the library sources by inserting: include $(PATH_APPS)/salsa-lib/Rules.mk
    early in our nard/apps/mpg123/Makefile. (Glance through it and you'll understand how it works.)

Now build yet again:

$ cd /your/path/nard
$ make
$ make upgrade                    # Wait while remote reboots
$ make ssh "mpg123 /dev/null"     # Remote start of our new program
    High Performance MPEG 1.0/2.0/2.5 Audio Player
    Directory: /dev/
    Playing MPEG stream 1 of 1: null ...
    [0:01] Decoding of null finished.

Success! We can now play MP3 files. You may want to inspect the files:
  – nard/apps/mpg123/Makefile
  – platform/mediaplayer/Rules.mk
for the end result. Use amixer from the alsa-utils package to control volume.


icon debian

Debian compatibility layer

An extention to Nard enables installation of binary .deb files from the Raspbian Wheezy archive. Dependencies are resolved automatically, just as with apt-get. Simply add e.g. "nano" to a configuration file and you get a fully featured text editor in the target.

Applications natively available in Nard are tuned for low resources and are thus the preferred choice. Raspbian on the other hand is heavy weight, with lots of bells and whistles and should therefore be avoided in embedded systems. Nevertheless, Raspbian has LOTS of packages readily available, so if you find integrating new applications manually are too overwhelming, this might be the remedy. Especially during development it's handy for temporary tools like packet sniffers, text editors, performance testers and such alike. Beware of "huge" applications like Firefox and OMXPlayer though, they are unlikely to work. Stick with small utilities and daemons. Here is a list of applications known to operate well:

Search for additional packages here. Configuration of what Debian/Raspbian packages to install mimics product recipes (inherits ancestor). Here is a simplified example:

debian add-on conf

As can be seen in the illustration, inherited products bring their Debian packages along, just as with native Nard applications. The file nard/platform/audit/debian.config can be used as a configuration template. Remember to enable the Debian layer itself, as well as these required build utilities in your product recipe:

$ cat nard/platform/my_product/Rules.mk
    PKGS_APPS += debian/debian
    PKGS_UTILS += xz-embedded/xz-embedded-20130513
    PKGS_UTILS += fakeroot/fakeroot-1.20.2
    PKGS_UTILS += fakechroot/fakechroot-2.17.2

Please note that the Debian compatibility layer is not as perfect as apt-get and still somewhat experimental! Occasionally it may need manual intervening. Also, daemons are installed but they aren't automatically started at boot (arrange yourself). Feedback and comments are welcome. The Debian compatibility layer is part of the add-on.


icon new product

New products

The introduction showed how new products may inherit from an elementary; and herewith features can be added on top of a solid base. Look at the mediaplayer example product which does this:

nard
└── platform
    └──mediaplayer
       ├── Rules.mk                (1)
       ├── firmware-template
       │   └── data
       │       └── tone.wav        (2)
       ├── fs-template
       │   └── etc
       │       └── rc.mediaplayer  (3)
       └── linux-rpi-3.10.y.config (4)

The Rules.mk (1) above contain a dependency on the skeleton example product like this:

PRODUCT_DEPS += skeleton
-include $(PATH_TOP)/platform/skeleton/Rules.mk

Through this dependency everything in skeleton (such as SSH, BusyBox etc.) will emerge in mediaplayer too. By adding applications in Rules.mk (1) "on top" of skeleton we build a new product:

PKGS_APPS += mpg123/mpg123-1.21.0
PKGS_APPS += fbi/fbi-1.31
PKGS_APPS += jpeg-lib/jpeg-lib-8d

Here we add mpg123 for audio and fbi for pictures.


Our mediaplayer launches whenever the system boots by creating the file rc.mediaplayer (3) with content:

# Play a startup sound each boot
start-stop-daemon -Sbx /usr/bin/aplay -q /boot/data/tone.wav

Finaly there is a custom kernel configuration (4). It is almost identical with the corresponding from skeleton, with the addition of sound and framebuffer drivers enabled.



icon separator