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:

You may also find it useful to download and read the LSB V4.0.0 specification appropriate for your target hardware platform. Hardware-specific LSB specifications are available for seven popular architectures: the IA32, IA64, PPC32, PPC64, S390, S390X, and AMD64 processors.

If you want to certify your application, please visit the Linux Foundation's LSB Certification Program.

To run the examples in this tutorial, you must have a computer running either the Linux or Windows XP operating system. The qemu application or a VMWare Workstation running on either of those platforms provides a Linux environment for you to do the rest of your work.

If your application depends on software libraries other than those ratified as part of the LSB specification for your processor, you must install those libraries on the virtual system, as well. To avoid confusion, it's ideal to install application-specific libraries separately from the standard libraries.

The Need for a Standard

According to the DistroWatch Web site, at least 25 significant Linux distributions currently exist. If you include other variations -- some optimized for size (such as Damn Small Linux), some for convenience (such as Knoppix), some tailored to a specific audience (such as Fedora Core), and still others customized for a specific country (such as Red Flag Linux)--that rather staggering number of choices easily doubles or triples. Linux is the only modern operating system with such numerous variations.

On one hand, the do-it-yourself culture of Linux encourages diversity and specialization. On the other hand, such proliferation can be overwhelming, especially if you're an independent software vendor (ISV) faced with developing, selling, and supporting a Linux application. If the "UNIX® Wars" of the 1980s splintered ISVs' chances of success, the large number of versions of Linux seems to promise nothing less than wholesale obliteration of the market for rich Linux applications. Imagine the expense of building and supporting a complex application on more than a handful of Linux variants.

LSB Terminology

When discussing the LSB, you'll frequently hear (and read) the terms conformance, compliance, and certification.

In this tutorial, you learn how to create compliant applications. You cannot self-certify your application, although you can run many tests that greatly increase the likelihood of certification.

Promoting Interoperability

In an attempt both to encourage diversification and provide consistency, the Free Standards Group (now The Linux Foundation) created the Linux Standard Base, an "open source project to develop and promote a set of standards [to] increase compatibility among Linux distributions and enable software applications to run on any compliant system" (according to the LSB Web site).

Specifically, the LSB defines a consistent Linux platform. A Linux distribution is LSB compliant if it implements (at least) the LSB platform. (Nothing precludes a version of Linux from providing additional features.) A Linux application is LSB compliant if it consumes only the services that the LSB platform provides. If the application requires additional libraries, it provides those, either during installation or through static linking. (Of course, the libraries must be both self-sufficient and LSB compliant as well.) The sidebar "LSB terminology" explains what other terminology means.

The figure below shows the many areas for which the LSB defines (or will eventually define) standards. The areas are libraries, the basis of all Linux applications; the execution environment, including mandates for where certain critical system files reside and how the system provides for localization services; system initialization; common commands and utilities to be found across all LSB-compliant systems; and user and group management.

Figure 1. The components of the LSB
Figure 1. The Components of the LSB

Application developers are probably most concerned with the blue and orange boxes.

In blue, the LSB stipulates a set of core libraries and additional modules that an LSB-compliant application may use. The core libraries include libc, libm, libpthread, libpam, libcrypt, libz, libncurses, librt, and libgcc_s. Modules include X Window System Version 11 graphics (libX11, libXt, libXext, libSM, libICE, and libGL) and the C++ standard library, libstdc++.

In orange--and not part of the LSB specification--is a set of valuable companion tools to validate that applications, packages, (and soon, static libraries) are LSB compliant.

Binary Compatibility

The LSB specification is a binary compatibility standard. An application binary (compiled, executable code) that is LSB compliant can run unchanged on any LSB-compliant Linux distribution that is built for the same processor architecture as the application.

Binary compatibility is remarkably different from source compatibility. An application that is source compatible requires the software to be recompiled in situ, with the local system's compilers and libraries--two significant founts of variability and unpredictability. Source compatibility doesn't guarantee that the executable will run, let alone run as expected.

The Benefits of Consistency

Think of the LSB as a kind of binding agreement between a distribution and an application. The distribution "agrees" to provide at least the specification's libraries and interfaces, and the application "agrees" to use only those libraries and interfaces, providing any other software that's needed. To ensure that both parties adhere to the agreement, the LSB provides tools, guidelines, and validation services to certify Linux distributions and applications as LSB compliant.

Adherence to the LSB benefits distribution vendors, ISVs, and users alike.

For the distribution vendor:

For the ISV:

For the customer or user:

Given all the dynamics listed above, distribution vendors, ISVs, and users reap rewards from each unique investment in Linux. In turn, Linux benefits as well.

The LSB Build Environment and Sample Implementation

The LSB is a "contract" between an application and a distribution to adhere to the LSB specification. Ignoring the complications of making a Linux distribution compliant, how can a Linux application developer--you--ensure compliance?

