| 1 | = Adding a Compiled Library to CMake = |
| 2 | This page describes how to add a new, compiled library to the CMake-based build system. If you library is a "header-only" library, and does not require separate compilation of object files into a library binary, you can safely skip this step. Before adding compiled libraries to CMake, make sure you have already followed the directions for [wiki:CMakeAddingALibrary adding a library to CMake], so that the CMake system recognizes your Boost library. |
| 3 | |
| 4 | In this page, we will assume that your library resides in the subdirectory `libs/libname`, and that we want to create the compiled library `boost_libname`. We will also assume that the sources for this library reside in the subdirectory `libs/libname/src`. The source directory should be listed via `SRCDIRS` in the use of the [wiki:CMakeLibraryProject boost_library_project macro], as described in the previous section, [wiki:CMakeAddingALibrary "Adding a Library to CMake"]. Follow these steps to add this new library into Boost's build system. If your library has multiple source directories listed after `SRCDIRS`, follow these steps for each one. |
| 5 | |
| 6 | 1. Create a new file `libs/libname/src/CMakeLists.txt`with your favorite text editor. This file will contain build rules for your compiled library. In this file, we will create one or more invocations of the [wiki:CMakeAddLibrary boost_add_library macro], which adds a compiled Boost library to the CMake system. The `boost_add_library` macro provides the name of the library, the source files from which the library will be built, and any specific compiler and linker options needed to help build the library. Let's start by adding a simple library with a few source files: |
| 7 | {{{ |
| 8 | boost_add_library(boost_libname |
| 9 | mysrc1.cpp mysrc2.cpp |
| 10 | ) |
| 11 | }}} |
| 12 | |
| 13 | This invocation will build several variants of the `boost_libname` library from the source files `mysrc1.cpp` and `mysrc2.cpp`. For example, it will build both static and shared library, single- and multi-threaded, debug and release, etc. This invocation also handles the installation of these libraries. |
| 14 | |
| 15 | 2. For simple libraries, that's it! Rebuilding via CMake (e.g., running `make` or reloading and rebuilding the Boost project in your IDE) will build the new library, including several different variants for different compilation options. Your Boost library will also be included when the user installs Boost or builds a binary package of Boost. |
| 16 | |
| 17 | 3. Many libraries will need specific compilation options when building, need to link against other libraries (Boost or otherwise), or rely on certain features of the compilation process to proceed. Follow the instructions in the remaining part of this page to address these library-specific needs. |
| 18 | |
| 19 | == Compilation Flags == |
| 20 | Many libraries require certain compilation flags when we are building the library binaries themselves (rather than when the library headers are included by the user). For example, we want to define the macro "BUILDING_BOOST_LIBNAME" when building the library. We can do so by passing the `COMPILE_FLAGS` option to `boost_add_library`: |
| 21 | {{{ |
| 22 | boost_add_library(boost_libname |
| 23 | mysrc1.cpp mysrc2.cpp |
| 24 | COMPILE_FLAGS "-DBUILDING_BOOST_LIBNAME=1" |
| 25 | ) |
| 26 | }}} |
| 27 | |
| 28 | Now when CMake builds the library, it will pass the flag `-DBUILDING_BOOST_LIBNAME=1` to the compiler. |
| 29 | |
| 30 | On Windows, shared libraries are built very differently from static libraries. In particular, when building a shared library, one needs to be sure to export the right symbols from the DLL using `dllexport`. When users use the shared library, these symbols will be imported (via `dllimport`). The typical way to handle this is to define a macro (say, `BOOST_LIBNAME_DYN_LINK`) when building the shared library. This macro instructs the library headers to `dllexport` everything that needs to be exported. We can do this with variant-specific compile flags, e.g., |
| 31 | {{{ |
| 32 | boost_add_library(boost_libname |
| 33 | mysrc1.cpp mysrc2.cpp |
| 34 | COMPILE_FLAGS "-DBUILDING_BOOST_LIBNAME=1" |
| 35 | SHARED_COMPILE_FLAGS "-DBOOST_LIBNAME_DYN_LINK=1" |
| 36 | ) |
| 37 | }}} |
| 38 | |
| 39 | When building a shared library, the `SHARED_COMPILE_FLAGS` options will be combined with the `COMPILE_FLAGS` options. When building a static library, the `SHARED_COMPILE_FLAGS` options will be ignored. There are other options that can be specified per-feature, such as `LINK_FLAGS` and `LINK_LIBS`; refer to the [wiki:CMakeAddLibrary boost_add_library macro reference] for more information. |
| 40 | |
| 41 | == Linking to Other Libraries == |
| 42 | Some Boost libraries depends on other Boost libraries. For example, perhaps our library uses the Boost.Filesystem library under the hood. We can use the `DEPENDS` feature of the [wiki:CMakeAddLibrary boost_add_library macro] to state which libraries our library depends on. In this example, we'll link against `boost_filesystem`: |
| 43 | |
| 44 | {{{ |
| 45 | boost_add_library(boost_libname |
| 46 | mysrc1.cpp mysrc2.cpp |
| 47 | COMPILE_FLAGS "-DBUILDING_BOOST_LIBNAME=1" |
| 48 | SHARED_COMPILE_FLAGS "-DBOOST_LIBNAME_DYN_LINK=1" |
| 49 | DEPENDS boost_filesystem |
| 50 | ) |
| 51 | }}} |
| 52 | |
| 53 | Now, each variant of the `boost_libname` library will link against the appropriate `boost_filesystem` library variant. Whenever `boost_filesystem` changes, our library will be relinked appropriately. |
| 54 | |
| 55 | == Linking External Libraries/Optional Sources == |
| 56 | Sometimes, Boost libraries need to link against other libraries supplied by the system. The primary challenge in linking against these libraries is ``finding`` those libraries, and their associated headers, on the system. If the library is found, we usually want to pass some extra compilation flags to our library and add in additional sources. Otherwise, we just skip these extra sources. |
| 57 | |
| 58 | Often, CMake already contains a module that will search for a common system library or tool; search the [http://www.cmake.org/HTML/Documentation.html CMake Documentation] for existing modules that do what you need. For example, say we want to link against the system's `PNG` library for portable network graphics. We can use the supplied `FindPNG` module by adding the following early in our `CMakeLists.txt` file: |
| 59 | {{{ |
| 60 | include(FindPNG) |
| 61 | }}} |
| 62 | |
| 63 | Documentation for CMake modules is typically found in the module file itself. Look into the `Modules` subdirectory of your CMake installation, either in `Program Files\CMake` (on Windows) or `/usr/share/cmake-version` (on Unix variants) to find the module of the same name. The module will typically provide a variable that indicates whether the library was found. For the `FindPNG` module, this variable is called `PNG_FOUND`. We can use this variable to optionally add sources to a variable `EXTRA_SOURCES`: |
| 64 | |
| 65 | {{{ |
| 66 | include(FindPNG) |
| 67 | set(EXTRA_SOURCES) |
| 68 | if (PNG_FOUND) |
| 69 | list(APPEND EXTRA_SOURCES png.cpp) |
| 70 | endif (PNG_FOUND) |
| 71 | }}} |
| 72 | |
| 73 | CMake modules also typically define macros specifying the include directories needed for the library and linking information for the library binary. For the `FindPNG` module, these variables are called `PNG_PNG_INCLUDE_DIR` and `PNG_LIBRARY`, respectively. The include directory should be added via the CMake `include_directories` macro, e.g., |
| 74 | |
| 75 | {{{ |
| 76 | include_directories(${PNG_PNG_INCLUDE_DIR}) |
| 77 | }}} |
| 78 | |
| 79 | while the `PNG_LIBRARY` value should be added to the `LINK_LIBS` option to the [wiki:CMakeAddLibrary boost_add_library macro]. Using these features together, we can search for the PNG library on the system and optionally include PNG support into our library: |
| 80 | |
| 81 | {{{ |
| 82 | include(FindPNG) |
| 83 | set(EXTRA_SOURCES) |
| 84 | if (PNG_FOUND) |
| 85 | include_directories(${PNG_PNG_INCLUDE_DIR}) |
| 86 | list(APPEND EXTRA_SOURCES png.cpp) |
| 87 | endif (PNG_FOUND) |
| 88 | |
| 89 | boost_add_library(boost_libname |
| 90 | mysrc1.cpp mysrc2.cpp |
| 91 | ${EXTRA_SOURCES} |
| 92 | COMPILE_FLAGS "-DBUILDING_BOOST_LIBNAME=1" |
| 93 | LINK_LIBS "${PNG_LIBRARY}" |
| 94 | SHARED_COMPILE_FLAGS "-DBOOST_LIBNAME_DYN_LINK=1" |
| 95 | DEPENDS boost_filesystem |
| 96 | ) |
| 97 | }}} |
| 98 | |
| 99 | If CMake does not provide a module to search for the library you need, don't worry! You can write your own module relatively easily, following the examples from the CMake `Modules` directory or some of the Boost-specific examples, such as [http://svn.boost.org/svn/boost/sandbox-branches/boost-cmake/boost_1_34_0/tools/build/CMake/FindICU.cmake tools/build/CMake/FindICU.cmake]. For a real-life example of finding system libraries and using that information to add optional, extra capabilities to a Boost library, check out the build rules for the Boost.IOStreams library at [http://svn.boost.org/svn/boost/sandbox-branches/boost-cmake/boost_1_34_0/libs/iostreams/src/CMakeLists.txt libs/iostreams/src/CMakeLists.txt]. |
| 100 | |
| 101 | == Build Variants == |
| 102 | The Boost build system defines many different [wiki:CMakeBuildFeatures build features], which describe specific properties of certain builds. For example, the `SHARED` feature indicates that we are building a shared library, while the `MULTI_THREADED` feature indicates that we are building a multi-threaded library. A specific set of features is called a ```variant```, e.g., `RELEASE` and `MULTI_THREADED` and `SHARED`. |
| 103 | |
| 104 | |
| 105 | Since some features conflict with certain libraries (a threading library cannot be `SINGLE_THREADED`!), one can pass |