How to build many different packages with CMake - c++

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++.

Related

How to install the C++20 range library from github

I would like to use the range-v3 library in my project, but i don't understand how. The installation description says the following:
This library is header-only. You can get the source code from the
range-v3 repository on github. To compile with Range-v3, just #include
the individual headers you want.
Does that mean I can copy and paste the needed header files and add the filepath to my CMake file? I am a bit confused, because I never included third party library.
Note: please see hythis' answer for a better solution.
Does that mean I can copy and paste the needed header files and add the filepath to my CMake file?
Basically, yes. First git clone to <path_to_range_v3>. Then include these lines into CMakeLists.txt:
add_library(range_v3 INTERFACE IMPORTED)
set_target_properties(range_v3 PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES <path_to_range_v3>/include)
target_link_libraries(your_target PUBLIC range_v3)
I'm not sure why Evg suggested what they did, I don't even think in 2019 you were forced to create your own CMake interface with ranges-v3 (see here, the file existed way before hand). Regardless, don't use Evg's solution, ranges-v3 is a good header only library, and in order for a header only library to be good it must provide CMake integration.
Header only libraries do not mean the authors do not provide CMake support, or even avoid CMake themselves. Bad authors do this, as you've probably experienced by having to ask this question in the first place.
To properly integrate with Ranges V3, use a packagemanager (though some package managers screw the process up depending on how their custom CMake files are configured) such as Conan or vcpkg and integrate with their respective CMake solutions, or add the project as a git submodule (though you could git clone it as well) then in your CMakeLists.txt:
add_subdirectory([path to submodules]/range-v3)
...
target_link_libraries(my_target [SCOPE] range-v3::range-v3)
It can be hard to figure out actual targets for libraries if the authors don't spell out how to use their projects in a CMake project, and I don't blame any one making an SO post about it, it's a pain.
Generally if the project has a CMakeLists.txt file, it probably has static-library/sub_directory cmake integration, but some libraries only have install targets, thus are unusable when baked into your source code with out editing their CMakeLists.txt
To check if this is the case, or if you can actually use the targets, if you can't find any CMake documentation about how to use the library (which I couldn't) do the following:
Look inside the CMakeLists.txt file
Find a project alias usually in the form of project_name::project_name. This is how I found range-v3's project alias.
If you can't find alias (via searching for ::), find the actual target name for the library (and try to use this directly), sometimes this isn't exported though (hidden in a sub directory from the top cmake file). OpenCV doesn't use :: for example, and instead each component target is marked with opencv_[component name] but still exported.
If the project has not been configured to be properly used as a submodule and is otherwise meant to be used as a static library, submit an issue or PR to the given repository, this is a bug.

Generating dll from an existing code on Windows using CMake and VS

I have downloaded an SDK written in C++ (OPC UA) that creates a .exe file on compiling with Visual Studio 2015. It has a bunch of CMake files. How could one see if it is possible to generate a .dll from such an SDK? Do the CMake files have this information or should there be any macros inside the headers I would have to search for ? The SDK has Visual Studio sample projects (.sln) that I am using to create .exe.
The CMakeLists.txt looks like this
project(uasdk)
cmake_minimum_required(VERSION 2.8.0 FATAL_ERROR)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
include(CMakeDependentOption)
include(MessageUtils)
display_project_header("true")
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src")
add_subdirectory(src)
endif ()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/examples")
add_subdirectory(examples)
endif ()
# set CMAKE_INSTALL_MESSAGE to LAZY by default to hide 'Up to date' output when building INSTALL target
if (NOT ${CMAKE_VERSION} VERSION_LESS "3.1")
set(CMAKE_INSTALL_MESSAGE LAZY CACHE STRING "")
set(CMAKE_INSTALL_MESSAGE_VALUES "ALWAYS;LAZY;NEVER")
set_property(CACHE CMAKE_INSTALL_MESSAGE PROPERTY STRINGS ${CMAKE_INSTALL_MESSAGE_VALUES})
endif ()
The questions that already have been asked regarding this topic are from the people who are writing their own code. I intend to use the code from the SDK. Apart from changing the CMAKE file to include the dll do I need to make changes in the source code as well?
It has a bunch of CMake files. How could one see if it is possible to generate a .dll from such an SDK? Do, the CMake files have this information or should there be any MACROS inside the headers I would have to search for ?
If the CMake project generates a library, then the statement add_library must appear somewhere. Note, however, that hierarchies of CMakeLists.txt files are possible, for example, the CMakeLists.txt you included adds two subdirectories. Consider the CMakeLists.txt files in there as well. Since an executable is generated, a call to add_executable must appear somewhere as well.
I intend to use the code from the SDK. Apart from changing the CMAKE file to include the dll do I need to make changes in the source code as well?
I am not familiar with this SDK, but I would guess that examples contains the sources for the executable and src contains the sources for a library. If you just want to try something out, you can modify the example code or add a new example. In this case, you only have to modify the CMakeLists.txt in the examples directory (i.e., add your new source code file).
If you want to use the SDK as external dependency, check whether there is a FindNameofmySDK.cmake included in the CMake modules list or whether there is a NameofmySDK-config.cmake somewhere in the SDK sources or your installation. In this case, you can create a CMake project for your application and use find_package to look for the SDK.

