The Linux Foundation

 

Become an Individual Member

Book/HowToDevel

From The Linux Foundation


Contents

Using the LSB Development Environment

What it is, and what it is not

The LSB development environments are designed to help developers build applications which conform to the LSB specification. They primarily do this by providing easy ways to:

  • compile against header files that contain definitions required by the LSB specification.
  • dynamically link against shared libraries that contain only interfaces required by the LSB specification.

The LSB development environment is not intended to be an Integrated Development Environment (IDE) in itself, but rather an enhancement to existing IDEs, to allow them to build binaries that are LSB compliant. It is important to note that although the LSB development environment helps programmers to build LSB compliant applications, it does not necessarily have to be used to be able to do so.

Getting the LSB Development Environment

The packages for the development environment can be downloaded from the LSB FTP site.
See the Downloading the LSB Development Environment section for details.

Using the LSB Development Environment

The main part of the LSB Development Environment is LSB SDK, that consists of sevaral packages described in details in the Downloading the LSB Development Environment section. The main ones are lsb-build-base and lsb-build-cc, that provide lsbcc compiler wrapper and header files and stubs for the core libraries. Additional lsb-build-* packages provide header files, stubs and different auxiliary utilities for C++ and desktop libraries included in LSB.

Another important entity is LSB Sample Implementation that can be used to execute and test the application in the LSB compliant environment.

LSB Stub Shared Libraries

The LSB development environment provides shared libraries that can be dynamically linked against an application. The functions within these libraries are stubs only (for example, contain no executable code) and are not intended to be used, except for linking against when building a dynamically linked binary.

The environment in which software is developed is often different than that in which the application is designed to be run on. For example, developers will often have a more recent version of the C library than what the LSB requires. Header files used during compilation can contain definitions that affect the runtime behavior of an application. For example, the content and size of structs can change as libraries develop, so it is important that the correct representation is used for the given version of the library.

In order to solve this problem, some libraries such as the C library use symbol versioning. Each interface within the library has a version associated with it, allowing for multiple versions of the same interface (such as open) to exist in the same shared library. The inclusion of multiple versions of a function allows older applications to continue to use the old version, while new applications use the new version.

When a binary is created, it inspects the shared library it is linking against and records the versions of those interfaces it requires. At runtime, the binary will will look for the the interfaces with the recorded version number, and fail if they do not exist. Thus, it is necessary to link against shared libraries that contain the versions of the interfaces guaranteed to exist on an LSB compliant runtime.

Where libraries supported by the LSB use symbol versioning, the specification specifies specific versions of the interfaces. The LSB stub libraries only contain the versions of the interfaces allowed by the LSB specification, and so if they are used it makes it impossible to use the wrong version when building a binary.

There are often interfaces contained in shared libraries that must not be used by an LSB compliant binary. These interfaces are often private functions, or interfaces not supported by the LSB. Since the stub libraries only contain interfaces required by the specification, an error will occur during the link stage if an application uses an unsupported interface.

LSB Header Files

The definitions contained within a header file associated with a library may change over time as the ABI of that library evolves. For example, a function in one version of the library may take one parameter, while in the next version it make take two parameters.

The LSB specification defines an ABI for each supported library, and the header files used to compile against must match exactly. In order to avoid the problem of finding the exact version of the software that contains the correct definitions, header files are supplied with the LSB build environment that are matched with the specification.

Using the Development Tools

The main tools provided by the LSB SDK are compiler wrappers fo C and C++, called lsbcc and lsbc++ correspondingly, that compile and link against compliant headers and libraries. Using these tools is an easy way to build an LSB compliant application.

Additional tools include:

  • makelsbpkg - an utility to create LSB compliant RPM from a source directory of files or a cpio archive;
  • qmake with accompanying utilities for Qt3 and Qt4;
  • lsbrun - an utility for running LSB-compliant applications on Linux systems that do not provide a LSB runtime.

lsbcc and lsbc++

