Dynamic Library

Let's now turn our static library into a dynamic library. It is a bit trickier with dynamic libraries since several things should be tweaked. First, we need to be able to mark methods (or classes) in our library as exported. Second, we need to tell our application where to look for our library at run time using rpaths.

Some compilers, like MSVC, require us to mark which symbols we want to export or import. The canonical way would be to define some helper macros. Let's start with a header that defines those helper macros:

// lib/lib_global.h

#ifndef LIB_GLOBAL_H
#define LIB_GLOBAL_H

#if defined(_WIN32) || defined(WIN32)
#define MYLIB_DECL_EXPORT __declspec(dllexport)
#define MYLIB_DECL_IMPORT __declspec(dllimport)
#else
#define MYLIB_DECL_EXPORT __attribute__((visibility("default")))
#define MYLIB_DECL_IMPORT __attribute__((visibility("default")))
#endif

#if defined(MYLIB_LIBRARY)
#define MYLIB_EXPORT MYLIB_DECL_EXPORT
#else
#define MYLIB_EXPORT MYLIB_DECL_IMPORT
#endif

#endif // LIB_GLOBAL_H

This header defines the MYLIB_EXPORT macro that expands either to an "export" or to an "import" directive based on the presence of the MYLIB_LIBRARY macro. We can use this macro to mark a function as follows:

// lib/lib.h
#include "lib_global.h"

MYLIB_EXPORT const char *get_string();

The modified library product may look like this:

// lib/lib.qbs

DynamicLibrary {
    name: "mylib"
    files: [
        "lib.c",
        "lib.h",
        "lib_global.h",
    ]
    version: "1.0.0"
    install: true

    Depends { name: "cpp" }
    cpp.defines: ["MYLIB_LIBRARY", "CRUCIAL_DEFINE"]
    cpp.sonamePrefix: qbs.targetOS.contains("darwin") ? "@rpath" : undefined

    Export {
        Depends { name: "cpp" }
        cpp.includePaths: [exportingProduct.sourceDirectory]
    }

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

The most important change is that we changed the item type from StaticLibrary to DynamicLibrary. We also added the MYLIB_LIBRARY to the list of defines. We do this only when building the library but we are not exporting it - that way the users of our library will have methods marked for import rather than export.

Finally, we set cpp.sonamePrefix to "@rpath". This is required only for Apple platforms, see Run-Path Dependent Libraries for details.

It is also required to set cpp.rpaths in our application file. Since the library is installed to the lib directory and the application is installed to the bin directory, we need to tell the loader to look in the lib directory. The FileInfo.relativePath method can help us:

cpp.rpaths: {
    if (!cpp.rpathOrigin)
        return [];
    return [
        FileInfo.joinPaths(
            cpp.rpathOrigin,
            FileInfo.relativePath(
                FileInfo.joinPaths("/", product.installDir),
                FileInfo.joinPaths("/", "lib")))
    ];
}

On Linux, this expression would be equivalent to this: cpp.rpaths: ["$ORIGIN/../lib"]. Don't forget to import qbs.FileInfo in order to be able to use the jsextension-fileinfo.html extension.

To make the example complete, here's how the full app/app.qbs file should look like:

// app/app.qbs
import qbs.FileInfo

CppApplication {
    Depends { name: "mylib" }
    name: "My Application"
    targetName: "myapp"
    files: "main.c"
    version: "1.0.0"

    consoleApplication: true
    install: true

    cpp.rpaths: {
        if (!cpp.rpathOrigin)
            return [];
        return [
            FileInfo.joinPaths(
                cpp.rpathOrigin,
                FileInfo.relativePath(
                    FileInfo.joinPaths("/", product.installDir),
                    FileInfo.joinPaths("/", "lib")))
        ];
    }
}

© 2022 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.