Convert from Xcode to CMake

I have a C++ project that I initially developed using Xcode on my Mac and I would like to set up the very same project using CMake. The project makes use of some external libraries, including eigen and boost. Xcode has a rather long list of Build Settings, including paths to external libraries, specification of the compiler version, additional linker flags, compiler optimization level, etc... and I am wondering where all of this information goes in the CMakeLists.txt file. I've searched extensively for help on this but have found precious little. I am new to CMake and have never written make files before. If there were a utility that could convert my Xcode project into a CMake project, that would be ideal. But I would be very glad to know of a tutorial on this, or to have some specific guidance. Any help on this would be greatly appreciated.
Conversion Strategy
I am pretty sure that the easiest and fastest way to move to CMake is a mixture of looking at comparable projects that link the same dependencies, and maybe copying a few relative file paths to your source files from XCode.
A well-written CMakeLists.txt that uses Eigen and Boost can be very small (and platform-independent).
One reason for this is CMake has a very different way to use dependencies.
For well-known libraries such as Boost, CMake includes scripts to include headers and link libraries.
Minimal CMakeLists.txt
A minimal example may look like this:
find_package(Eigen3 REQUIRED)
find_package(Boost REQUIRED COMPONENTS system)
add_executable(
app
src/main.cpp
)
target_include_directories(
app
${Eigen3_INCLUDE_DIRS}
${Boost_INCLUDE_DIR}
)
target_link_libraries(
app
${Boost_LIBRARIES}
)
Example Projects
For Eigen, there is no such pre-installed script that can be called by find_package.
Here are two real-world example projects that link Eigen and Boost: https://github.com/ompl/ompl/blob/master/CMakeLists.txt
https://github.com/roboticslibrary/rl
Here is an example for a find script for Eigen.
As a piece of advice, some CMake projects are out there are convoluted and use old syntax, newer project files tend to use small letters in commands.
If it happens that directly target linking libraries doesn't work, you'll have to write your own Find*.cmake files by yourself.
Here's a spec of what you should cover to make it (this is just one approach):
Imagine you have a library XYZ:
Your file
FindXYZ.cmake should have as a result a set of variables to use:
XYZ_LIBRARIES
XYZ_INCLUDE_DIR
For example:
set(XYZ_LIBRARIES ${SOME_PATH_TO_LIBRARY1} ${SOME_PATH_TO_LIBRARY2})
find_path(XYZ_INCLUDE_DIR NAMES xyz/xyz.h HINTS ${PLACE_WHERE_INCLUDE_SHOULD_BE}
PATH_SUFFIXES include
)
From your main cmake maybe you 'use' it:
find_package(XYZ REQUIRED)
# Now we use both _INCLUDE_DIR and _LIBRARIES
include_directories(SYSTEM "${XYZ_INCLUDE_DIR}")
# TARGET_NAME is the current target, the 'client' of XYZ
# append XYZ to our list of libraries to link
target_link_libraries(${TARGET_NAME} ${XYZ_LIBRARIES})
I'm surely missing details but that's the general idea. Here are some cmake scripts that I know work in a big project:
Example with OpenSSL
Find:
https://github.com/highfidelity/hifi/blob/Android/cmake/modules/FindOpenSSL.cmake
Client (in this case is a library that indeed needs OpenSSL):
https://github.com/highfidelity/hifi/blob/Android/domain-server/CMakeLists.txt

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.

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.