Making an Opkg Package

Tuesday, October 19, 2010

Now that we have Opkg for Android, we could use it to install packages from local files or off Web servers. Installing a package is as simple as

opkg install path/to/package.opk

or, if it’s on the Web

opkg install http://host/path/to/package.opk

And to remove the package, we would go

opkg remove name-of-package

But what if we wanted to share our own software with others? In this case, we would create our own packages. An Opkg package is essentially a Debian package with fewer control fields. If you know how to make a Debian package, you should be well on your way. In general, a package is an ar archive containing a control tarball, a data tarball, and a debian-binary file. For example let’s have a look at the opkg-hello package:

package.opk (ar)
+- debian-binary (text)
+- control.tar.gz (tarball)
...+- control (text)
...+- preinst (script)
...+- postinst (script)
...+- prerm (script)
...+- postrm (script)
+- data.tar.gz (tarball)
...+- system
......+- bin
.........+- opkg-hello (example program)

Now, debian-binary simply contains the string 2.0; it signifies that the archive is indeed a Debian[esque] package. The files within control.tar.gz are cached when the package is installed, and contain information about the package itself, how the package is to be installed, and how the package is to be removed. The contents of control describe the package and are used to build the repository feed, which we will cover later. There are also scripts that govern the installation and removal processes and require execution permission: preinst runs before the package is extracted, postinst performs any configuration after the main files are in place, prerm prepares the system before the package is removed, and postrm cleans up after the main files are gone. Let’s have a look inside these files:

Package: opkg-hello
Version: 0.0.1
Description: Sample OPKG package
Section: cyanogenmod/applications
Priority: optional
Maintainer: Jiang Yio
Architecture: all

echo "preinst: preparing to install package"
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system

mount -o ro,remount -t yaffs2 /dev/block/mtdblock3 /system
echo "postinst: installed package"

echo "prerm: preparing to remove package"
mount -o remount,rw -t yaffs2 /dev/block/mtdblock3 /system

mount -o ro,remount -t yaffs2 /dev/block/mtdblock3 /system
echo "postrm: removed package"

Other than emitting some debugging information, the scripts also make the /system tree writable while the package is installed or removed.

Now that we have the anatomy of an Opkg package, we could create more like it with ease. Here are a couple of helpful commands:

make a tarball
tar zcvf name-of-tarball.tar.gz list of files and directories

make an archive
ar -r name-of-archive.opk list of files and directories

