1.. SPDX-License-Identifier: CC-BY-SA-2.0-UK 2 3Working with Pre-Built Libraries 4******************************** 5 6Introduction 7============ 8 9Some library vendors do not release source code for their software but do 10release pre-built binaries. When shared libraries are built, they should 11be versioned (see `this article 12<https://tldp.org/HOWTO/Program-Library-HOWTO/shared-libraries.html>`__ 13for some background), but sometimes this is not done. 14 15To summarize, a versioned library must meet two conditions: 16 17#. The filename must have the version appended, for example: ``libfoo.so.1.2.3``. 18#. The library must have the ELF tag ``SONAME`` set to the major version 19 of the library, for example: ``libfoo.so.1``. You can check this by 20 running ``readelf -d filename | grep SONAME``. 21 22This section shows how to deal with both versioned and unversioned 23pre-built libraries. 24 25Versioned Libraries 26=================== 27 28In this example we work with pre-built libraries for the FT4222H USB I/O chip. 29Libraries are built for several target architecture variants and packaged in 30an archive as follows:: 31 32 ├── build-arm-hisiv300 33 │ └── libft4222.so.1.4.4.44 34 ├── build-arm-v5-sf 35 │ └── libft4222.so.1.4.4.44 36 ├── build-arm-v6-hf 37 │ └── libft4222.so.1.4.4.44 38 ├── build-arm-v7-hf 39 │ └── libft4222.so.1.4.4.44 40 ├── build-arm-v8 41 │ └── libft4222.so.1.4.4.44 42 ├── build-i386 43 │ └── libft4222.so.1.4.4.44 44 ├── build-i486 45 │ └── libft4222.so.1.4.4.44 46 ├── build-mips-eglibc-hf 47 │ └── libft4222.so.1.4.4.44 48 ├── build-pentium 49 │ └── libft4222.so.1.4.4.44 50 ├── build-x86_64 51 │ └── libft4222.so.1.4.4.44 52 ├── examples 53 │ ├── get-version.c 54 │ ├── i2cm.c 55 │ ├── spim.c 56 │ └── spis.c 57 ├── ftd2xx.h 58 ├── install4222.sh 59 ├── libft4222.h 60 ├── ReadMe.txt 61 └── WinTypes.h 62 63To write a recipe to use such a library in your system: 64 65- The vendor will probably have a proprietary licence, so set 66 :term:`LICENSE_FLAGS` in your recipe. 67- The vendor provides a tarball containing libraries so set :term:`SRC_URI` 68 appropriately. 69- Set :term:`COMPATIBLE_HOST` so that the recipe cannot be used with an 70 unsupported architecture. In the following example, we only support the 32 71 and 64 bit variants of the ``x86`` architecture. 72- As the vendor provides versioned libraries, we can use ``oe_soinstall`` 73 from :ref:`ref-classes-utils` to install the shared library and create 74 symbolic links. If the vendor does not do this, we need to follow the 75 non-versioned library guidelines in the next section. 76- As the vendor likely used :term:`LDFLAGS` different from those in your Yocto 77 Project build, disable the corresponding checks by adding ``ldflags`` 78 to :term:`INSANE_SKIP`. 79- The vendor will typically ship release builds without debugging symbols. 80 Avoid errors by preventing the packaging task from stripping out the symbols 81 and adding them to a separate debug package. This is done by setting the 82 ``INHIBIT_`` flags shown below. 83 84The complete recipe would look like this:: 85 86 SUMMARY = "FTDI FT4222H Library" 87 SECTION = "libs" 88 LICENSE_FLAGS = "ftdi" 89 LICENSE = "CLOSED" 90 91 COMPATIBLE_HOST = "(i.86|x86_64).*-linux" 92 93 # Sources available in a .tgz file in .zip archive 94 # at https://ftdichip.com/wp-content/uploads/2021/01/libft4222-linux-1.4.4.44.zip 95 # Found on https://ftdichip.com/software-examples/ft4222h-software-examples/ 96 # Since dealing with this particular type of archive is out of topic here, 97 # we use a local link. 98 SRC_URI = "file://libft4222-linux-${PV}.tgz" 99 100 S = "${WORKDIR}" 101 102 ARCH_DIR:x86-64 = "build-x86_64" 103 ARCH_DIR:i586 = "build-i386" 104 ARCH_DIR:i686 = "build-i386" 105 106 INSANE_SKIP:${PN} = "ldflags" 107 INHIBIT_PACKAGE_STRIP = "1" 108 INHIBIT_SYSROOT_STRIP = "1" 109 INHIBIT_PACKAGE_DEBUG_SPLIT = "1" 110 111 do_install () { 112 install -m 0755 -d ${D}${libdir} 113 oe_soinstall ${S}/${ARCH_DIR}/libft4222.so.${PV} ${D}${libdir} 114 install -d ${D}${includedir} 115 install -m 0755 ${S}/*.h ${D}${includedir} 116 } 117 118If the precompiled binaries are not statically linked and have dependencies on 119other libraries, then by adding those libraries to :term:`DEPENDS`, the linking 120can be examined and the appropriate :term:`RDEPENDS` automatically added. 121 122Non-Versioned Libraries 123======================= 124 125Some Background 126--------------- 127 128Libraries in Linux systems are generally versioned so that it is possible 129to have multiple versions of the same library installed, which eases upgrades 130and support for older software. For example, suppose that in a versioned 131library, an actual library is called ``libfoo.so.1.2``, a symbolic link named 132``libfoo.so.1`` points to ``libfoo.so.1.2``, and a symbolic link named 133``libfoo.so`` points to ``libfoo.so.1.2``. Given these conditions, when you 134link a binary against a library, you typically provide the unversioned file 135name (i.e. ``-lfoo`` to the linker). However, the linker follows the symbolic 136link and actually links against the versioned filename. The unversioned symbolic 137link is only used at development time. Consequently, the library is packaged 138along with the headers in the development package ``${PN}-dev`` along with the 139actual library and versioned symbolic links in ``${PN}``. Because versioned 140libraries are far more common than unversioned libraries, the default packaging 141rules assume versioned libraries. 142 143Yocto Library Packaging Overview 144-------------------------------- 145 146It follows that packaging an unversioned library requires a bit of work in the 147recipe. By default, ``libfoo.so`` gets packaged into ``${PN}-dev``, which 148triggers a QA warning that a non-symlink library is in a ``-dev`` package, 149and binaries in the same recipe link to the library in ``${PN}-dev``, 150which triggers more QA warnings. To solve this problem, you need to package the 151unversioned library into ``${PN}`` where it belongs. The following are the abridged 152default :term:`FILES` variables in ``bitbake.conf``:: 153 154 SOLIBS = ".so.*" 155 SOLIBSDEV = ".so" 156 FILES:${PN} = "... ${libdir}/lib*${SOLIBS} ..." 157 FILES_SOLIBSDEV ?= "... ${libdir}/lib*${SOLIBSDEV} ..." 158 FILES:${PN}-dev = "... ${FILES_SOLIBSDEV} ..." 159 160:term:`SOLIBS` defines a pattern that matches real shared object libraries. 161:term:`SOLIBSDEV` matches the development form (unversioned symlink). These two 162variables are then used in ``FILES:${PN}`` and ``FILES:${PN}-dev``, which puts 163the real libraries into ``${PN}`` and the unversioned symbolic link into ``${PN}-dev``. 164To package unversioned libraries, you need to modify the variables in the recipe 165as follows:: 166 167 SOLIBS = ".so" 168 FILES_SOLIBSDEV = "" 169 170The modifications cause the ``.so`` file to be the real library 171and unset :term:`FILES_SOLIBSDEV` so that no libraries get packaged into 172``${PN}-dev``. The changes are required because unless :term:`PACKAGES` is changed, 173``${PN}-dev`` collects files before `${PN}`. ``${PN}-dev`` must not collect any of 174the files you want in ``${PN}``. 175 176Finally, loadable modules, essentially unversioned libraries that are linked 177at runtime using ``dlopen()`` instead of at build time, should generally be 178installed in a private directory. However, if they are installed in ``${libdir}``, 179then the modules can be treated as unversioned libraries. 180 181Example 182------- 183 184The example below installs an unversioned x86-64 pre-built library named 185``libfoo.so``. The :term:`COMPATIBLE_HOST` variable limits recipes to the 186x86-64 architecture while the :term:`INSANE_SKIP`, :term:`INHIBIT_PACKAGE_STRIP` 187and :term:`INHIBIT_SYSROOT_STRIP` variables are all set as in the above 188versioned library example. The "magic" is setting the :term:`SOLIBS` and 189:term:`FILES_SOLIBSDEV` variables as explained above:: 190 191 SUMMARY = "libfoo sample recipe" 192 SECTION = "libs" 193 LICENSE = "CLOSED" 194 195 SRC_URI = "file://libfoo.so" 196 197 COMPATIBLE_HOST = "x86_64.*-linux" 198 199 INSANE_SKIP:${PN} = "ldflags" 200 INHIBIT_PACKAGE_STRIP = "1" 201 INHIBIT_SYSROOT_STRIP = "1" 202 SOLIBS = ".so" 203 FILES_SOLIBSDEV = "" 204 205 do_install () { 206 install -d ${D}${libdir} 207 install -m 0755 ${WORKDIR}/libfoo.so ${D}${libdir} 208 } 209 210