The lsbcc and lsbc++ are wrapper programs for C and C++ system compilers (e.g. gcc and g++) that are invoked in place of the compiler. The wrapper program modifies the arguments passed to the actual compiler to ensure that your application uses the LSB specified versions of header files and libraries are used instead of those installed on the system. However, the full functionality of the native system is available to build, develop, and debug the application. To use lsbcc, you can use either of the following commands:

Example 1. lsbcc

# CC=lsbcc ./configure
# CC=lsbc++ ./configure (for C++)

or

# CC=lsbcc make
# CC=lsbc++ make (for C++)

Further information about using lsbcc and lsbc++ can be found in the man page included with the lsb-build-cc package.

Simple Example

In this example we have a source file hello_world.c.

Example 2. hello_world.c Source File

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

int main(int argc, char *argv[])
{
printf("Hello World\n");
exit(0);
}

Instead of calling gcc directly, we instead use lsbcc.

Example 3. lsbcc

$ lsbcc -Wall -o hello_world hello_world.c
$ ./hello_world
Hello World
$

Hint

Suppose myfunction were an ABI provided by libc and it had different versions. If myapplication uses the myfunction ABI, we could compare the application and the library images to see which ABI is actually used.

Example 4. myapplication

   $ /usr/bin/objdump -T myapplication | grep myfunction
08048330 DF *UND* 00000032 GLIBC_2.0 myfunction

$ /usr/bin/objdump -T /lib/i686/libc.so.6 | egrep myfunction
000bb160 g DF .text 00000032 GLIBC_2.0 myfunction
000bb160 w DF .text 00000032 GLIBC_2.1 myfunction

The correct ABI for myfunction used by myapplication should be GLIBC_2.0 so that it will return a double. The library and the operating system are allowed to evolve, but the LSB refreshes less frequently to provide a stable runtime environment for applications.

Changing Dynamic Linker

LSB compatible applications are supposed to use LSB dynamic linker instead of the default system linker. For example on x86 machines /lib/ld-lsb.so.1 should be used instead of /lib/ld-linux.so.2. By default, when built with lsbcc or lsbc++, the desurable dynamic linker is set using appropriate gcc option.

However, one may claim that at least for some applications it would be nice to be able to use the same executable on both LSB compliant platforms and on platforms that don't provide LSB dynamic linker, since even in the latter case the platform may provide all functionality required for the particular program. LSB SDK provides two ways to implement this possibility:

  • Do not set dynamic linker to the LSB one. When using lsbcc, this can be achieved through the --lsb-use-default-linker option or LSBCC_USE_DEFAULT_LINKER environment variable. However, such applications are not considered as LSB-compliant at the moment.
  • Use 'best effort' policy - allow application to choose the dynamic linker at runtime. If LSB linker is available, then it will be used, otherwise the default system linker will be invoced. To add this possibility to the application compiled with lsbcc, use --lsb-besteffort option. Alternatively, you may set the LSBCC_BESTEFFORT environment variable.
  • Set dynamic linker to the LSB one and use the lsbrun utility to execute the program on platforms that don't have LSB dynamic linker.

makelsbpkg

LSB currently suggests to use RPM format to package the applications. However, as time goes by, RPM itself evolves and modern systems may create RPM files that cannot be installed on older systems. In order to create RPM files that match LSB requirements, one may use the makelsbpkg utility. A simple example of its usage is like the following:

Example 5. makelsbpkg

   $ makelsbpkg mypackage pkgroot/mypackage

This command will takes all the files in pkgroot/mypackage and package them in mypackage-1.0.0-1.%arch.rpm. (%arch is detected from the host system).

Detailed information can be found in the man page included with the lsb-makelsbpkg package.


Shared libraries

When an application uses a library that is not part of the LSB specification, it can be built in one of two ways. Either the binary is statically linked against that library, or if the library is LSB compliant it may be dynamically linked with the binary. If it is dynamically linked, the shared library must be supplied with the rest of the application.

The requirements for a shared library to be considered to be LSB compliant are essentially the same as those required for a directly executable program. That is, it must only use dynamic interfaces supported by the specification, or alternatively supplied in an another LSB compliant shared library that is packaged with the rest of the application.

