decoupling app and libraries in CMake project - c++

I had a project that was configured to be:
CMake Project
static Lib A src (depends on B)
static Lib B src (depends on Qt)
App src (statically links with LibA)
Each of these folders had its own CMakeLists.txt but all were part of the same CMake project. Things were working fine.
Then for the purpose of more easily separating the library source and the app source into different source code repositories, I started to learn about the creation of CMake packages and performing find_package on LibA. I rearranged things so that now the libraries are their own CMake project, which requires I run "cmake --build . --target install" to put the packages in a common area (not in the build folder).
The app similarly became its own CMake package, and I thought I would only need to find_package(LibA). It turned out I also needed to find_package on LibB because there was one header that the App needed. But the unexpected part is that the App needed to find_package on Qt5Widgets, Qt5Core, and Qt5Gui just as LibB did. That's the part that I don't quite understand. When everything was one giant project, the App's CMakeLists.txt only needed to link against LibA. Was all of the other stuff just taken care of without me knowing? Am I naive to think that performing find_package on LibA and LibB would somehow cause the Qt libs to be linked in to the App as well?
This might be a lousy question, because I have things working again. I just want to make sure I understand the why.

Using static libraries in C++ does not pull in their dependencies, so they have to be specified explicitly while linking the executable (as compared to dynamic ones).
A static library is essentially a pre-compiled archive of functions (an object file), which get linked into your applications by your C++ linker in a similar way as any other object file would. As such, it does not include information about its dependencies.
A shared (dynamic) library is a more complex (and generic) thing, allowing to load and link code run-time. This is done by a dynamic linker, which will also bring it any dependencies of the loaded library recursively.
For this reason, if you want to avoid specifying the dependencies explicitly, a dynamic library might be a better choice (it might be a better choice for a variety of other reasons as well :) ).

Related

How do I statically link FFTW on windows?