If you're a developer, you likely know your code very well and can work diligently to meet the obligations of LSB compliance. However, it may not always be obvious that your code depends on a non-standard (non-LSB) component, especially as a typical Linux distribution has thousands of components strewn about the system.

For example, perhaps your code depends on a non-compliant string library found only on your favorite distribution. Or perhaps the string library used was added locally and recently by your system administrator. As an another example, perhaps your code depends on a specific version of a library. Version W of the library is LSB compliant, but version Y--the version you depend on--is not part of the LSB specification.

Tools to Help You Migrate

To help find and remove such dependencies--the crux of making your code LSB compliant--the LSB provides two significant tools: the Build Environment and the Sample Implementation.

The Build Environment helps you identify source code that depends on non-LSB libraries and application binary interfaces. The Build Environment consists of header files, stub libraries, and a compiler wrapper that simulate a software build environment on a compliant Linux system. You can install the Build Environment on any Linux system--even one that is not compliant.

The Build Environment is a set of utilities that run within your local operating system. The utilities simulate a build within an LSB environment.

The Sample Implementation helps you validate that your application executes successfully in a compliant runtime environment. You can think of the Sample Implementation as a mini-Linux (yes, you can boot from it, if you want to)--an environment that proxies for an LSB-compliant distribution.

Of course, you could use an LSB-compliant distribution as your test environment, but the Sample Implementation has a few advantages: It only includes what's defined in the LSB, and several versions of the Sample Implementation exist--one each for version of the LSB specification. Hence, if you want to verify that your application is LSB V3.0 and LSB V3.2 compliant, you can install the respective Sample Implementations on a single test system rather than require two Linux systems. Certainly, the Sample Implementation is the preferred method to validate your application against a newly ratified LSB specification before real-world, compliant systems are available.

An individual Build Environment and Sample Implementation set is provided for each version of the LSB standard. For this tutorial, you'll use LSB V4.0.0 as the target platform. (Version 4.0.0 was the most recent LSB specification at the time this tutorial was written. Versions 3.2.0 and 3.1.0 are the previous versions of the LSB. You'll likely find that many popular Linux distributions are certified with one of the earlier instances of the LSB.)

Since LSB V4.0.0, the Build Environment is not bound to a particular specification version and can be used to create applications compatible with any given LSB version greater or equalt to 3.0.0. By default, the latest LSB version is used as a target. To change target version, one should use either the LSBCC_LSBVERSION environment variable or the '--lsb-target-version' option of the compiler wrapper.

The Benefits of Porting Using Virtual Machines

To run the LSB V4.0.0 Sample Implementation, you need an operating system capable of running the Sample Implementation in a chroot environment. The community distribution Fedora 9 (aka FC9) is one flavor of Linux that can run the V4.0.0 Sample Implementation, which we will use for the purpose of this tutorial.

But what if you don't have FC9 installed or you want to run your application on numerous instances of the LSB, or on a handful of Linux distributions? You could assemble a (somewhat large) collection of hardware or multi-boot among all your desired variations, but a far easier and less-expensive solution is to run each Linux distribution in its own emulator or virtual machine.

In the following examples, we will be using the qemu emulator to boot from a Fedora Core 9 disk image.

Install qemu

Install qemu on Debian or Ubuntu, and run FC9 to run the LSB V4.0.0 Build Environment and Sample Implementation.

Download a qemu Image

You can download a FC9 disk image from the Linux Foundation web site. As this image contains an entire operating system, it's quite large (1400MB).

Installing qemu

If you are running the Ubuntu Intrepid system, installing qemu merely requires installing its package with the following command in a terminal window.

sudo apt-get install qemu

You can also use the Synaptics package manager if you prefer a graphical interface.

Running qemu

To start qemu, run the following command in a terminal window, in the same directory where you saved the FC9 disk image. (In each of the following command lines, a preceding dollar sign ($) means to run the command as a normal user, and a preceding hash mark (#) means to run the command as root.

$ qemu fedora-9-i386.qcow2 -redir tcp:2222::22 &

The qemu application traps all mouse and keyboard input unless you press Ctrl+Alt. To set the focus back to the virtualized environment, click in the qemu window.

Get root on qemu by logging in with single user mode, then reboot. You will need to answer a few questions, such as the name of the user account you want to create.

Congratulations! You now have Fedora Core 9 running on its own disk image, entirely separate from your own Linux installation. You can log into the emulator from your "real" computer's console with the following command.

$ ssh -p 2222 localhost

Logging into the emulator with ssh will enable you to copy and paste example code into the emulator, something highly desirable for the sake of this tutorial.

Porting Your Code to the LSB

You can now 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:

  1. 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, an emulator or virtual machine.

  2. 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 use this tool to scan your static archives for suitability for use in an LSB-compliant application.

  3. 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.

  4. 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.)

  5. If your code builds successfully within the LSB Build Environment, run the code in the LSB Sample Implementation.
     
  6. If your target Linux system is LSB-compliant, run your code on that system.
     
  7. 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 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 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 in the standard LSB format, respectively, aren't compliant with the LSB.

Download and Install the Build Environment Utilities

Log into qemu.

# nano /etc/yum.repos.d/lsb.repo

Paste the following code into the nano screen.

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

Type Ctrl-X and save the file. Now you can install packages from the LSB repositories into FC9. The following line will do just that, as well as install GCC, the C compiler, which is not present on the disk image, and a library we'll use later.

# yum install lsb-task-sdk lsb-appchk gcc pcre-devel

An Example Program

Now as normal user, create an empty C source code file called echoargs.c.

$ nano echoargs.c

Copy and paste the following source code into the nano editor screen. When compiled, it will become a small program that echoes its command-line arguments (error-checking code has been omitted intentionally).

#include <stdlib.h>
#include <stdio.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);
} 