Much like an ordinary binary, a shared library that is to be supplied with an LSB compliant application should be built against the LSB headers and stub libraries. Rather than building a shared library with ld:

Example 6. Building With ld

	# ld -r -shared -o libtest.so obj1.o obj2.o

This may lead to the use of symbol versions that are not part of the LSB specification. If you are using the lsbcc technique of building an application, then shared libraries must also be built using lsbcc.

Example 7. Build With lsbcc

	# lsbcc -shared -o libtest.so obj1.o obj2.o

When it comes to linking an application, if you use lsbcc, by default only the LSB specified libraries will be linked dynamically, even if both static and shared libraries are available in the search path. This behaviour can be modified by setting the environment variable LSBCC_SHAREDLIBS. This is a colon separated list of library names and specifies which extra libraries should be dynamically linked.

Case Study: rsync

The rsync application is one of the programs in the LSB Application Battery. We use this program as an example of the types of problems that developers may encounter, and how to work around them when attempting to build an LSB compliant binary.

We use the lsbcc build tool with rsync version 3.0.0. The source for rsync can be downloaded from the rsync Web site.

Building an rsync binary with lsbcc

First we unpack the sources, and run configure. We make sure that configure uses lsbcc as the compiler by setting the CC environment variable, and not cc, as configure might do otherwise by default.

Example 8. Run Configure

$ tar xfz rsync-3.0.0.tar.gz
$ cd rsync-3.0.0/
$ CC=lsbcc ./configure
configure: Configuring rsync 3.0.0
checking build system type... i686-pc-linux-gnu
checking host system type... i686-pc-linux-gnu
checking target system type... i686-pc-linux-gnu
checking for gcc... lsbcc
checking for C compiler default output... a.out
checking whether the C compiler works... yes
...
checking for mallinfo... no
checking for getgroups... yes
checking for setgroups... yes
...
checking whether to support ACLs... running tests:
checking for acl_get_file in -lacl... no
checking for ACL support... no
checking ACL test results... No ACL support found
checking whether to support extended attributes... no
...
config.status: creating popt/dummy
config.status: creating shconfig
config.status: creating config.h

   rsync 3.0.0 configuration successful

From the edited configure output shown above, we can see that the configure script has correctly detected that mallinfo and ACL-relative elements are not part of the LSB, and so are not used.

Next we attempt to compile the rsync binary. Since we told the configure script to use lsbcc as the compiler, we do not need to set the CC environment variable when invoking make.

Example 9. Compile the rsync Binary

$ make
...
lsbcc -std=gnu99 -g -O2 -DHAVE_CONFIG_H -Wall -W -I./popt -Wno-unused-parameter -o rsync 
 flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o main.o 
 checksum.o match.o syscall.o log.o backup.o options.o io.o compat.o hlink.o token.o 
 uidlist.o socket.o hashtable.o fileio.o batch.o clientname.o chmod.o acls.o xattrs.o 
 progress.o pipe.o params.o loadparm.o clientserver.o access.o connection.o authenticate.o 
 lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o lib/md5.o lib/permstring.o lib/
 pool_alloc.o lib/sysacls.o lib/sysxattrs.o  zlib/deflate.o zlib/inffast.o zlib/inflate.o 
 zlib/inftrees.o zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o 
 popt/findme.o  popt/popt.o  popt/poptconfig.o popt/popthelp.o popt/poptparse.o
authenticate.o(.text+0x83d): In function `auth_client':
/home/cyeoh/src/rsync-3.0.0/authenticate.c:317: undefined reference to `getpass'
collect2: ld returned 1 exit status
make: *** [rsync] Error 1

A link error has occurred - the linker was unable to find the getpass function. The getpass is not in the LSB specification (the man page for it on Linux has it marked as obsolete) and so a stub for it is not contained in the LSB C stub library. The info page for glibc suggests an alternative method and so we patch the rsync source code with suggested code excerpt. After we have done this, the make succeeds and produces an rsync binary.

