Where to place CMake macro definitions? - c++

I'm writing an application that relies on the Poco project. I just need a few sub modules but they use macros defined by the Poco project which are stored in a cmake folder at the root of the Poco folder structure.
I don't want to drag the whole Poco folder as I don't want to link my project to the whole Poco framework. How can I make those macros available to my project?

I'm not sure to well understand what you need. But why not simply include de file containing the macros by this way with cmake ?
include(path/to/Poco/cmake/macros.cmake)

Take the Poco project
Open the main CMakeLists.txt of Poco and comment (with #) all the add_subdirectory commands for the directories you don't need.
Try to build Poco
If it fails, add back the directories which contains the missing dependencies (in short, you might think you don't need a directory, but it might be that one of the directories you need depends on another directory)
When it builds, you can delete all the directories for which you have removed the command add_subdirectory

Related

how to link third-part library in cmake

I'm currently work with the project that chosen the CMake as the build system.
Nonetheless, I'm not very familiar with CMake. I spent much time on including the third-party library, the result is not very prefer. Could someone provide a way to fix my scenario?
My project tree is given in following section:
|--->top-Level
|--->ThirdLib
|------>Lib1
|---------->DLL
|---------->Include
|---------->LIB
|------>Lib2
|---------->DLL
|---------->Include
|---------->LIB
|--->UseThirdLib
|----->test.h //this file will used third-part lib
it seems u need some basic cmake tutorial?
https://cmake.org/cmake/help/latest/guide/tutorial/Adding%20a%20Library.html
target_include_directories
target_link_libraries
in Top level CmakeLists.txt
include_directories(${PROJECT_SOURCE_DIR}/ThirdLib/Lib1/include)
include_directories(${PROJECT_SOURCE_DIR}/ThirdLib/Lib2/include)
target_link_directories(your_target_name ${PROJECT_SOURCE_DIR}/ThirdLib/Lib1/lib)
target_link_directories(your_target_name ${PROJECT_SOURCE_DIR}/ThirdLib/Lib2/lib)
And all .dll should be placed in the same folder as executable or env:PATH should refer to folder with .dlls

How do I scaffold a new C++ project using CMake?

Is there a way to quickly scaffold a basic C++ CMake project using CMake itself? For examples in an empty directory calling cmake new then CMake asks a few questions e.g. project name, lisence and generator. Then CMake generates all the required files and directories, e.g. CMakeLists.txt file, src directory and probably initialize it as Git repository.
I don't know of such features and I don't see a point to add scaffolding into CMake itself. There are free and popular tools specifically for scaffolding purpose, so I suggest you to go to yeoman or slush generators search pages and search for cmake.
You may write a CMake function to create an empty project with a specific layout.
file command helps you to create files and directories.

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.

CMake: target_include_directories() prints an error when I try to add the source directory itself, or one of its subdirectories

I am writing a C++ library (header-only) and am using CMake to generate my (Visual Studio) project and solution files. I'm also writing a test suite, which is part of the same CMake project.
My problem occurs when I call target_include_directories() on the target that represents my header-only library, so that consumers of my library may find its header files. I get the following error message (even though generation is NOT aborted).
CMake Error in CMakeLists.txt:
Target "Fonts" INTERFACE_INCLUDE_DIRECTORIES property contains path:
"D:/Projects/GPC/fonts/include"
which is prefixed in the source directory.
(D:/Projects/GPC/Fonts being the top-level directory of my library project. Btw the problem remains if I move my header files to the top directory.)
The offending line in my CMakeLists.txt is this (adapted for simplicity):
target_include_directories(Fonts INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include")
I do not understand what I'm doing wrong. Without target_include_directories(), code of consumer projects simply can't include my header files (unless in installed form, but I haven't gotten to that yet, and in any case I want to be able to use my library from its build tree, without installation.)
I feel like I'm missing something basic here; yet I've searched for hours without finding a solution or explanation.
The origin of the problem is not the target_include_directories command itself, but the attempt to install a target that has a public or interface include directory prefixed in the source path (i.e. the include directory is a subdirectory of your ${PROJECT_SOURCE_DIR}.)
While it is perfectly fine and desirable to use absolute paths when building the library from scratch, a third party library that pulls in a prebuilt version of that library will probably want to use a different include path. After all, you do not want all of your users to mirror the directory structure of your build machine, just to end up in the right include path.
CMake's packaging mechanism provides support for both of these use cases: You may pull in a library directly from the build tree (that is, check out the source, build it, and point find_package() to the directory), or from an install directory (run make INSTALL to copy built stuff to the install directory and point find_package() to that directory). The latter approach needs to be relocatable (that is, I build and install on my machine, send you the resulting directory and you will be able to use it on your machine from a different directory structure), while the former is not.
This is a very neat feature, but you have to account for it when setting up the include directories. Quoting the manual for target_include_directories:
Include directories usage requirements commonly differ between the
build-tree and the install-tree. The BUILD_INTERFACE and
INSTALL_INTERFACE generator expressions can be used to describe
separate usage requirements based on the usage location. Relative
paths are allowed within the INSTALL_INTERFACE expression and are
interpreted relative to the installation prefix. For example:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
$<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
)
The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions do all the magic:
$<INSTALL_INTERFACE:...>
Content of ... when the property is exported using install(EXPORT), and empty otherwise.
$<BUILD_INTERFACE:...>
Content of ... when the property is exported using export(), or when the target is used by another target in the same buildsystem.
Expands to the empty string otherwise.

CMake and Config/Modules find_package

I'm developing a lib and now trying to make it usable through cmake find_package keyword.
Using the config mode works fine.
I've put the CPackConfig.cmake generated by cmake inside the installation folder of my lib by naming it log++Config.cmake and it can be found in my project. Fine.
But this method is not satisfying. I need to define my own variables such as lib dependencies needed to link and some custom macros, and didn't found any way to embed this inside the CPackConfig.cmake.
So now I'm trying to use the module mode of find_package. My concern is that I can't find any way to have cmake use my Findlog++.cmake without putting it inside cmake installation folders (which is awfully ugly).
I've found some posts telling to just put this file inside my project root but it's almost as ugly as modifying cmake itself.
Is there a way to have my Findlog++.cmake file somewhere inside my lib folder and have cmake finding it without setting the CMAKE_MODULE_PATH variable?
You seem to be confused between CPack and 'config file packages'. First, understand that they are separate and different. Then read
http://www.cmake.org/cmake/help/v3.0/manual/cmake-packages.7.html#creating-packages
http://www.cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html
to learn about usage requirements and inclusion of macros etc.