cmake use library target in added executable - c++

I have started a new c++ project which has several executables and a relatively large amount of shared code.
root
CMakeLists.txt
Common
Application1
Application2
....
So the multiple applications all get compiled with their unittests without issues. But since they depend on the shared code in Common I have the recompile the shared code for each project once I update something there.
So I am wondering if it would be possible to add the library target. And build that first. And then I link my code to that library.
This seems like a relatively normal thing to do but I can't find anything about it on google.
Any help is appreciated.

Yes this is possible.
You have to add a CMakeLists file to the Common folder and in it you compile it as a library
# Add required source files.
add_library(Common ...)
# Include required header files. They must be public to be recognized where they are needed.
target_include_directories(Common PUBLIC ...)
Then in the project's CMakeLists you use:
add_subdirectory(Common) // Will call the other CMakelists
...
# Link to the required libraries.
target_link_libraries(Application Common)

Related

Where does target_link_libraries look for the required files?

I am building a project from source and am trying to understand what is happening in the CMakeLists.txt files.
Where exactly is target_link_libraries looking for the required library files?
The specific CMakeLists.txt file I have has:
target_link_libraries(MyApplication PRIVATE
Magnum::Application
Magnum::GL
Magnum::Magnum
Magnum::Shaders)
I found folders that have the names GL and Shaders in a directory called Magnum in the project, and they have a collection of header files in them. I believed that target_link_libraries is telling CMake to include the libraries in the GL and Shaders folder.
However, I cannot seem to find a corresponding folder for Application, hence my line of reasoning must be flawed.
I do know target_link_libraries is doing something related to allowing the finally-put-together program to be able to use a set of libraries.
What exactly does target_link_libraries do? Where does it look for the required files in order to be able to use the libraries it needs to?
target_link_libraries doesn't link anything automatically. You should have a target previously created via add_library (or add_executable), where all files are listed.
The way these targets added into your CMake project may differ. E.g. you may have a library source files with CMakeLists.txt configuration (where the said add_library command is) under some folder libs/mylib. Then in your CMakeLists.txt you may have the library added with add_subdirectory(libs/mylib). Another option is to add the library with find_package.
In your specific case, you pass targets to target_link_libraries(). Targets with a shape like Magnum::Application etc are either imported targets or ALIAS targets.
From what you say, it seems than Magnum is vendored into your project, so I guess your are linking ALIAS targets, like the one defined here https://github.com/mosra/magnum/blob/cfc02599e54e02337dd56bb61f70b2e61eb9ce8d/src/Magnum/CMakeLists.txt#L295
Targets defined by add_library() or add_executable() in CMake are an abstraction carrying several informations, including location of files.

How to build many different packages with CMake

I'm trying to put together a CMake project where I have different packages that I need to build. This is my desired structure:
package1
src
file.cpp
test
file_test.cpp
package2
src
file2.cpp
test
file2_test.cpp
CMakeLists.txt
main.cpp // this will be removed later
This is my current CMakeLists.txt file:
cmake_minimum_required(VERSION 3.10)
# set the project name
project(cppApp)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
include_directories(${PROJECT_SOURCE_DIR})
# add the executable
add_executable(cppApp main.cpp ./package1/src/file.cpp ./package2/src/file2.cpp)
So the question is firstly, is a library considered a package in CMake? This question comes from someone who have done a lot of Java where I would typically call that a package and not a library. But does it in CMake?
Also, how do I in CMake include all files in the "packages" to be built instead of hard coding in the files as an executable? If I create many .cpp/.h files I want to automate this as much as possible.
I have seen that some other projects use a CMakeLists.txt file inside each "package", is this ideal? And is this good practice?
If you have a better suggestion according to some standard I should use to structure my project I would like to know a good one as well.
So the question is firstly, is a library considered a package in
CMake? This question comes from someone who have done a lot of Java
where I would typically call that a package and not a library. But
does it in CMake?
Your definition of package in Java is not quite accurate. Package is just a mean to organize classes in Java in namespace manner. It could be classes of a separate library, but nothing prevents you from using different packages within the same project. It has nothing to do with CMake packages, where each package is actually a whole separate project.
I have seen that some other projects use a CMakeLists.txt file inside
each "package", is this ideal? And is this good practice?
CMakeLists.txt files in subdirectories merely define new subset of rules for those directories. In order to make your CMake project respect those rules, you add such directory with add_subdirectory. It's not neccessarily a separate library, you can make subset of rules for parts of a single project, and it's usually a good idea to do that if some files are really that different.
CMake have something called add_library(lib) and is those kinds of directories considered a library?
add_library creates so-called CMake target, just like add_executable. The targets can be linked with each other with use of target_link_libraries, and that will indeed be considered a library in terms of C++.