Checking the binary

The lsbappchk can be used to static check a binary for LSB compliance. The static application checker examines an application to check that it is using only the libraries, interfaces, and runtime loader specified by the LSB, as well as verify that its program image has some features required by the ELF format.

Example 10. Application Checker

$ lsbappchk rsync
 LSB version is not specified, using 4.0 by default.               
 BIN: rsync
$
If any problems are found they will output to standard error and recorded in a journal file, named, journal.<binary_name>.

Improved analysis of the application can be performed using the Linux Application Checker.

The lsbdynchk can be used at runtime to check a binary for compliance. The dynamic application checker examines the application parameters at runtime according to the specification.

Further testing such as running the binary in the LSB Sample Implementation and running any functional verification tests for the application should be done at this stage.

Targeting another LSB version

Ok, we can be sure that the rsync executeble uses only symbols included in the latest LSB version (4.0 at the moment). But maybe rsync is also compatible with earlier LSB versions? Let's try to build it for LSB 3.1.

Starting with LSB 4.0, the same LSB SDK can be used to create applications compatible with any given LSB version greater than or equal to 3.0. By default, the latest LSB version is used, but this behaviour can be changed either by setting LSBCC_LSBVERSION environment variable or by using '--lsb-target-version' of the lsbcc.

In our case, it is convinient to use environment variable:

Example 11. Build for LSB 3.1

$ LSBCC_LSBVERSION=3.1 CC=lsbcc ./configure
...
$ LSBCC_LSBVERSION=3.1 make
...

We'll find out that there are no problems here, i.e. that rsync is compatible with LSB 3.1 without any additional patches.

FHS Issues

The lsbappchk tool is not able to verify that an application is completely LSB compliant. Some aspects such as File Hierarchy Standard compliance currently need to be checked manually. For example by default rsync uses a configuration file rsyncd.conf that resides in /etc. But the FHS says configuration files should reside in /etc/opt/package. This can be achieved by applying the following patch:

Example 12. Patch

--- rsync-3.0.0/rsync.h.lsbcc	2008-03-01 15:12:04.000000000 -0500
+++ rsync-3.0.0/rsync.h	2008-03-18 10:35:35.000000000 -0400
@@ -29,7 +29,7 @@
 /* RSYNCD_SYSCONF is now set in config.h */
 #define RSYNCD_USERCONF "rsyncd.conf"
-#define DEFAULT_LOCK_FILE "/var/run/rsyncd.lock" +#define DEFAULT_LOCK_FILE "/var/run/lsb-rsyncd.lock" #define URL_PREFIX "rsync://"
#define SYMLINK_PREFIX "/rsyncd-munged/"
Similarly rsync can be configured to install into /opt/lsb-rsync instead of /usr/local by passing configure the --prefix=/opt/lsb-rsync parameter.

Further examples

Further examples of building LSB compliant versions of applications can be found as part of the LSB Application Battery described in the Resolution of Coding Problems section of the chapter called Using the Application Battery.

Building the LSB Development Environment

Most of the source code for the LSB SDK packages is auto generated from the LSB Specification database. This has the benefit that the header files and stub libraries are synchronized with the specification. Normally it should not be necessary for people to build the source code from the database, though all of the scripts and the contents of the database are publically available in the LSB Bazaar repository.

Image:lsbdev.png

Figure 1. LSB Development Environment.

Source tarballs and source rpm packages for the LSB SDK are available from the LSB FTP Archive. The tarballs contains a README that describes how to build the package and the source rpm packages can be built in the usual manner with the rpm tool. For example:

Example 13. Building rpm Packages

# rpm --rebuild lsb-build-base-4.0.0-2.src.rpm

Expanding the LSB Development Environment

Using compilers other than gcc

Nearly all of the testing and use of the LSB development environment has been with GCC as the compiler. It is possible to build LSB compliant applications using other compilers.

