Nuxi

Nuxi CloudABI for Fedora

Though CloudABI has initially been developed on FreeBSD, a fairly complete implementation for the Linux kernel has also been developed.

This document explains how to develop software for CloudABI on Fedora systems and how these systems can be configured to run this software. Right now this still requires you to perform a significant number of manual steps, but work is underway to streamline this process by packaging and upstreaming most of these components.

1. Installing a C and C++ compiler for CloudABI

CloudABI uses a toolchain based on LLVM, Clang and LLD for building C and C++ software. Though the version of Clang shipped with Fedora 23 (3.7.0) is sufficient for compiling code for CloudABI, only the upcoming version of LLD (3.9.0) is mature enough to generate executables properly. Until this version has been released and packaged by Fedora, we advise that LLVM is built from trunk.

The following commands can be used to build LLVM, Clang and LLD from SVN and install them into /usr/local/llvm-trunk:

$ sudo dnf install -y cmake gcc gcc-c++ ninja-build subversion $ svn co https://llvm.org/svn/llvm-project/llvm/trunk llvm $ svn co https://llvm.org/svn/llvm-project/cfe/trunk llvm/tools/clang $ svn co https://llvm.org/svn/llvm-project/lld/trunk llvm/tools/lld $ mkdir build $ cd build $ cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr/local/llvm-trunk ../llvm ... -- Configuring done -- Generating done -- Build files have been written to: /home/ed/llvm/build $ ninja-build $ sudo ninja-build install

After installing LLVM, we can create a number of symbolic links in /usr/local/bin that point to the utilities provided by LLVM, having the CloudABI cross compilation target prefixed to their name. LLVM automatically acts like a cross compiler for CloudABI when invoked through these symbolic links.

for target in aarch64-unknown-cloudabi i686-unknown-cloudabi x86_64-unknown-cloudabi; do for tool in ar nm objdump ranlib size; do sudo ln -s ../llvm-trunk/bin/llvm-${tool} /usr/local/bin/${target}-${tool} done sudo ln -s ../llvm-trunk/bin/clang /usr/local/bin/${target}-cc sudo ln -s ../llvm-trunk/bin/clang /usr/local/bin/${target}-c++ sudo ln -s ../llvm-trunk/bin/lld /usr/local/bin/${target}-ld sudo ln -s ../../${target} /usr/local/llvm-trunk/${target} done

The commands above set up the Clang C and C++ compiler for every architecture supported by CloudABI, thus making it very easy to cross compile software for other hardware:

