Target_link_libraries Cmake Example

This tutorial shows various ways to use CMake’s target_link_libraries() statement and explains the differences between them. We will create a basic Raspberry Pi project using the sqlite3 library and will then show different ways of using target_link_libraries() to reference the necessary libraries.

  • Targetlinklibraries means in Modern CMake two things: use library (get its properties) at compilation stage and link with it at linking stage. Hence maybe a bit better name for it would be targetuselibraries but it would break the backward compatibility. Example 2: defining header-only libraries.
  • When using CMake 3.12 or earlier, working around the restriction with targetlinklibraries is harder. The choices are either to move the targetlinklibraries call up to the same directory in which the target is defined, or avoid creating new directory scopes by using include instead of addsubdirectory. The second of these options.

Target_link_libraries Cmake Example Report


In this tutorial we will use Visual Studio and VisualGDB, however the steps described below will work with any other CMake-based environment.

  1. Connect to your Raspberry Pi via SSH and install the libsqlite3-dev package. If you are using SmarTTY, the Tools->Manage Linux Packages command can help you find the exact package name easier:
  2. Start Visual Studio and open the VisualGDB Linux Project Wizard:
  3. On the first page select “Create Application -> CMake -> Ninja”:
  4. On the next page select your Raspberry Pi cross-toolchain and pick the SSH connection for your Pi. Ensure the “test connection” checkbox is checked so that VisualGDB can check that all the necessary packages are present:
  5. Press “Finish” to create the project. Once it is created, open VisualGDB Project Properties and click “Synchronize Sysroot” on the CMake project settings page. This will copy the sqlite libraries from the Raspberry Pi into the toolchain so that you can reference them from the projects built with that toolchain:
  6. Replace the contents of the main source file with the following basic project demonstrating the use of sqlite3:
    #include <sqlite3.h>
    using namespacestd;
    printf('sqlite3_initialize() failed: error %dn',rc);
  7. Try building the project. As we have included the header files (that provide the definitions for sqlite3_xxx() functions), but have not referenced the library defining them, the linker will fail due to missing definitions for the sqlite3 functions:
  8. In order to fix the “undefined reference to ‘sqlite3_initialize’” errors, we need to locate the library that defines those symbols. This can be done by either checking the sqlite3 documentation, or searching for all libraries on Raspberry Pi for the name of the missing symbol (sqlite3_initialize):
  9. Once you have located the library, add its full path to the Linked Libraries field under the VS properties for your main CMake target. Note that if the project is built on the Windows side, you would need to use the ${CMAKE_SYSROOT} prefix to refer to the sysroot directory (a copy of the Raspberry Pi’s file system that is bundled with the toolchain). In this example the library path would be ${CMAKE_SYSROOT}/usr/lib/arm-linux-gnueabihf/libsqlite3.a:
  10. Alternatively, simply edit the target_link_libraries() statement for your library manually. Now the build will fail due to missing pthread and dl functions:
  11. You could locate the library names for pthread and dl functions using similar steps as we used for libsqlite3, however in this tutorial we will use just the short names for simplicity (we will explain the differences between the short names and full paths inside target_link_libraries() later):
  12. Press F5 to start debugging and ensure the program runs successfully:
  13. Open the CMakeLists.txt file and locate the target_link_libraries() statement. It will normally have the following contents:
    In farming simulator 19 how to get inf money

    Craig Scott – Professional CMake: A Practical Guide (5th edition)

    Just buy the book! Its value is a multiple of its 30 USD price. The book covers all of CMake in three parts.

    • Part I: Fundamentals. The first part teaches you the CMake language: application and library targets, variables and their scopes, flow control, functions, properties and splitting up projects into subdirectories. This is normally enough to build your Qt application with some libraries.
    • Part II: Builds in Depth. The second part explains how to generate release, debug and other configurations, how to add compiler and linker flags, how to generate and copy files during a CMake run, how to integrate toolchains (32-bit GCC, Raspberry Pi and Android) and how to handle versioning.
    • Part III: The Bigger Picture. The third part goes beyond CMake. It explains how to run tests with CTest and how to show the results in a dashboard (CDash). Installing your applications, libraries and auxiliary files with CMake amounts to some calls to CMake’s install function. CPack enables packaging the installation files as simple archives, Qt IFW, WIX, NSIS, RPM, DEB, etc.

    Every chapter ends with a section Recommended Practices. Craig illustrates with hundreds of well thought-out examples how CMake and its companion tools work. I can often copy one or two lines from the book and use them in my own CMake files – with little or no modifications. The book also contains a lot of useful tips for building Qt applications.

    Craig Scott – Professional CMake: A Practical Guide (6th edition)

    Craig updated his CMake book to cover version 3.17. He added a brand new chapter about Working With Qt (Chapter 30). I had the pleasure of reviewing the new Qt chapter. It is full of great advice and well thought-out examples – like the rest of the book. Although I have gained quite a bit of experience with CMake, I learned a few new tricks.

    • Calling find_package for each Qt module separately may find Qt modules from different versions. It’s better to call it once for all modules.
    • If you switch on CMAKE_AUTOMOC, CMake will collate a file mocs_compilation.cpp, which includes all sources files generated by moc. This file can quickly become huge, takes a long time to compile, and becomes the bottleneck for compilation. Craig gives a solution with qt5_wrap_cpp and a custom target, where CMake generates a separate moc source file for each moc header.
    • CMake provides the macros qt5_create_translation and qt5_add_translation to generate the .ts files and to compile the .ts files into .qm files, respectively. Of course, Craig gives an example CMakeLists.txt file how to build and deploy translations.
    • CMake comes with deployment tools macdeployqt, windowsdeployqt and androiddeployqt for MacOS, Windows and Android. The best solution for Linux is to use the CMake install commands for CMake 3.14 or newer or the workaround with QtCreatorDeployment.txt as described here for older versions.

    As you probably know by now, CMake is the default build system for Qt 6. This new chapter prepares you very well for the future. As in my review of the 5th edition, my verdict is: Just buy the book! It’s worth every penny. Bonus: If you own the book already, you’ll get all updates for free.

    Mathieu Ropert – Using Modern CMake Patterns to Enforce Good Modular Design

    This talk is the foundation for quite a few of Manuel’s dos and don’ts (see above). It especially elaborates on the tip Imagine targets as objects. Mathieu’s talk will make the difference whether you end up in CMake hell or not. So you better watch it!

    Mathieu’s core point is that you regard every library defined by add_library as an object or module with a public and private interface. Clients depending on the library don’t have to know all the compiler and linker options required to build the library. These are implementation details best hidden from clients.

    All the target properties have PUBLIC and PRIVATE keywords to control the visibility of compiler and linker options. If, for example, library A depends on library B only internally, you can write

    Clients of library A won’t know anything of B. If you replace PRIVATE by PUBLIC or leave out the keyword, clients of A will see library B. Library B will be listed in the linker options of A. Similarly, you can specify which headers are visible to clients and which are not.


    Mathieu’s advice is to use PRIVATE whereever possible to avoid polluting the global namespace. Otherwise, your CMake projects will quickly become unmaintainable.

    The target_link_libraries command above refers to a module B instead of linker options -L/usr/local/lib -lB. The linker options are hidden inside module B. Library A uses the command find_package(B) to address module B as an object. find_package only works, if CMake finds a config package file BConfig.cmake.

    If library B is a CMake project, you can generate most of the config package file with the command install(EXPORT). Unless for simple projects, you need to extend the config package file a little bit. Craig gives a detailed example in section 25.7.1 of his book Professional CMake. If library B is not a CMake project, Mathieu describes how to write a hand-made finder (starting at position 39:22 in the video).

    Manuel Binna – Effective Modern CMake

    Follow the link and click on the title Effective Modern CMake to see the full post in its latest version. Manuel has compiled a list of 40+ dos and don’ts, which he maintains and extends regularly. The explanation for each item is short and to the point. If the explanation is too short, you can head over to Craig’s CMake book for more details. Here are my favourite items.

    • Treat CMake code like production code. Keep your CMakeLists.txt files as simple as possible and improve them regularly.
    • Define project properties globally. Variables, options or properties defined in the top-level CMakeLists.txt file are propagated to all subdirectories and included files. Examples are compiler warnings and flags for crossbuilds, for static-analysis builds or for adding license checks.
    • Follow a naming convention for test names. A unique prefix of the test project names helps you to identify a set of tests to run with CTest.
    • Imagine targets as objects. The functions add_executable and add_library are the constructors. Target properties like target_compile_definitions, target_include_libraries and target_link_libraries are the member variables.

    Manuel’s list will save you considerable time, as you don’t have to figure out the dos and don’ts for yourself.

    Kevin Funk – Using Modern CMake with Qt

    Kevin gives a compact and easy-to-follow introduction how to write CMakeLists.txt files with modern CMake (versions 3.x). Loyal readers will know most of the tips from the CMake special in Episode 4 of my newsletter.

    Enabling AUTOMOC merges all the files generated by moc into one big source file (one-big-file approach). The alternative is to have moc generate a file for each header file containing a Q_OBJECT macro (many-small-files approach). Kevin saw a 5% speedup with the one-big-file approach over the many-small-files approach. The overhead of creating a new compile process for each moc file outweighs the gains from building individual moc files in parallel.

    Craig Scott makes the opposite observation in Section 30.3.1 Moc in his book Professional CMake (6th Edition): “If the number of classes processed by AUTOMOC […] is very large, […] it can make larger builds less efficient, so it may be desirable to have the generated files compiled individually to take advantage of build parallelism and reduce resource requirements.”

    My observations are more in line with Craig’s. However, I haven’t done any measurements. So, Kevin’s advice may depend on the concrete situation.

    Daniel Pfeifer – Effective CMake

    Yes, this is the same Daniel Pfeifer who patiently helped me with my first CMake steps. Many of Manuel’s dos and don’ts (see here) are extracted from Daniel’s talk.

    Daniel covers a wide range of CMake topics from basics over best practices for real-life projects to packaging and testing in just under 90 minutes. His talk is packed with tons of invaluable advice but can be a bit overwhelming. I still need to stop the video regularly and read up on the topics in Craig’s Professional CMake book.

    My Posts about CMake


    I have written four articles about CMake with a special focus on Qt.

    Cmake Target_link_libraries Static Example

    CMake Cross-Compilation Based on Yocto SDK. I assume that you have created an SDK from your Yocto build. Then, I walk you through writing a toolchain file step by step. The toolchain file for an i.MX6 SoC is used during cross-building the Qt application.

    Deploying Qt Projects to Embedded Devices with CMake. QtCreator allows you to cross-build a Qt application, deploy it to the target embedded system and run it there – all with one command. The QtCreator based on Qt 5.12 could not generate all the information required for deployment from the CMakeLists.txt files. I describe a workaround. Newer QtCreator and CMake versions are better integrated and don’t need the workaround any more.

    Benefits of a Relocatable Qt. Starting with version 5.14, Qt is relocatable. I show how to relocate Qt from a build server to a developer PC and from the developer PC to the target system. The second step demands special treatment of rpaths, which CMake provides.

    Target_link_libraries Cmake Example Questions

    Creating Simple Installers with CPack. This post is a follow-up to my earlier post Benefits of a Relocatable Qt, where I showed how to relocate Qt from a build server to a developer PC and finally to an embedded system. Relocation became very easy with Qt 5.14. My new post fixes two problems. First, I replace the absolute install rpath by an rpath relative to the application’s directory. Second, I use CPack to create a gzipped tarball instead of doing that manually. CPack also allows to create RPM and DEB packages or UI installers like the Qt Installer Framework (Qt IFW).