Using the header files and stub libraries of the development environment is not strictly necessary, though it almost certainly will be easier to do so. The changes in building required when using another compiler can be summarised as:

  • Use LSB compliant header files.
  • Use LSB compliant libraries. Using the development environment stub libraries has the advantage that link errors will occur if you attempt to use non LSB interfaces. Furthermore, in some cases decision on whether to use certain interfaces or not is made by the compiler on the basis of their presence in libraries used during compilation.
  • Ensure that the binary uses the LSB dynamic linker instead of the standard Linux linker for that architecture. For example on x86 machines /lib/ld-lsb.so.1 should be used instead of /lib/ld-linux.so.2.

The way to achieve the third will be compiler dependent, but as an example, this is done with gcc by editing the specs configuration file.

Integration with an IDE

In general, integration of LSB SDK with any IDE is fairly straight forward as the only change required is to call lsbcc instead of the normal compiler. An additional help is provided for those developers who use Eclipse IDE by means of the special Eclipse Plugin.

Using non LSB interfaces

Sometimes developers are not able to build a completely LSB compliant application as the core functionality of their program depends on a feature not included as part of the LSB specification. However, for compatability reasons, they still want to be as LSB compliant as possible.

An example of this would be a dependence on a C library interface or a system call that is not in the LSB specification. In this case it is not possible to simply supply a shared library with the application or to statically link the requirement to make the binary LSB compliant. By modifying the LSB development environment it is still possible to use it to build the binary and get the associated benefits. In the above case the simplest approach would be to retrieve the source for the stub libraries, manually add the required interfaces and build a new version of the stub libraries. Similarly prototypes can be added to the LSB header files.

Downloading the LSB Development Environment

To obtain the LSB Development Environment go to the LSB download Web page. The packages that form the LSB SDK are listed in the Table 1.

Table 1. Development Environment Download Page

Specification Version Package Version Architecture
4.0 lsb-build-base 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-build-c++ 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-build-cc 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-build-desktop 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-build-qt3 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-build-qt4 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-makelsbpkg 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64, src
4.0 lsb-runner 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-setup 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64
4.0 lsb-xdg-utils 4.0.0-1 i486, ia64, ppc, ppc64, s390, s390x, x86_64

Sources of all packages are available in the LSB Bazaar repository.

Note

Note

All packages listed above can be downloaded as a single bundle from the LSB download Web page. The bundle is provided with the install.sh script that can be used to install all packages on any LSB compliant system.

Note

Note

The version numbers of the lsb-build packages refer to the version of the specification that the stub libraries and header files have been generated for. Note that since LSB 4.0 these packages are not bound to the particular LSB version and can be used to create applications compatible with any given LSB version greater than or equal to 3.0.

lsb-build-base
The LSB Build environment base package provides core stub libraries and appropriate header files. These can be used to build LSB compliant applications.
lsb-build-c++
This package provides interim C++ building support for the lsb-build packages. It provides a set of header files configured from GNU C++ 4.1.0, as well as libstdc++ stub library.
lsb-build-cc
This package provides lsbcc compiler wrapper, which is one of the approaches that can be used to build LSB conforming applications.
lsb-build-desktop
This package provides LSB desktop building support for the lsb-build packages. In particular, it provides stub libraries for such desktop libraries as Qt and GTK and header files for those libraries that are written on the C programming language.
lsb-build-qt3
This package provides LSB Qt3 building support for the lsb-build packages. It adds LSB Qt3 headers and qmake command with accompanying utilities.
lsb-build-qt4
This package provides LSB Qt4 building support for the lsb-build packages. It adds LSB Qt4 headers and qmake command with accompanying utilities.
lsb-makelsbpkg
This is a perl script to build an LSB compliant RPM from a source directory of files or a cpio archive.
lsb-runner
This package provides lsbrun, a utility for running LSB-compliant applications on Linux systems that do not provide a LSB runtime (at least as well as such applications can run).
lsb-setup
This package is a meta-package, meaning that its purpose is to contain dependencies for installing the LSB SDK.
lsb-xdg-utils
This package provides LSB xdg-utils.

[Article] [Discussion] [View source] [History]