$ ls /usr/local/bin/*-unknown-cloudabi-{cc,c++} /usr/local/bin/aarch64-unknown-cloudabi-c++ /usr/local/bin/aarch64-unknown-cloudabi-cc /usr/local/bin/i686-unknown-cloudabi-c++ /usr/local/bin/i686-unknown-cloudabi-cc /usr/local/bin/x86_64-unknown-cloudabi-c++ /usr/local/bin/x86_64-unknown-cloudabi-cc

2. Accessing the CloudABI Ports Collection

The CloudABI Ports Collection provides copies of precompiled libraries that you can use to build complex CloudABI applications. Software that is part of the CloudABI Ports Collection is automatically packaged for a variety of systems, including RPMs for Fedora.

The CloudABI Ports Collection can be accessed by adding a configuration file for the repository to /etc/yum.repos.d:

$ sudo tee /etc/yum.repos.d/cloudabi.repo << EOF [cloudabi-ports] name=CloudABI Ports baseurl=https://nuxi.nl/distfiles/cloudabi-ports/redhat/ gpgkey=https://pgp.mit.edu/pks/lookup?op=get&search=0x0DA51B8531344B15 gpgcheck=0 repo_gpgcheck=1 EOF $ sudo dnf update ... Importing GPG key 0x31344B15: Userid : "CloudABI Ports Collection for Red Hat <info@nuxi.nl>" Fingerprint: 1EAC 388A 6C0D 6572 1A22 3743 0DA5 1B85 3134 4B15 From : https://pgp.mit.edu/pks/lookup?op=get&search=0x0DA51B8531344B15 Is this ok [y/N]: y

It typically makes sense to at least install the standard C++ runtime environment package, so that it is possible to compile C and C++ applications that depend on just core C, C++ and POSIX interfaces:

$ sudo dnf install -y x86_64-unknown-cloudabi-cxx-runtime ... Installed: x86_64-unknown-cloudabi-cloudabi.noarch 0.6-1 x86_64-unknown-cloudabi-cloudlibc.noarch 0.30-1 x86_64-unknown-cloudabi-compiler-rt.noarch 3.8.0-3 x86_64-unknown-cloudabi-cxx-runtime.noarch 1.0-2 x86_64-unknown-cloudabi-libcxx.noarch 3.8.0-5 x86_64-unknown-cloudabi-libcxxabi.noarch 3.8.0-5 x86_64-unknown-cloudabi-libunwind.noarch 3.8.0-4 Complete!

A full list of packages provided by the CloudABI Ports Collection can be obtained by running the following command:

$ dnf --disablerepo=\* --enablerepo=cloudabi-ports list available Available Packages aarch64-unknown-cloudabi-boost.noarch 1.60.0-10 cloudabi-ports aarch64-unknown-cloudabi-buddy.noarch 2.4-9 cloudabi-ports aarch64-unknown-cloudabi-bzip2.noarch 1.0.6-9 cloudabi-ports aarch64-unknown-cloudabi-c-runtime.noarch 1.0-2 cloudabi-ports ...

3. Executing CloudABI applications

Our eventual goal is to provide support for CloudABI in the form of a kernel module that can be used in combination with a stock Linux kernel. Unfortunately we still depend on a fair number of local changes to the kernel that need to be upstreamed first, meaning that support for CloudABI is currently only available in the form of a modified Linux kernel with integrated CloudABI support.

The following instructions show how this kernel can be checked out, built, packaged and installed, using the standard RPM kernel build target:

$ sudo dnf install -y git openssl-devel rpm-build $ git clone https://github.com/NuxiNL/linux.git Cloning into 'linux'... $ cd linux $ git branch -l * cloudabi $ cp /boot/config-$(uname -r) .config $ make oldconfig ... Enable clone4() system call (CLONE4) [Y/n/?] (NEW) y Enable CLONE_FD flag for clone4() (CLONEFD) [Y/n/?] (NEW) y ... Kernel support for CloudABI ELF binaries (BINFMT_ELF_CLOUDABI) [N/y/?] (NEW) y ... Capsicum capabilities (SECURITY_CAPSICUM) [Y/n/?] (NEW) y ... # configuration written to .config $ make rpm ... Wrote: /home/ed/rpmbuild/RPMS/x86_64/kernel-4.5.0_cloudabi+-3.x86_64.rpm ... $ sudo rpm -i /home/ed/rpmbuild/RPMS/x86_64/kernel-4.5.0_cloudabi+-3.x86_64.rpm $ sudo reboot

After rebooting, CloudABI executables can be executed directly:

$ cat hello.c #include <stdio.h> int main(void) { dprintf(1, "Hello, world\n"); } $ x86_64-unknown-cloudabi-cc -o hello hello.c $ ./hello Hello, world

It also makes sense to install the cloudabi-utils package that contains the cloudabi-run utility. This tool can be used to spawn CloudABI applications safely, ensuring that no resources are accidentally leaked into the process. It can be installed as follows:

$ sudo dnf install -y libyaml-devel $ git clone https://github.com/NuxiNL/cloudabi.git Cloning into 'cloudabi'... $ sudo install -m 444 cloudabi/headers/* /usr/local/include/ $ git clone https://github.com/NuxiNL/cloudabi-utils.git Cloning into 'cloudabi-utils'... $ cd cloudabi-utils $ cmake . $ make ... Linking C executable cloudabi-run [100%] Built target cloudabi-run $ sudo make install ... -- Installing: /usr/local/bin/cloudabi-run $ sudo tee /etc/ld.so.conf.d/local.conf << EOF /usr/local/lib64 EOF $ sudo ldconfig

The shell commands below show how cloudabi-run can be used to execute the CloudABI test suite. Please refer to cloudabi-run's manual page for more examples.

$ mkdir tmp-unittest $ cloudabi-run /usr/x86_64-unknown-cloudabi/bin/cloudlibc-unittests << EOF %TAG ! tag:nuxi.nl,2015:cloudabi/ --- tmpdir: !file path: tmp-unittest logfile: !fd stdout nthreads: !!int 8 EOF