= Overview = `liblitmus` is the userspace library of LITMUS^RT^. When you compile `liblitmus`, a static library file named `liblitmus.a` is created. Userspace applications can and should link against this library like any other shared library. When creating userspace test tools, it may be tempting to create new tools within the `liblitmus` repository. However, this is not recommended as it is difficult to maintain when newer `liblitmus` versions become available. Instead, project-specific userspace tools should be maintained in separate repositories and explicitly link against `liblitmus`. To simplify this setup, `liblitmus` generates an include file (at `$LIBLITMUS/inc/config.makefile`) that is intended to be used in the Makefiles of projects that depend on `liblitmus`. The following tutorial shows how to use these include files. = Tutorial = In the following, we assume that you want to create a tool that depends on the LITMUS^RT^ userspace interface. The tutorial assumes that you have checked out '''and compiled''' `liblitmus` to a directory `$DIR/liblitmus` (where `$DIR` is arbitrary). == Step 1: Create a New Directory == Create a new directory in `$DIR`, say `$DIR/mytools/`, and create a sub-directory `$DIR/mytools/src/`. {{{#!highlight console numbers=off $ cd $DIR $ mkdir -p mytools/src }}} == Step 2: Create a Source File == For testing purposes, we'll create a simple dummy app that links against `liblitmus`. To this end, create a file `mytool.c` in `mytools/src` with the following contents. {{{#!highlight c #include #include /* include the main liblitmus header */ #include int main(int argc, char** argv) { struct rt_task param; int ready_rt_tasks, all_rt_tasks; init_litmus(); init_rt_task_param(¶m); /* Normally you would configure the task here, enter real-time mode, and start * the real-time computation, but we'll simply call a liblitmus function and * quit here as the goal is simply to test whether we can successfully link * against liblitmus. */ /* query the LITMUS^RT proc interface */ if (!read_litmus_stats(&ready_rt_tasks, &all_rt_tasks)) { perror("read_litmus_stats"); exit(1); } printf("There are %d real-time tasks waiting for a synchronous " "task system release.\n", ready_rt_tasks); printf("There are %d real-time tasks in total.\n", all_rt_tasks); return 0; } }}} == Step 3: Create a Makefile == Next, we'll setup the new project to link against `liblitmus` by reusing the build framework of `liblitmus`. To this end, create a `Makefile` in `mytools/` with the following contents. {{{#!highlight make # ############################################################################## # User variables # user variables can be specified in the environment or in the local make.conf file -include make.conf # Where is the LITMUS^RT userspace library source tree? # By default, we assume that it resides in a sibling directory named 'liblitmus'. LIBLITMUS ?= ../liblitmus # Include default configuration from liblitmus. # IMPORTANT: Liblitmus must have been built before this file exists. include ${LIBLITMUS}/inc/config.makefile # all sources vpath %.c src/ # local include files CPPFLAGS += -Iinclude/ # ############################################################################## # Targets all = mytool .PHONY: all clean all: ${all} clean: rm -f ${all} *.o *.d obj-mytool = mytool.o mytool: ${obj-mytool} # dependency discovery include ${LIBLITMUS}/inc/depend.makefile }}} This completes the setup. == Testing == You should now be able to compile `mytool` and link against `liblitmus`, which should look similar to this. {{{#!highlight console numbers=off $ make /usr/bin/gcc -O2 -Wall -Werror -g -Wdeclaration-after-statement -D_XOPEN_SOURCE=600 -D_GNU_SOURCE -m64 -DARCH=x86_64 -I../liblitmus/include -I../liblitmus/arch/x86/include -I../liblitmus/arch/x86/include/uapi -I../liblitmus/arch/x86/include/generated/uapi -Iinclude/ -c -o mytool.o src/mytool.c /usr/bin/gcc -m64 mytool.o -L../liblitmus -llitmus -o mytool }}} You should now be able to run `./mytool`. {{{#!highlight console numbers=off $ file mytool mytool: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.18, not stripped }}} On a non-LITMUS^RT^ kernel, you'll see a bunch of error messages because the task initialization fails. {{{#!highlight console numbers=off $ ./mytool mlockall(): Cannot allocate memory Warning: Could not initialize LITMUS^RT, mlockall() failed. init_kernel_iface: cannot open LITMUS^RT control page (No such file or directory) kernel <-> user space interface initialization: No such file or directory Warning: Could not initialize LITMUS^RT, kernel <-> user space interface initialization failed. read_litmus_stats: No such file or directory }}} On a LITMUS^RT^ kernel, the tool should run without error messages if executed as root. == Adding Additional Build Targets == To add additional build targets, you can simply add them to the `all` list. For example, suppose you wanted to add a second application called `myapp`, and further suppose that `myapp` also needs to link against `librt` (Linux's POSIX real-time library) to get access to `clock_gettime()`. This can be realized with the following steps: 1. Add a target `myapp` to `all`. This should look now like: ` all = mytool myapp` 2. Add `-lrt` to `LDLIBS`, like this: `LDLIBS += -lrt`. It's important that you use `+=` (and not `=`) to ensure that the settings of `liblitmus` are not removed. 3. Add the list `obj-myapp` to list all object files needed for `myapp`. For example: `obj-myapp = myapp.o` if there is a file `mytools/src/myapp.c` 4. Add the target for `myapp`, like this: `myapp: ${obj-myapp}`. As a result, the Makefile should now look as follows. {{{#!highlight make [...] # ############################################################################## # Targets all = mytool myapp LDLIBS += -lrt .PHONY: all clean all: ${all} clean: rm -f ${all} *.o *.d obj-mytool = mytool.o mytool: ${obj-mytool} obj-myapp = myapp.o myapp: ${obj-myapp} [...] }}} == Cleanup == The makefile automatically includes a `clean` target to remove all build products. {{{#!highlight console numbers=off $ make clean rm -f mytool myapp *.o *.d }}} == Discussion == The method described in this tutorial is the preferred way to link against `liblitmus`, as it prevents the accumulation of cruft in `liblitmus`. Even though `liblitmus` already contains a bunch of tools in `bin/`, it should not accumulate further project-specific tools and applications. Further, it ensures that clients of `liblitus` are compiled with compatible flags. If you use a cross-compiler to build `liblitmus` (e.g., to build binaries for an ARM target), then any project using `/inc/config.makefile` will by default also be built using the cross-compiler. In our experience, this simplifies cross-compilation setups considerably. Optionally including the local file `make.conf` (which doesn't have to exist) makes it possible include local settings that are never committed to `git`. It's not strictly needed, but if you plan on collaborating with others (who, for example, might have checked out `liblitmus` at a different path), this is a useful feature and we recommend that you always provide this functionality in LITMUS^RT^-related Makefiles.