Porting to the LSB Demo

Note: This article is out of date in some places, but is kept for posterity.

Because Linux is an open operating system, you can configure and assemble it to suit specialized purposes. However, while variety and choice are beneficial for users, heterogeneity can vex software developers who must build and support packages on a multitude of similar but subtly different platforms. Fortunately, if an application conforms to the Linux Standard Base (LSB) and a flavor of Linux is LSB compliant, the application is guaranteed to run. Discover the LSB, and learn how to port your code to the standard.

This tutorial describes the Linux Standard Base (LSB), a specification and collection of tools and test suites that help Linux software developers increase compatibility among Linux software distributions. Applications and distributions can be certified compliant with the specification, providing assurances to users that certified software is compatible. This tutorial describes the LSB and explains how to vet your application code to conform with it.

Prerequisites

To benefit from this tutorial, you should have experience with the C or C'' programming language as well as the typical Linux software development environment and its cadre of tools, including the compiler, linker, system libraries, configuration and build utilities, and packaging tools. You should also have experience installing software from the command line and have at least a modicum of experience with administering and maintaining a Linux system, such as configuring a file system, starting and stopping network services, and adding system services. If you're running Debian Linux, you should also have some experience with the APT package manager. Before you start the tutorial, you must install several software packages on your Linux system. Here's everything you need: * The [[http://kvm.qumranet.com

sudo apt-get install kvm

in a terminal window. Or, you can use the Synaptics package manager if you prefer using a graphical interface. As packaged in the Debian and Ubuntu distributions, in order to use kvm without being root, your user id must be in the “kvm” group. You can edit the /etc/group via a text editor as the superuser, or if you are running Ubuntu, you can use the menu selection System→Administration→Users and Groups from the system's menubar, and then on the click on the “Unlock” button, enter your password, then click on “Manage Groups”. This will cause a “Group Settings” window to appear. Find “kvm” in the selection window, and then click on “Properties”, and then add a check-mark next to your user id in the “Group Members” list, and then click the “OK” button. After you make a change to the group membership of the “kvm” group, you will need to logout and then login again so the change can take effect. ====Running KVM==== To start the KVM virtual machine you simply untar the lsb-siX-vm tarball and run the following command in a terminal window:

kvm lsb-siX-vm-4.0.1-2.i686-1.1.2.vmdk

The KVM application traps all mouse and keyboard input unless you press Ctrl+Alt. To set the focus back to the virtualized environment, just click in the KVM window. There are additional arguments mentioned in the README that comes with the lsb-siX appliance that allow networking and port redirection to move files in and out of the virtual machine. Congratulations! You now have openSUSE 11.1 running in its own VM! =====Porting Your Code to the LSB===== With setup behind you, you can begin the process of porting your code to the LSB. ====The General Approach to Porting==== Porting an application to the LSB requires the following steps: - Copy your code to the new build system.The new build system might be an LSB-compliant Linux distribution running on separate hardware or, in this case, a VM. - Build your code, and run the Linux Application Checker (“AppCheck”) tool to scan your binary for symbols that are not expressly provided in the LSB specification.You can also this tool to scan your static archives for suitability for use in an LSB-compliant application. - If AppCheck finds invalid symbols, change your code or the assembly of your code to bring it into compliance.For instance, if you're using a library that isn't part of the LSB specification, link to it statically so that the code is self-contained in your binary. (Again, this assumes that the code in the library itself is otherwise LSB compliant.) Assuming that you've addressed all the issues, you can proceed to the next step. - Use the LSB Build Environment to build the code in a clean, compliant environment.If your code uses libraries that are not provided for under the LSB, you must modify your build process to either install or link statically to those libraries. (Remember that all libraries must be LSB compliant, as well.) - If your code builds successfully within the LSB Build Environment, run the code in the LSB Sample Implementation.

   
- If your target Linux system is LSB compliant, run your code on     that system.\\ 
   
- Package your application.LSB-conforming systems promise to be able to install an LSB-compliant RPM. However, you need not limit yourself to that format, with the caveat that the packaging technology you choose must work on an LSB-compliant system. For example, a compliant shell script with a tarball is an acceptable format. Your own installer is acceptable, too, as long as the installer itself is LSB compliant.

Now, let's build a simple application to elaborate on the process. =====Installing and Running the LSB Build Environment Utilities===== Before using the chroot version of the LSB Build Environment, try the Build Environment utilities, which you can quickly and easily install on virtually any Linux system. You can use the Build Environment utilities lsbappchk and lsbpkgchk to quickly determine why your application and RPM package (the standard LSB format), respectively, aren't compliant with the LSB. ====Download and Install the Build Environment Utilities==== The Build Environment utilities are available as two RPMs, one for lsbappchk and another for lsbpkgchk. Because the test system is Debian Linux, you can either convert the RPMs to DEB format using alien, or download the native .deb packages suitable for Debian's dpkg package manager. For a more complex application, with a GUI, you may want to also download lsb-build-desktop, lsb-build-qt3 and/or lsb-build-qt4.

1 $ sudo apt-get install wget
2 $ wget http://ftp.linuxfoundation.org/pub/lsb/test_suites/released-all/binary/application/lsb-appchk-4.0.0-2.i486.rpm
3 $ wget http://ftp.linuxfoundation.org/pub/lsb/test_suites/released-all/binary/application/lsb-pkgchk-4.0.1-2.i486.rpm

4 $ wget http://ftp.linuxfoundation.org/pub/lsb/base/released-all/binary/lsb-setup-4.0.0-2.noarch.rpm
5 $ wget http://ftp.linuxfoundation.org/pub/lsb/lsbdev/released-all/binary/ia32/lsb-build-base-4.0.0-4.i486.rpm
6 $ wget http://ftp.linuxfoundation.org/pub/lsb/lsbdev/released-all/binary/ia32/lsb-build-c++-4.0.0-2.i486.rpm

7 $ wget http://ftp.linuxfoundation.org/pub/lsb/lsbdev/released-all/binary/ia32/lsb-build-cc-4.0.0-4.i486.rpm
8 $ sudo apt-get install alien
9 $ alien -k *.rpm
10 $ ls -t -1 *.deb
lsb-setup_4.0.0-2_all.deb
lsb-pkgchk_4.0.1-2_i386.deb
lsb-build-cc_4.0.0-4_i386.deb
lsb-build-c++_4.0.0-2_i386.deb
lsb-build-base_4.0.0-4_i386.deb
lsb-appchk_4.0.0-2_i386.deb
11 $ sudo dpkg --install *.deb
12 $ ls /opt/lsb
bin  doc  man
13 $ ls /opt/lsb/bin
lsbappchk  lsbc++  lsbcc  lsbpkgchk

The native .deb packages are at:

http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-appchk_4.0.0-2_i386.deb
http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-pkgchk_4.0.1-2_i386.deb

http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-setup_4.0.0-2_all.deb
http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-build-base_4.0.0-4_i386.deb
http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-build-c++_4.0.0-2_i386.deb
http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/pkgs-common/lsb-build-cc_4.0.0-4_i386.deb

Command 1 installs wget if it isn't already available on the system. Commands 2-7 download the latest versions of the LSB utilities: * lsb-appchk verifies that a supplied binary only uses the dynamically linked symbols defined in the LSB. * lsb-pkgchk verifies that an application package–a bundle used to install the software on an LSB-compliant system–is valid. The lsb-pkgchk tool is intended for RPMs only. However, the LSB does not mandate the use of RPMs to install software. * lsb-setup simply provides the /opt/lsb/* directory structure used by a number of lsb packages * lsb-build-base provides stub libraries and header files. While the stub libraries don't implement the functions defined in the LSB, they do mimic the actual dynamic libraries found on an LSB system. Hence, you can use lsb-build-base to build a compliant application. * lsb-build-c** adds ''C++'' support to the build environment. * **lsb-build-cc** contains lsbcc, a wrapper around the GNU Compiler Collection (GCC) compiler that yields LSB-conforming applications. If your application uses a GNU-style configure script, you can easily modify your script to use lsbcc instead of the default system (typically GCC) CC compiler. In some cases, you can directly replace GCC with lsbcc (for example, in a makefile). Command 8 installs alien, a utility that can convert RPMs to Debian DEB packages (among other features). Command 9 runs alien; command 10 shows the results; and command 11 installs all the software into the /opt/lsb/ directory, as shown in commands 12 and 13. If you use the native .deb packages, steps 8 and 9 would be skipped. If your system supports a package manager such as apt, yum, or zypper, you can also add LSB package repositories and install the SDK and application tests using those tools. The LSB repositories are at: * [[http://ftp.linuxfoundation.org/pub/lsb/repositories/debian/

[lsb-4]
name=LSB 4
baseurl=http://ftp.linuxfoundation.org/pub/lsb/repositories/yum/lsb-4.0/repo-ia32
enabled=1

For zypper, again you create an LSB repo file like /etc/zypp/repos.d/lsb-ia32.repo:

name=lsb-ia32
enabled=1
autorefresh=0
baseurl=http://ftp.linuxfoundation.org/pub/lsb/repositories/yum/lsb-4.0/repo-ia32
type=rpm-md
keeppackages=0

Then the package installation would look something like:

apt-get install lsb-appchk lsb-pkgchk lsb-build-cc lsb-build-c++

or

yum install lsb-appchk lsb-pkgchk lsb-build-cc lsb-build-c++

or

zypper in lsb-appchk lsb-pkgchk lsb-build-cc lsb-build-c++

You'll note we omitted lsb-setup and lsb-build-base. This is because the package manager now resolves the dependencies and pulls these packages in with the others. Building and verifying an RPM is beyond the scope of the tutorial. Instead, let's focus on building a small C application with lsbcc and scanning the resulting binary for invalid symbols with lsb-appchk. ====An Example Program==== Listing 1 shows a small program that echoes its command-line arguments (error-checking code has been omitted intentionally).
Listing 1. A Simple C Program

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

main(argc, argv)
int argc;
char *argv[];
{
  int i = 0;

  for (i = 1; i < argc; i++) {
   fputs(argv[i], stdout);
   putchar(' ');
  }
  
  putchar('\n');
  
  exit(0);
}

Copy and paste the code into a file named echoargs.c, and then build it with the compiler installed on your Debian system:

$ cc -o echoargs echoargs.c 
$ ./echoargs hello there, world!
hello there, world!

The code works as intended, but is it LSB conforming? To make the determination, run the lsbappchk command:

$ /opt/lsb/bin/lsbappchk echoargs
LSB version is not specified, using 4.0 by default.

BIN: echoargs
LSB Application Checker Report
==============================

Binary echoargs:
  FAIL
  Incorrect program interpreter: /lib/ld-linux.so.2
  URL: http://developer.linux-foundation.org/lsbchk?suite=appchk&arch=IA32&testcase=echoargs&tpnum=16&result=FAIL&purpose=Check%20program%20interpreter

Section .interp not checked
Section .note.ABI-tag not checked
section .gnu.hash is not in the LSB
  FAIL
  section .gnu.hash is not in the LSB

Echoargs is clearly not an LSB-conforming application. ====Use the LSB Compiler to Make the Application Conform==== Now, rebuild the same code using the LSB compiler–lsbcc–and run lsbappchk on the binary it produces:

$ /opt/lsb/bin/lsbcc -o lsb-echoargs echoargs.c
$ /opt/lsb/bin/lsbappchk lsb-echoargs
LSB version is not specified, using 4.0 by default.

BIN: lsb-echoargs
LSB Application Checker Report
==============================
...

(there is additional output, but no FAIL messages) Much better! The new binary is conforming. It was built with the LSB stub libraries using the LSB include files (header files) instead of the system header files. But does the application run?

$ ./lsb-echoargs foo bar
$ foo bar

While not yet certified, Ubuntu Hardy is indeed lsb conforming. If running the application gave this type of message:

$ ./lsb-echoargs foo bar
-bash: no such file or directory: ./lsb-echoargs

It would be an indication that the system is not LSB V4.0 conformant, so the binary cannot be executed. The command ./lsb-echoargs produces the somewhat odd message, -bash: ./lsb-echoargs: No such file or directory, which belies the real error–namely, that the system cannot load the binary. (In a moment, you'll use the LSB Sample Implementation to run this binary.) As another example, consider Listing 2. The code snippet uses the open source Perl Compatible Regular Expressions (PCRE) library to add the power of regular expressions to traditional C. As useful as PCRE is, it's not part of the LSB specification. On Ubuntu Hardy, you need to install libpcre3-dev to build this example. On other systems the package name may be different

$ apt-get install libpcre3-dev**\\ **

Listing 2. A Snippet of a PCRE Application

#include <pcre.h>

int main()
{
  pcre *re;
  const char *error;
  int erroffset;

  /* more code here */
  
  re = pcre_compile("^[A-Z]", 0, &error, &erroffset, NULL);

  /* rest of the application */
}

You can build the code with the command cc -o pcre pcre.c -lpcre.. Checking the code with lsbappchk produces additional error messages:

$ cc -o pcre pcre.c -lpcre
$ /opt/lsb/bin/lsbappchk pcre

LSB version is not specified, using 4.0 by default.

BIN: pcre
LSB Application Checker Report
==============================

Binary pcre:
  FAIL
  Incorrect program interpreter: /lib/ld-linux.so.2
...
  FAIL
  DT_NEEDED: libpcre.so.3 is used, but not part of the LSB
...
  FAIL
  Symbol pcre_compile is used, but is not included in LSB 4.0 (Core & C++ & Desktop)

The functions declared by PCRE are not LSB compliant and are flagged. You could avoid this error (assuming that the rest of the PCRE library was LSB compliant) by adding the -static flag when compiling. Interestingly, the same command using lsbcc does not generate errors:

$ /opt/lsb/binlsbcc -o lsb-pcre pcre.c -lpcre
$ /opt/lsb/bin/lsbappchk lsb-pcre
LSB version is not specified, using 4.0 by default.

BIN: lsb-pcre
LSB Application Checker Report
==============================
...

Again, a lot of output, but no FAIL messages. Let's look at the symbols in lsb-pcre:

$ nm lsb-pcre | grep pcre
08051be0 R _pcre_OP_lengths
08058240 R _pcre_default_tables
0804fd40 T _pcre_is_newline
08050020 T _pcre_ord2utf8
08050090 T _pcre_ucp_findprop
08050130 T _pcre_ucp_othercase
08051c50 R _pcre_utf8_table1
08051c68 R _pcre_utf8_table1_size
08051c6c R _pcre_utf8_table2
08051c84 R _pcre_utf8_table3
08051ca0 R _pcre_utf8_table4
08051f80 R _pcre_utt
08051ce0 R _pcre_utt_names
080521f8 R _pcre_utt_size
080501b0 T _pcre_valid_utf8
0804fec0 T _pcre_was_newline
080597c8 B pcre_callout
0804fd00 T pcre_compile
0804f340 T pcre_compile2
080597b8 D pcre_free
080597b4 D pcre_malloc
080597c0 D pcre_stack_free
080597bc D pcre_stack_malloc

Here, lsbcc statically linked the PCRE code into the executable – one solution to avoid library differences between one Linux platform and another. Lsbcc modifies command-line arguments to the GCC compiler to use LSB header files and libraries and to avoid dynamic links to non-compliant LSB libraries. If you use GCC and a number of home-grown or popular tools to build your code, lsbcc is probably preferable over the chroot LSB Build Environment. In contrast, if you use a compiler other than GCC or have dependencies on a specific compiler, compiler options, or library or include file paths, the LSB Build Environment may be superior. The next section demonstrates how to install and use the LSB Sample Implementation to test your application. Both the Build Environment and the Sample Implementation have been redesigned for LSB V4.0. As of this writing the Build Environment is not yet ready for testing. When available, it will be similar to the Sample Implementation, a standalone minimal system. Basically the Sample Implementation with the addition of the SDK. =====Installing the Sample Implementation===== Note: The rest of this tutorial uses the virtual lsb-siX-vm instance of openSUSE 11.1 running in VMWare Workstation. If you previously suspended the VM or quit VMWare Workstation, resume the VM or re-launch VMWare Workstation and start the lsb-siX-vm instance. When the instance is running, you should be logged in as tux automatically. ====Download and Install the chroot LSB Sample Implementation==== This section only applies if you are using a different OS or virtual machine than the lsb-siX-vm. The LSB appliance already has lsbsi-chroot and lsbsi-tools installed. If you are using the lsb-siX-vm, please skip ahead to the section on using the SI. The Sample Implementation is distributed as the lsbsi-choot rpm package, with a supporting lsbsi-tools package which helps integrate the SI as a “application” on the host system. Because of the complexity of the SI, it tends to lag the full LSB release slightly, and at the time of this writing it is still in beta. For what we're doing in this demo, the beta release should be sufficient.

1 $ wget http://ftp.linux-foundation.org/pub/lsb/impl/beta/binary/ia32/lsbsi-chroot-4.0.1-1.i586.rpm
2 $ wget http://ftp.linux-foundation.org/pub/lsb/impl/beta/binary/ia32/lsbsi-tools-4.0.0-1.i586.rpm

3 $ rpm -ivh lsbsi-chroot-4.0.1-1.i586.rpm lsbsi-tools-4.0.0-1.i586.rpm

Commands 1-2 download the pieces of the LSB Sample Implementation. Command 3 installs them on the system. * lsbsi-chroot is the core of the Sample Implementation. It installs in opt/lsb/si/chroot. * lsbsi-tools is a set of scripts and menu entry that facilitate your chroot into the SI system. The scripts provide the proper bind mounts and environment that enable the SI chroot to behave much like a “real” system. An lsbsi group is added to the system at package install. By adding users to this group, non-root users will also be able to use the SI. After you install the Sample Implementation, you can use chroot to get to it. You can either run the command /opt/lsb/bin/si-chroot, the command /opt/lsb/si/tools/si, the command /opt/lsb/si/tools/si-gui, or select the menu entry Development|LSB Sample Implementation. To exit the chroot environment, press Ctrl+D at the new shell prompt. =====Executing Code in the Sample Implementation===== Build the simple code of Listing 1 within openSUSE 11.1 and run it within the Sample Implementation. ====Install the SDK==== To make things convenient for development, the lsb-siX-vm openSUSE 11.1 environment provides gcc and LSB SDK. If you are using another system, you would need the install a compiler and the LSB build tools as outlined earlier. Within your openSUSE 11.1 VM, you now have two environments: the openSUSE environment, with the SDK, and the Sample Implementation. There should be a terminal window open already within the Sample Implementation and if you open another tab or window, you should be the “tux” user in that home directory. For convenience, tux's home directory is bind mounted under /root/myfiles within the SI: tux user:

$ pwd
$ /home/tux
$ touch foo

root user in the SI:

$ cd /root/myfiles
$ ls -1
Desktop
Documents
foo

So, to build Listing 1 with the SDK and test it in the chroot Sample Implementation, you download the code to the openSUSE 11.1 environment, and then build it per the following sequence (the prefixes in the command-line prompt were added for clarity): (tux) $ wget http://ftp.linuxfoundation.org/pub/lsb/demos/source-code/echoargs.c (tux) $ /opt/lsb/bin/lsbcc -o echoargs echoargs.c (si) $ cd /root/myfiles (si) $ ./echoargs hello there hello there By the way, because openSUSE 11.1 is nearly compliant with LSB V4.0.0, the binary you created with lsbcc runs fine in the openSUSE:

(tux) $ ./echoargs this is cool
this is cool**\\ **

=====Summary===== While the example code shown in this tutorial was simple, the same techniques used to build and test a few lines of code apply equally well to a few thousand lines of code. Use the lsb-appchk tool to find questionable symbols. Try building your code with the LSB Build Environment utilities and within the stand-alone LSB Build Environment chroot environment. If you don't have an LSB V4.0.0-compliant version of Linux, use the LSB Sample Implementation to test the portability of your application. Leverage a tool such as VMWare Workstation to virtually (both metaphorically and practically) multiply your computing resources and run your targeted flavors of Linux. With a little work, you can shape your application to be LSB compliant, and then apply to have your application certified. Certified distributions and certified applications allow users to invest in Linux comfortably. The LSB provides uniformity, which–perhaps paradoxically–promotes choice. And after all, choice is what Linux is all about. =====Attribution===== This article originally appeared on IBM developerWorks. It has been revised to current technology practices. Thanks to Ted T'So and Jeff Licquia for updating it. The current version has been updated to reflect changes with LSB V4.0.