Compile the program with the local C compiler, which happens to be GCC.

$ 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

Here is the relevant portion of the output of lsbappchk.

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

Binary echoargs:
  FAIL          
  Incorrect program interpreter: /lib/ld-linux.so.2
...
section .gnu.hash is not in the LSB                                          
  FAIL                                                                       
  section .gnu.hash is not in the LSB
...
Dynamic Tag 0x6ffffef5 unknown    
  FAIL                            
  Dynamic Tag 0x6ffffef5 unknown  

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

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

Binary lsb-echoargs:
...
  No failures found.

No LSB compliance issues were found.

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 hey there
hey there

As another example, consider the listing below. This 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.

#include 

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

  re = pcre_compile("^[A-Z]", 0, &error, &erroffset, NULL);
}

Create an empty C source code file called pcre.c as you did above with echoargs.c, and then paste in the listing above. Build it and check it with lsbappchk as follows.

$ cc -o pcre pcre.c -l pcre

$ /opt/lsb/bin/lsbappchk pcre

This time you should receive some additional error messages.

  FAIL
  DT_NEEDED: libpcre.so.0 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 flagged because they're not LSB-compliant. You can avoid these errors (assuming that the rest of the PCRE library is LSB-compliant) by adding the -static flag.

Interestingly, the same program compiled with lsbcc does not generate errors.

$ /opt/lsb/bin/lsbcc -o lsb-pcre pcre.c -l pcre

$ /opt/lsb/bin/lsbappchk lsb-pcre

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 homegrown or popular tools to build your code, lsbcc is probably preferable to 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 is superior. The next section demonstrates how to install and use the LSB Build Environment.

Installing the Build Environment and Sample Implementation

In order to run the LSB Build Environment, you will need to install the Sample Implementation first.

Download and Install the chroot LSB Sample Implementation

First, download the lsbsi-chroot and lsbsi-tools binaries from the LSB SI Tools Release page. You will also need a special package to force installation of dependencies under Fedora.

Next, install the packages you downloaded.

# yum localinstall --nogpgcheck redhat-lsb-4.0-1.fc11.i386.rpm Lsbsi-chroot-4.0.0-1.i586.rpm Lsbsi-tools-4.0.0-1.i586.rpm

Building and Executing Code in the Build Environment and the Sample Implementation

Build the simple code of Listing 1 within the Build Environment and run it within the Sample Implementation.

Copy files into the Build Environment

Within your FC9 emulation, you now have three environments: the FC9 environment, the Build Environment, and the Sample Implementation. For convenience and clarity, create three working directories and set three environment variables to make copying files between them a snap:

# FC9=/tmp/work

# BE=/opt/lsb/tmp/work

# SI=/opt/lsb/si/chroot/tmp/work

# mkdir -p $FC9 $BE $SI

The $FC9 directory can be your regular Fedora Core 9 working directory. The $BE directory is the directory for source code that you want to build using the Build Environment. The $SI directory is the drop for binaries built in the Build Environment that you want to run in the Sample Implementation. You can also copy the LSB-compliant binaries you created with the LSB Build Environment utilities to the $SI directory to determine whether they run in LSB V4.0.0. (Everything should work perfectly.)

So, to build Listing 1 in the chroot Build Environment and test it in the chroot Sample Implementation, you download the code to the FC9 environment, and then run the following sequence.

TK: Somewhat unclear on how to run a chroot Build Environment, so omitting those for now.--RWHE

By the way, because FC9 is LSB-compliant, the binary you created in the Build Environment runs fine in FC9:

# cp lsb-* $SI

# /opt/lsb/bin/si-chroot

# cd /tmp/work

# ./lsb-echoargs hello there
hello there

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 qemu, kvm, or 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 Ts'o, Jeff Licquia, and Ron Hale-Evans for updating it.