During the setup of my project - when I knew even less than I do now about cmake - I was trying my hardest to link the FFTW library.
C:\\path\\to\\fftw-3.3.5-dll64 contains the .h files, .lib files (generated from .def files) and .dll files.
What I ended up doing was adding these links to my CMakeLists.txt:
add_executable(${TargetName} PRIVATE main.cpp)
target_include_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_libraries(${TargetName} PRIVATE libfftwf3-3)
After building this, the application was still not working. Eventually, I figured out that on opening the executable, windows was looking for the libfftw3-3 dll file. At the time I just wanted to get it working, so I copied the .dll files that are included with the library - even though this is shared/dynamic linking, not static linking.
I'm now trying to properly statically link the library; I removed the dll's from my build folder and filtered my CMakeLists.txt file down to:
add_executable(${TargetName} PRIVATE main.cpp)
target_include_directories(${TargetName} PRIVATE "C:\\path\\to\\fftw-3.3.5-dll64")
target_link_libraries(${TargetName} PRIVATE libfftwf3-3)
This builds, as I would expect it would. However, even though, in my CMakeLists.txt file, I've taken the steps to statically link the library, I'm still required to copy the dll's over in order for the executable to run (its dynamically linking still).
(Successful) verbose build output: https://pastebin.com/bbrZdd7r
The LIB files you generated from the DEF files are "stubs". They contain just enough code to load the DLL and call functions from it. They do not contain the actual FFTW code. You cannot statically link with these pre-built FFTW LIBs.
You will need to compile FFTW into a static library yourself first. It comes with a CMake build file where you can turn off BUILD_SHARED_LIBS.
edit: on review, your question is nearly identical to this one, with the same answer.
libs can be either static or dynamic. The one's generated (following the instructions in the README-WINDOWS file) are shared (they link to the .dll files inside the same folder.
With the windows binaries provided by FFTW, you cannot statically link (because all they provide are the dynamic libraries (.dlls). If you look at the file size of the .lib file, it's very small, because it's just a reference to the .dlls.
Follow the instructions on FFTW's windows page, for building the library from the source. Because you're now building the library yourself, you have the option to turn of "shared-library" and make a "static" lib.

Embedding library and it's includes via CMake

I'm creating a very small project that depends on the following library: https://github.com/CopernicaMarketingSoftware/AMQP-CPP
I'm doing what i always do with third-party libraries: i add their git repo as a submodule, and build them along with my code:
option(COOL_LIBRARY_OPTION ON)
add_subdirectory(deps/cool-library)
include_directories(deps/cool-library/include)
target_link_libraries(${PROJECT_NAME} coollib)
This has worked perfectly for libraries like Bullet, GLFW and others. However, this AMQP library does quite an ugly hack. Their include directory is called include, but in their CMake install() command, they rename it to amqpcpp. And their main header, deps/cool-library/amqpcpp.h, is referencing all other headers using that "fake" directory.
What happens is: when CMake tries to compile my sources which depend on deps/cool-library/amqpcpp.h, it fails because it's not finding deps/cool-library/amqpcpp/*.h, only deps/cool-library/include.
Does anyone have any idea how i can fix this without having to bundle the library into my codebase?
This is not how CMake is supposed to work.
CMake usually builds an entire distributive package of a library once and then installs it to some prefix path. It is then accessible for every other build process on the system by saying "find_package()". This command finds the installed distibution, and all the libs, includes etc. automagically. Whatever weird stuff library implementers did, the resulting distros are more or less alike.
So, in this case you do a lot of unnecessary work by adding includes manually. As you see it can also be unreliable.
What you can do is:
to still have all the dependencies source distributions in submodules (usually people don't bother doing this though)
build and install each dependency package into another (.gitignored) folder within the project or outside by using their own CMakeLists.txt. Let's say with a custom build step in your CMakeLists.txt
use "find_package()" in your CMakeLists.txt when build your application
Two small addition to Drop's answer: If the library set up their install routines correctly, you can use find_package directly on the library's binary tree, skipping the install step. This is mostly useful when you make changes to both the library and the dependent project, as you don't have to run the INSTALL target everytime to make library changes available downstream.
Also, check out the ExternalProject module of CMake which is very convenient for having external dependencies being built automatically as part of your project. The general idea is that you still pull in the library's source as a submodule, but instead of using add_subdirectory to pull the source into your project, you use ExternalProject_Add to build it on its own and then just link against it from your project.

creating a static library and linking using Cmake

I have a application which need to use two libraries (pugixml and lua) and need to be an multi-platform build capable. I am trying to use Cmake for this. Since I have three different solution (two for creating static libraries and one solution which actually uses that libraries). So far what I do is run Cmake for those two libraries and copy those static libraries manually to the lib folder into application and run cmake again.
I need to reduce the three step and make it as a single step so that I can handle the multi-platform build in a single shot.
I need to know, should we need to create a dynamic link library or shared library or static library for these kind of operation?
And need help on how to do it. I tried creating the source folder of pugixml and copy the cpp/hpp/h file and wrote a cmakelists file like
set(HEADERS pugixml.hpp pugiconfig.hpp)
set(SOURCES ${HEADERS} pugixml.cpp)
add_library(pugixmlLib STATIC ${SOURCES})
target_link_libraries(pugixmlLib pugixml)
On the solution I could see my application project and pugixml project, but on my application project linker property I could find pugixml library.

CMake - Depending on another cmake project

I have the following structure to a project I am working on:
---Library1
------build
------include
------src
------CMakeLists.txt
---Library2
------build
------include
------src
------CMakeLists.txt
---Executable1
------build
------include
------src
------CMakeLists.txt
Library1 is a library I am developing that needs to link with Library2 which is a 3rd party library. When I build Library1, I need it to automatically build Library2 and link with it. Executable1 will need to build and link with Library1. I'm not sure how to do with with Cmake, and I was wondering if anyone could guide me in the right direction. I think I may need to use the add_dependencies command or add_subdirectory but I'm not sure how to go about using them and making sure they are linked to my library. Any help would be appreciated.
I'd think the best commands here are likely to be add_subdirectory (as you suspected) and target_link_libraries.
I guess with your directory structure, I'd expect to see a "top-level" CMakeLists.txt in the root. In that CMake file, you'd invoke the subdirectories' CMakeLists using add_subdirectory.
I imagine both Library1 and Library2 are actual CMake targets, included via add_library, and similarly you have add_executable(Executable1 ...). In this case, you can add the following to Library1/CMakeLists.txt:
target_link_libraries(Library1 Library2)
CMake now automatically links Library2 whenever Library1 is specified as a dependency. If Library2 is modified, then it will be rebuilt automatically before being linked to Library1 again.
Likewise in Executable1/CMakeLists.txt you can then do:
target_link_libraries(Executable1 Library1)
Probably the only thing to watch for here is that the order of the add_subdirectory commands would need to be
add_subdirectory(Library2)
add_subdirectory(Library1)
add_subdirectory(Executable1)
so that the dependencies are defined before they're referred to in the target_link_libraries calls.
A final point which seems odd to me is that you have a build directory per target. Normally there should only be a need for a single build directory (preferably outside the source tree).

How to easily include headers from library dependency in cmake circa v2.8.8

I'm experimenting with CMake a bit for a C++ repository, but I'm running into some trouble trying to make it easy to build applications against libraries in the same source tree without a lot of extra CMake code.
The layout of the source tree is basically the following:
ROOT
libs/
lib1/
lib2/
lib3/
apps/
app1/
app2/
app3/
The libraries are independent of one another, and the applications may link against one or more of the libraries.
Currently I have a root CMakeLists.txt that lists out each application and library as a subdirectory so that if the library is changed and the application is rebuilt, so is the library. This works fine and CMake links it in without me having to specify where the library lives, but I don't see a way to do something similar for include directories.
Is there a common way to handle this? I'd prefer not to have each application's CMakeLists.txt have to manually list out the path to the libraries it needs.
If you are not afraid of making more headers available than you actually need for each application, you could list all lib directories in an INCLUDE_DIRECTORIES statement e.g. in the CMakeListst.txt adding all application sublists. But there is no such concept of managing "belonging" include folders per target built-in.
This question is pretty old. It was asked on 2012-07-18. I'm adding an answer here to attempt to explain some history. Warning: I may have gotten it wrong or misunderstood the history.
At that time, the latest non-release-candidate relase was CMake v2.8.8 (released on 2012-04-18). The INCLUDE_DIRECTORIES target property already existed in v2.8.8, but there was no corresponding INTERFACE_INCLUDE_DIRECTORIES target property yet. Its target_link_libraries documentation didn't say anything about a target automatically adding the include directories of the targets it depended upon.
About ten months after this question was asked (2012-07-18), CMake v.2.8.11 was released. It added the target_include_directories command signature with the INTERFACE|PUBLIC|PRIVATE argument, and added the INTERFACE_INCLUDE_DIRECTORIES target property.
So you can create a target B, specify public/interface include directories for it, and then make a target A depend on it via target_linK_libraries, and then A will automatically add/use the include directories of B. That can be made transitive by making the link public/interface, or non-transitive by making the link private.
You can find Kitware's list of software releases here, and a list of the documentation revisions here.