Including SO files without headers

I have recently involved myself in making a basic game engine. I have decided to place all of my middleware into an Externals directory, where a bash script builds all my middleware into shared object files in the Binaries directory.
In my CmakeLists.txt file, I am able to link these libraries into my main executable, like so:
add_library (glfw SHARED IMPORTED)
set_target_properties (glfw PROPERTIES IMPORTED_LOCATION
${ENGINE_BINARIES_DIR}/Libraries/Shared/libglfw.so.3.2
)
...
target_link_libraries (Engine glfw)
However, when I try to include GLFW/glfw3.h in my main file, it fails to compile. This makes sense, because there is no glfw3.h file; however, all other attempts at including glfw into my project have failed.
TL ; DR
What is the best way to include headers from an existing shared object library? Is it possible to achieve this without an includes/glfw directory, or would one need to modify their code / project structure in order to load these functions?
I realize my mistake now.
I did a bit of research on shared objects / DLL's and building GLFW before posting this question; however, I believe I was still rather confused as to what a shared library was and how it worked.
I now realize that you do, in fact, need to include the header file; as it contains the declarations of the middleware code, while the libglfw.so.3.2 library contained the definitions of the code.
I have thus solved my issue by keeping the .so file in the Libraries/Shared directory and the GLFW header file in the External directory, and using CMake to point the compiler / linker to both.

decoupling app and libraries in CMake project

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 :) ).

How to use external DLLs in CMake project

I've been searching over the internet but I couldn't find anything that would answer my question (or I don't know what to search for).
Anyway here's my issue:
I want to use 3rdParty libraries (.dll files) in my CMake project. Library (https://github.com/pitzer/SiftGPU) that I want to include is open source and is also available in binary which I would like to use and also uses CMake as build tool if that's relevant.
I hope I was clear enough.
First, edit your CMakeLists.txt to include your third party library. You'll need two thing: path to header files and library file to link to. For instance:
# searching for include directory
find_path(SIFTGPU_INCLUDE_DIR siftgpu.h)
# searching for library file
find_library(SIFTGPU_LIBRARY siftgpu)
if (SIFTGPU_INCLUDE_DIR AND SIFTGPU_LIBRARY)
# you may need that if further action in your CMakeLists.txt depends
# on detecting your library
set(SIFTGPU_FOUND TRUE)
# you may need that if you want to conditionally compile some parts
# of your code depending on library availability
add_definitions(-DHAVE_LIBSIFTGPU=1)
# those two, you really need
include_directories(${SIFTGPU_INCLUDE_DIR})
set(YOUR_LIBRARIES ${YOUR_LIBRARIES} ${SIFTGPU_LIBRARY})
endif ()
Next, you can do the same for other libraries and when every libraries are detected, link to the target:
target_link_libraries(yourtarget ${YOUR_LIBRARIES})
Then you can configure your project with CMake, but as it doesn't have any magic way to find your installed library, it won't find anything, but it'll create two cache variables: SIFTGPU_INCLUDE_DIR and SIFTGPU_LIBRARY.
Use the CMake GUI to have SIFTGPU_INCLUDE_DIR pointing to the directory containing the header files and SIFTGPU_LIBRARY to the .lib file of your third party library.
Repeat for every third party library, configure again and compile.