- Qbs Manual
- Configurable Library
- Qbs 2.3.1

Buildconfig Module ◦ How-tos

# Configurable Library

In this chapter, we will make our library more configurable. We will add configuration options to be able to choose between static and dynamic builds.

We start with some new properties in the `mybuildconfig` module:

     Module {
         ...
         property bool staticBuild: false
         property bool installStaticLib: true
         ...
     }

We need to do some modifications to export macros in the `lib/lib_global.h` header:

     // lib/lib_global.h
     #if defined(MYLIB_STATIC_LIBRARY)
     #define MYLIB_EXPORT
     #else
     #if defined(MYLIB_LIBRARY)
     #define MYLIB_EXPORT MY_LIB_DECL_EXPORT
     #else
     #define MYLIB_EXPORT MY_LIB_DECL_IMPORT
     #endif
     #endif

Here' we added a new branch when `MYLIB_STATIC_LIBRARY` is defined. In that case, we make the `MY_LIB_EXPORT` macro empty.

Now, let's modify the `qbs/imports/MyLibrary.qbs` file as follows:

     Library {
         Depends { name: "cpp" }
         Depends { name: "mybuildconfig" }
         type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary"
         version: "1.0.0"
         install: !mybuildconfig.staticBuild || mybuildconfig.installStaticLib
         installDir: mybuildconfig.libInstallDir

         readonly property string _nameUpper : name.replace(" ", "_").toUpperCase()
         property string libraryMacro: _nameUpper + "_LIBRARY"
         property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY"
         cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro]
         cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined

         Export {
             Depends { name: "cpp" }
             cpp.includePaths: [exportingProduct.sourceDirectory]
             cpp.defines: exportingProduct.mybuildconfig.staticBuild
                 ? [exportingProduct.staticLibraryMacro] : []
         }

         Depends { name: "bundle" }
         bundle.isBundle: false
     }

First thing to notice is that we changed the type of the item from DynamicLibrary to the Library item which is a common base item for dynamic and static libraries.

Second, we change the type of the product so it depends on the `staticBuild` property:

     type: mybuildconfig.staticBuild ? "staticlibrary" : "dynamiclibrary"

Third, we change our export macro to be different in the static and dynamic builds to correspond with the changes we made to the `lib_global.h`:

     readonly property string _nameUpper : name.replace(" ", "_").toUpperCase()
     property string libraryMacro: _nameUpper + "_LIBRARY"
     property string staticLibraryMacro: _nameUpper + "_STATIC_LIBRARY"
     cpp.defines: mybuildconfig.staticBuild ? [staticLibraryMacro] : [libraryMacro]

Note that in a static build we export the `MYLIB_STATIC_LIBRARY` macro so that the dependent products will know whether they link to a static or dynamic library:

     Export {
         ...
         cpp.defines: exportingProduct.mybuildconfig.staticBuild
             ? [exportingProduct.staticLibraryMacro] : []
     }

Now we can build our project in dynamic or static mode:

     $ qbs resolve modules.mybuildconfig.staticBuild:false && qbs build
     ...
     $ ls default/install-root/usr/local/lib/
         libmylib.1.0.0.so
         libmylib.1.0.so
         libmylib.1.so
         libmylib.so
     $ rm -r default
     $ qbs resolve modules.mybuildconfig.staticBuild:true && qbs build
     ...
     $ $ ls default/install-root/usr/local/lib/
         libmylib.a

Buildconfig Module ◦ How-tos