TipsAndTricks/Packaging Prebuilt Libraries

From Yocto Project
Jump to navigationJump to search

Some library vendors do not release source code for their software but do release pre-built binaries. When shared libraries are built, they should be versioned (see this article for some background), but sometimes this is not done. This article shows how to deal with both versioned and unversioned libraries.

Versioned Libraries

In this example we work with libraries for the FT4222 USB I/O chip. Libraries are built for x86 32 and 64bit architectures and packaged in zip file as follows.

├── build-i386
│   └── libft4222.so.1.2.1.35
├── build-x86_64
│   └── libft4222.so.1.2.1.35
├── ftd2xx.h
├── libft4222.h
└── WinTypes.h

The key steps are as follows

  • The vendor will have licence so add a licence flag
  • Vendor provides a tarball containing libraries so set SRC_URI appropriately.
  • Set COMPATIBLE_MACHINE so that recipe cannot be be used with an unsupported architectures. In this example we support Minnowboard Max, genericx86 (both 32 and 64bit), Intel Edison and qemux86.
  • We installing, use the MACHINE override to set source directory within tarball appropriately.
  • As vendor provides versioned libraries, we can use so_oeinstall to install shared library and creates symbolic links. If vendor does not do this we need to follow the non-versioned library guidelines below
  • As the vendor likely used the different LDFLAGS from your Yocto build, disable checking by adding ldflags to INSANE_SKIP
  • Vendor typically ship release builds with debug symbols so disable stripping to prevent packaging errors by setting INHIBIT_PACKAGE_STRIP and INHIBIT_SYSROOT_STRIP.

Complete recipe would look like this.

SUMMARY = "FTDI FT4222 Library"
SECTION = "libs"
LICENSE_FLAGS = "ftdi"
LICENSE = "CLOSED"

COMPATIBLE_MACHINE = "intel-corei7-64|intel-core2-32|genericx86-64|genericx86|edison|qemux86"

# BUILD_NUMBER is set to build number of libft4222 release tarball
# Set subdir variable to ${P} so that files are unpacked into ${S}
SRC_URI = "http://www.ftdichip.com/Support/SoftwareExamples/${PN}-${PV}.${BUILD_NUMBER}.tgz;subdir=${P}"
SRC_URI[md5sum] = "c5bc189fb5b167daf662ff81c66cde55"
SRC_URI[sha256sum] = "df03e50f4a205474eaacadcdb59dc602237e95d48008ede8fc2d1f2493e54845"

MACHINE_DIR_intel-corei7-64 = "build-x86_64"
MACHINE_DIR_genericx86-64 = "build-x86_64"
MACHINE_DIR_genericx86 = "build-i386"
MACHINE_DIR_intel-core2-32 = "build-i386"
MACHINE_DIR_edison = "build-i386"
MACHINE_DIR_qemux86 = "build-i386"

INSANE_SKIP_${PN} = "ldflags"
INHIBIT_PACKAGE_STRIP = "1"
INHIBIT_SYSROOT_STRIP = "1"

do_install () {
	install -m 0755 -d ${D}${libdir}
	oe_soinstall ${S}/${MACHINE_DIR}/libft4222.so.${PV}.${BUILD_NUMBER} ${D}${libdir}
	install -m 0755 -d ${D}${includedir}
	install -m 0755 ${S}/*.h ${D}${includedir}
}

Non-versioned Libraries

Some Background

Libraries in Linux systems are generally versioned so that it is possible to have multiple versions of the same library installed, which eases upgrades and support for older software. For example, suppose that in a versioned library an actual library is called "libfoo.so.1.2", a symbolic link named "libfoo.so.1" points to "libfoo.so.1.2", and a symbolic link named "libfoo.so" points to "libfoo.so.1.2". Given these conditions, when you link a binary against a library, you typically provide the unversioned file name (i.e. -lfoo to the linker). However, the linker follows the symbolic link and actually links against the versioned filename. The unversioned symbolic link is only used at development time. Consequently, the library is packaged along with the headers in the development package ${PN}-dev along with the actual library and versioned symbolic links in ${PN}. Because versioned libraries are far more common than unversioned libraries, the default packaging rules assume versioned libraries.

Yocto Packaging Overview

It follows that packaging an unversioned library requires a bit of work in the recipe. By default, "libfoo.so" gets packaged into ${PN}-dev, which triggers a QA warning that a non-symlink library is in a -dev package, and binaries in the same recipe link to the library in ${PN}-dev, which triggers more QA warnings. To solve this problem, you need to package the unversioned library into ${PN} where it belongs. Following are the abridged default FILES variables in bitbake.conf:

 SOLIBS = ".so.*"
 SOLIBSDEV = ".so"
 FILES_${PN} = "... ${libdir}/lib*${SOLIBS} ..."
 FILES_SOLIBSDEV ?= "... ${libdir}/lib*${SOLIBSDEV} ..."
 FILES_${PN}-dev = "... ${FILES_SOLIBSDEV} ..."

SOLIBS defines a pattern that matches real shared object libraries. SOLIBSDEV matches the development form (unversioned symlink). These two variables are then used in FILES_${PN} and FILES_${PN}-dev, which puts the real libraries into ${PN} and the unversioned symbolic link into PN-dev. To package unversioned libraries, you need to modify the variables in the recipe as follows:

 SOLIBS = ".so"
 FILES_SOLIBSDEV = ""

The modifications cause .so to be the real library and unsets FILES_SOLIBSDEV so that no libraries get packaged into PN-dev. The changes are required because unless PACKAGES is changed, PN-dev collects files before PN. PN-dev must not collect any of the files you want in PN.

Finally, loadable modules (i.e. essentially unversioned libraries that are linked at runtime using dlopen() instead of at build time) should generally be installed in a private directory. However, if they are installed in ${libdir}, then the modules can be treated as unversioned libraries.

Example

The example below installs an unversioned x86-64 pre-built library libfoo.so. The COMPATIBLE_MACHINE, INSANE_SKIP, INHIBIT_PACKAGE_STRIP and INHIBIT_SYSROOT_STRIP variables are all set as for the versioned example above. The "magic" is setting the SOLIBS and FILES_SOLIBSDEV variables are explained above.

SUMMARY = "libfoo sample recipe"
SECTION = "libs"
LICENSE = "CLOSED"

SRC_URI = "file://libfoo.so"

COMPATIBLE_MACHINE = "intel-corei7-64|genericx86-64"

INSANE_SKIP_${PN} = "ldflags"
INHIBIT_PACKAGE_STRIP = "1"
INHIBIT_SYSROOT_STRIP = "1"

SOLIBS = ".so"
FILES_SOLIBSDEV = ""

do_install () {
	install -m 0755 -d ${D}${libdir}
	oe_libinstall ${WORKDIR}/libfoo.so ${D}${libdir}
}