Other than that, just be sure all the files have the right owner, group, and permission. It would also help to know something about the Android directory tree — for example, we dropped the example program in /system/bin, which we know is part of the search path.


  1. 8ut8f8rder says:

    Here is a script that will build an opkg package.
    It was an ipkg script before. I made some minor changes now it drops opk.

    mkdir FILE && mkdir FILE/CONTROL && mkdir FILE/system && mkdir FILE/system/bin

    touch FILE/CONTROL/control && touch FILE/CONTROL/preinstall and so on… put your things in.

    than set the owner:
    chown -hR root:root FILE

    ./ FILE

    packed is ready to install

  2. Jiang says:

    Thanks for sharing this. Also worth noting is that Opkg knows how to work with Ipkg packages.

    Some devices require that parts of the filesystem be remounted read-write before Opkg could do its work. My distribution has a /system/bin/opkg script that takes care of the remounting before and after running /system/bin/opkg-cl. I have noticed that letting packages manage the mounting is not very portable and leads to problems when many packages are installed together.

  3. 8ut8f8rder says:

    Whats the exact problem, if I do the mounting stuff in the contol files? I made only some packages with binarys for /system/bin until now. I have set up an experimental repo in my dropbox. Its made for android-1.6.

    I have seen you packaged a lot of gapps. I guess, I should check out these.

    Would you pass me your opkg-wrapper script? So I wouldnt run in the same trouble.

  4. Jiang says:

    Check this out (/usr/bin/opkg)…

    mount -o remount,rw /
    mount -o remount,rw /system
    /system/bin/opkg-cl $@
    mount -o ro,remount /system
    mount -o ro,remount /

    When you manipulate multiple packages, control scripts are run before and after all the packages have been unpacked or removed. I had some trouble with remounting the filesystem read-only 20 times in a row, which lead to errors :)

    Also, I don’t trust these gapps packages. They were built for testing purposes (and to demonstrate delivery of APK’s via Opkg), but some of them may not be perfect. I built them in bulk using a script.

  5. 8ut8f8rder says:

    Yeah thats true… but in case some uses the command opkg-cl we need to check whether it rw or ro

    I put something like this in my preinstall and preremove:


    if [ “$(busybox grep -il /system.*rw /proc/mounts > /dev/null;echo $?)” != “0” ];then
    mount -o remount,rw /system
    echo “postinst: installed package”

  6. 8ut8f8rder says:

    great… where do you want to put the tmp folder in?

    I made a repository with all the DRC83 gapps from this server: they are for 1.6, but its just for testing to figure out what depends on what. This is my current Package file:

    I think we need some standarts for the names and sections of all these packages.

  7. Jiang says:

    Good job with the repo. I see you have quite a few goodies in there.

    I think it makes sense to put temporary files somewhere in /cache, since that’s what /cache is used for. On the other hand, config files might be better off under /system/etc. The only reason I didn’t put them there to begin with is that /system is usually read-only and I was in a hurry.

    Package naming does need standardization. So far, for “core” packages I’d just call it the name of the program. For third-party packages, I’d do something like vendor-name. And if it’s part of a collection, I’d do collection-name or vendor-collection-name. Architectures might need standardization too. We could use architectures to target not only specific processor architectures, but also specific screen resolutions and specific versions of the Android OS.

    So… we might need a community-editable wiki :D

  8. 8ut8f8rder says:

    I had a look in the files of googles ndk, the complier can deal with armeabi and armeabi-v7a so we should use this for the arch.conf. Its in the NDKROOT/build/toolchains/arm-eabi-4.4.0/ file.

    The wiki is a good idea. I dont have a webserver, if you want, feel free to set one up. :)

    The android version should we manage over the repository, as I know, there is only one declaration for a package allowed. But it isn’t a problem for a maintainer to separate this stuff in the repository url. Instead we could give an option for the used board/device, because of specific things like camera drivers and stuff.

    Here is a idea for the example config files:

    Ok, tmp goes in /cache config and binarys in /system. And the –with-opkglibdir= option? It places the package index there, so it must be writeable. I would say /data/local/lib

  9. 8ut8f8rder says:

    Here is a with the old syntax:

    It installs Opkg, an improved version of your remount script, wget and the config files. I couldnt figure out how to link curl an openssl. Its just a basic version.

  10. Jiang says:

    Alright so… I’ve put up a wiki page. I decided to require registration for spam control, but that should be pretty painless anyway (until I figure out how to integrate it with OpenID or this blog, or something)…

    Ah, I haven’t tried cURL/OpenSSL in a while because the resulting build didn’t work exactly right for me. The configuration script should point you at some –with-* options, and you’ll have to link in the relevant libraries during the final step. For cURL, I remember I had to compile my own static libcurl without gssapi (which is only available as a shared library). Eventually, this should not be a problem once we get shared libraries working.

  11. 8ut8f8rder says:

    I made an account for the wiki. I will add my stuff, should I get it compiled in the ndk.

  12. Jiang says:

    Thanks; I would love to see how that turns out. I haven’t touched the NDK yet.

  13. Gilles says:

    Thanks for the tutorial. I’ve never built packages before (Debian, or otherwise), and followed it step-by-step to build my first Opkg package, but it fails installing: “Collected errors: * pkg_init_from_file: Malformed package file package.opk.”

    I removed the two empty lines in “control” (Source and Depends), to no avail.

    Incidently, this is on an appliance running uClinux.

    Any hint appreciated.

  14. Jiang says:

    The error message is quite generic. I’d find some prebuilt packages (OpenWrt has lots!), unpack them, and use them for reference.

  15. mateor says:

    ok, thanks for the info. Sounds easy from here…we’ll see.

    Smiley Face/Winky Face/Sad Face
    /\ /\
    I I

  16. mateor says:

    oh. Success.

    Happy face.