Friday, January 13, 2017

The new Ubuntu SDK, part 1

[Update: Changed links to source code from and to which is where the current tools probably live.]

In September of 2016 Canonical released an updated version of the Ubuntu SDK. The main change there was a move from the schroot-based build images (kits) to LXD-based images as can be read in the announcement. Some more details are mentioned in the beta announcement. But that's about all I found about this change.

Luckily, there are some other places where one can see how does the new SDK work and how to use it from the command line:
If you're confused by the relationship between LXD and LXC this post might help.

It turns out the new change basically means that the click command-line tool is used to create the actual click package but for compiling the click chroot functionality is no longer used. It's been replaced by the LXC containers.

If you have the current Ubuntu SDK installed (and you installed also at least one kit), you can list the kits (and perhaps other LXC containers, if you have some) by running lxc list. You might for example get:

$ lxc list
|     NAME     |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
| desktop      | STOPPED |      |      | PERSISTENT | 0         |
| device-armhf | STOPPED |      |      | PERSISTENT | 0         |
| device-i386  | STOPPED |      |      | PERSISTENT | 0         |

Unless the Ubuntu SDK has started some of them they are in the state STOPPED. You can start a container by lxc start, for example to start the device-armhf container, run:

lxc start device-armhf

When a container is running, you can run commands in it, for example:

$ lxc exec device-armhf -- arm-linux-gnueabihf-gcc -v
Using built-in specs.
Target: arm-linux-gnueabihf
Configured with: ../src/configure -v --with-pkgversion='Ubuntu/Linaro 4.9.2-10ubuntu10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/arm-linux-gnueabihf/include/c++/4.9.2 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-libitm --disable-libquadmath --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf-cross/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-armhf-cross --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-armhf-cross --with-arch-directory=arm --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --disable-libgcj --enable-objc-gc --enable-multiarch --enable-multilib --disable-sjlj-exceptions --with-arch=armv7-a --with-fpu=vfpv3-d16 --with-float=hard --with-mode=thumb --disable-werror --enable-multilib --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=arm-linux-gnueabihf --program-prefix=arm-linux-gnueabihf- --includedir=/usr/arm-linux-gnueabihf/include
Thread model: posix
gcc version 4.9.2 (Ubuntu/Linaro 4.9.2-10ubuntu10) 
(The -- separate the arguments of lxc from the command to run. Without it, lxc would interpret the -v as a switch for itself.)

The previous post uses click chroot to build the application binary. The new approach with LXC could look like this:

lxc exec device-armhf -- su $USER -c bash -c "cd $PWD; arm-linux-gnueabihf-g++ hello-world.cpp -o hello-world"

This is a bit more complex because LXC is more low-level and by default gives you root shell in the terminal. And the working directory is the root's home.

There is another way though: The package ubuntu-sdk-tools contains the tool usdk-target which handles all this. There is no man page for it, but running usdk-target help gives you some information:
$ usdk-target help
Usage: usdk-target [subcommand] [options]
Available commands:
 autofix    - Automatically fixes problems in the container backends.
 autosetup  - Creates a default config for the container backend.
 create     - Missing summary.
 destroy    - Deletes a container.
 exec       - Executes a command in the container.
 exists     - Checks if a container exists.
 help       - Presents details on how to use usdk-target.
 images     - Shows the available Ubuntu SDK images.
 initialized - Checks if the container backend is setup correctly.
 list       - Lists the existing SDK build targets.
 maint      - Executes a command in the container.
 register   - Register a user into the target.
 rootfs     - Shows the path to the root filesystem of a container.
 set        - Change container flags.
 status     - Shows the current status of the container.
 upgrade    - Upgrades the container.
  LXD_CONF           Path to an alternate client configuration directory.
  LXD_DIR            Path to an alternate server directory.

To build the hello-world binary, you can just run:
usdk-target exec arm-linux-gnueabihf-g++ hello-world.cpp -o hello-world

(Just note that usdk-target kills your locale settings. Why? Don't ask me. It's supposedly a feature...)

There are some more useful details:
  • usdk-target maint gives you a root shell (the documentation isn't too explicit about this) - this is similar to click chroot maint.
  • To get a non-root shell inside the container using usdk-target just run usdk-target KIT_NAME exec, without any other arguments. usdk-target has a special handling for this.
So, using usdk-target for compilation and click build for packaging, one can build a click package on the command line using the current state of things.

No comments:

Post a Comment