CMake target_include_directories and target_compile_definitions alternative - c++

CMake 2.8.11 introduces target_include_directories and target_compile_definitions. However some of the devices I am working one has 2.8.9. And I don't want to compile and build latest CMake there. So what is the alternative that I can use conditionally for those devices ?
How to check whether this cmake have target_include_directories or not from inside the CMakeLists.txt ?

There is no easy way to get this functionality on earlier CMake versions, as the respective target properties that they are based on (INTERFACE_INCLUDE_DIRECTORIES and INTERFACE_COMPILE_DEFINITIONS) are missing.
This is crucial as CMake uses these target properties to automatically propagate public and interface fields to dependent targets. Emulating this behavior from CMake code is rather difficult. For an in-house project we built a system that does just this a couple of years back before CMake supported it. This basically requires writing your own replacement functions for add_library and add_executable that handle the propagation in the background through user defined properties. All targets in the system then must use the replacement functions instead of the original CMake ones for the system to work. I would strongly recommend reconsidering your CMake upgrade policies before going for this option though.
The quickest way to check whether you can use these functions is by doing a cmake_minimum_required (which you anyway should always do for all projects). If you want to make use of the commands, simply require at least 2.8.11. If you cannot make that requirement, use of the functions is out of the question in the first place and you will need to come up with an alternative. In which case it does not make much sense to check for their existence to begin with.

ComicSansMS is correct about emulation not being possible prior to 2.8.11.
You can use
if (COMMAND target_include_directories)
endif()
or
if (COMMAND target_include_directories AND COMMAND target_compile_definitions)
endif()
as your test of whether the commands are available.

How to check whether this cmake have target_include_directories or not from inside the CMakeLists.txt ?
if (NOT CMAKE_VERSION VERSION_LESS 2.8.12)
target_include_directories(...)
else()
# Not available
endif()

Related

AHow to use different compilers for projects with CMake? [duplicate]

It seems like CMake is fairly entrenched in its view that there should be one, and only one, CMAKE_CXX_COMPILER for all C++ source files. I can't find a way to override this on a per-target basis. This makes a mix of host-and-cross compiling in a single CMakeLists.txt very difficult with the built-in CMake facilities.
So, my question is: what's the best way to use multiple compilers for the same language (i.e. C++)?
It's impossible to do this with CMake.
CMake only keeps one set of compiler properties which is shared by all targets in a CMakeLists.txt file. If you want to use two compilers, you need to run CMake twice. This is even true for e.g. building 32bit and 64bit binaries from the same compiler toolchain.
The quick-and-dirty way around this is using custom commands. But then you end up with what are basically glorified shell-scripts, which is probably not what you want.
The clean solution is: Don't put them in the same CMakeLists.txt! You can't link between different architectures anyway, so there is no need for them to be in the same file. You may reduce redundancies by refactoring common parts of the CMake scripts into separate files and include() them.
The main disadvantage here is that you lose the ability to build with a single command, but you can solve that by writing a wrapper in your favorite scripting language that takes care of calling the different CMake-makefiles.
You might want to look at ExternalProject:
http://www.kitware.com/media/html/BuildingExternalProjectsWithCMake2.8.html
Not impossible as the top answer suggests. I have the same problem as OP. I have some sources for cross compiling for a raspberry pi pico, and then some unit tests that I am running on my host system.
To make this work, I'm using the very shameful "set" to override the compiler in the CMakeLists.txt for my test folder. Works great.
if(DEFINED ENV{HOST_CXX_COMPILER})
set(CMAKE_CXX_COMPILER $ENV{HOST_CXX_COMPILER})
else()
set(CMAKE_CXX_COMPILER "g++")
endif()
set(CMAKE_CXX_FLAGS "")
The cmake devs/community seems very against using set to change the compiler since for some reason. They assume that you need to use one compiler for the entire project which is an incorrect assumption for embedded systems projects.
My solution above works, and fits the philosophy I think. Users can still change their chosen compiler via environment variables, if it's not set then I do assume g++. set only changes variables for the current scope, so this doesn't affect the rest of the project.
To extend #Bill Hoffman's answer:
Build your project as a super-build, by using some kind of template like the one here https://github.com/Sarcasm/cmake-superbuild
which will configure both the dependencies and your project as an ExternalProject (standalone cmake configure/build/install environment).

Converting from qmake to cmake, how do I find libraries in the same way?

in qmake I can have something like this:
LIBS += -lopengl32 \
-lglu32
This will automatically find and link the OpenGL and GLU with my application. How can I do the same in cmake? Is it as simple as:
target_link_libraries(${TARGET_NAME} opengl32 glu32)
If so, how does cmake know where to find these libraries? Is there a way to do this that involves a find_libraries call instead? The above (if it works), would give me anxiety.
Yes, there is a way.
About the sample you provided:
target_link_libraries(${TARGET_NAME} opengl32 glu32)
In this case, when you just list libraries to be linked against, CMake will just pass them to the linker, without any additional work; it is the linker, who must find them.
About the CMake way of including libraries:
However, CMake may help you much much more. Pls take a look at the following code snippet, that represents the preferred way of finding libraries in CMake:
#NOTE: this is a complete & working CMakeLists.txt
project(my_opengl_program)
set(TARGET_NAME ${PROJECT_NAME})
set(TARGET_SOURCES my_opengl_program.cpp my_opengl_program.h)
add_executable(${TARGET_NAME} ${TARGET_SOURCES})
find_package(OpenGL REQUIRED)
target_link_libraries(${TARGET_NAME} OpenGL::GL OpenGL::GLU)
Instead of using find_library directly, use find_package. It will find the libraries you need (by employing find_library internally) and set various helpful variables for you.
Also, most of the packages will also define so-called import libraries, OpenGL::GL and OpenGL::GLU in your case, that can be used for linking. The wonderful thing about linking against the CMake targets is that your executable will inherit all relevant compile/link requirements from the target used for linking. Of course, "import libraries" are also CMake targets :)
Please note that there are NO additional compile/link options, include directories, compile definitions, etc... for your executable. Everything that is necessary is inherited from OpenGL::GL and OpenGL::GLU.
CMake also provides packages for many standard libraries (scroll down to "Find Modules").
About searching for libraries
You can always use find_library directly, and in that case, it is your responsibility to take care of all requirements the library imposes.
Determining the places to search for libraries may be quite complex, and is driven by various CMake variables, as well as parameters passed to find_library. In the simplest case, when no related CMAKE_* variables are changed, and when the find_library is called with basic syntax, like:
find_library(GL_LIB opengl32)
fund_library(GLU_LIB glu32)
Search for openGL32 and glu32 will be controlled by CMAKE_SYSTEM_PREFIX_PATH, CMAKE_SYSTEM_LIBRARY_PATH CMake variables.
In the end, here is the complete documentation for find_library, find_package, cmake supported libraries (scroll down to "Find Modules"), target_link_libraries
[update]
find_library vs find_package
The question was raised about the difference between find_library and find_package.
Briefly, these two commands do not "compete" but rather "complement" each other. One may think about find_library as a low-level interface for including libraries. In this context, find_package would be a much higher interface, that is easier to use. On the other hand, find_package requires additional support from the library maintainers, or from the CMake directly.
Digging a little deeper into the problem:
Suppose that some library is introduced using
find_library (SOME_OTHER_LIB some_other_lib_name). If the lib was found, the variable SOME_OTHER_LIB will contain the path to the library, which is enough for linking, using target_link_libraries.
But to really use the library, sources need to include SOME_OTHER_LIB specific headers, i.e. another find_path(...) needs to be introduced, to locate headers, followed by target_include_directories(...). Also, compile options required by the library also need to be extracted somehow, and introduced using target_compile_options(...)
Of course, if the SOME_OTHER_LIB is used on more than one place, all target_include_directories, target_compile_options, and target_link_libraries must be used all over.
The same process must be repeated for every foreign library that is used.
One can quickly spot the pattern, and this is exactly where find_package becomes handy. All that low-level work is hidden from the end-user (i.e. developer using CMake), and she/he is presented with a clean and unified interface. The downside is that find_package requires a "kind of driver" that will "drive" the process of including the foreign library. All libraries that are directly supported by CMake may be found on cmake-modules (scroll down to "Find Modules").
The icing on the cake, almost all find modules also create so-called "import libraries" (OpenGL::GL and OpenGL::GLU in your case) that are cmake targets holding all requirements of the 3rd party library. All those data are inherited by just linking against the import library, making the code much cleaner.
Unfortunately, there are no "enforcements" about the naming of created import libraries (just guidelines), so the only solution is to check the documentation. For OpenGL module, it can be found on FindOpenGL page.

Set LINK_FLAGS for INTERFACE libraries in cmake

I am working on a header-only C++11 library which uses modern CMake. By "modern," I mean not only using CMake v3.0+ but also trying to use as much as possible the best practices in Daniel Pfeifer's talk.
I have done some research on my question, but the answers are mostly regarding modifying the LINK_FLAGS directly in the global level, which I do not want to have. Right now, in my project, I require a minimum version of 3.9.0 of CMake because of some features I am using.
My question is about whether/how to add LINK_FLAGS coming from two of my dependencies: BLAS and LAPACK. Basically, I have the following excerpt from my CMakeLists.txt file:
cmake_minimum_required(VERSION 3.9.0)
project(polo VERSION 1.0.0 LANGUAGES C CXX)
find_package(BLAS REQUIRED)
find_package(LAPACK REQUIRED)
add_library(polo INTERFACE)
add_library(polo::polo ALIAS polo)
target_compile_features(polo INTERFACE cxx_std_11)
target_include_directories(polo
INTERFACE
$<BUILD_INTERFACE:${polo_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
target_link_libraries(polo
INTERFACE
${BLAS_LIBRARIES}
${LAPACK_LIBRARIES}
)
set_property(
TARGET
polo
PROPERTY LINK_FLAGS
${BLAS_LINKER_FLAGS}
${LAPACK_LINKER_FLAGS}
)
As far as I can understand from documentations of the FindBLAS and FindLAPACK modules, I need to inform my users at least about {BLAS,LAPACK}_LIBRARIES and {BLAS,LAPACK}_LINKER_FLAGS. For the former, I think I have handled the issue properly. However, for the latter, I need to use either set_target_properties or set_property. Between the two, the latter seems to give me a cleaner solution in that I can use both variables coming from Find{BLAS,LAPACK} modules together. When I try to build my library using the above solution, I get the obvious error:
CMake Error at src/CMakeLists.txt:32 (set_property):
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "LINK_FLAGS" is not allowed.
My question is two folds:
Should I use *_LINKER_FLAGS coming from the modules at all, and,
If yes, how should I integrate them cleanly into my CMake project?
As for the 2. above, I have seen some suggestions/answers for using target_link_libraries, but I am not sure whether that is the option to go for.
Thank you for your time!
First of all, I do apologize to the community for cross posting the issue.
Matthieu has tried helping me with two options:
Providing a helper function so that the consumers of the library could call the function to properly handle the LINK_FLAGS, and,
The IMPORTED library option, which he has kept as the final answer (please see the comments there for the motivation).
Unfortunately, neither of these solutions seem to work. The first one is not a clean way of informing the consumer about your dependencies. The second version seems to work with INTERFACE libraries, but any consumer that depends on the INTERFACE library that build an object, such as, e.g., a C-API of the header-only library that builds a SHARED library, has problems building and installing the IMPORTED library.
The solution seems to be to use CMake v3.13 and above, which, as of the posting date, is in the release candidate (rc3) state. Apparently, CMake v3.13 will be introducing INTERFACE_LINK_OPTIONS for such purposes.
EDIT. CMake v3.13 has been released.
The nice thing is that you can provide a helper .cmake for them (called polo-config.cmake).
One option inside the .cmake file is to create an IMPORTED library, which you hold the flags that you want, probably as PUBLIC this time, so that they are propagated to the next user.
Of course, you need to add the library properly, setting up the include paths, the path to the library...

CMake: set path to MPI headers and binaries manually

I am developing an MPI application which requires to be run with a specific implementation of MPI (let's call it MPIvA). On my workstation, another implementation of MPI (let's call it MPIvB) is installed.
My application is built using CMake and the find_library(MPI) obviously points to MPIvB. It compiles and runs without hassle.
I compiled MPIvA on my workstation. How can I make CMake use these headers and binaries?
CMake comes with a FindMPI module, that does all the heavy lifting for you.
In your CMakeLists.txt, instead of calling find_library(MPI), use find_package like so:
#### MPI
find_package(MPI REQUIRED)
if (MPI_FOUND)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
else (MPI_FOUND)
message(SEND_ERROR "This application cannot compile without MPI")
endif (MPI_FOUND)
Then wherever you link your application, link against the ${MPI_LIBRARIES}:
target_link_libraries(example-app ${MPI_LIBRARIES})
Now cmake will automatically find a MPI implementation in your system. If you have multiple different MPI versions, and want to specify which one to compile with, you can set the MPI_C_COMPILER and MPI_CXX_COMPILER variables to the corresponding mpicc and mpicxx compiler wrappers. The CMake module will then use those to figure out all the required compiler and linker flags itself.
Example:
cmake -DMPI_C_COMPILER=/usr/share/mvapich/bin/mpicc your-project-dir
To make sure cmake is using the correct MPI, start in a new empty build directory.
More information on the FindMPI module here: https://cmake.org/cmake/help/v3.0/module/FindMPI.html
In order to compile against MPIvA on your workstation, you'll need CMake to find those headers and binaries first. The following link describes how CMake's find_library's search order works: https://cmake.org/cmake/help/v3.0/command/find_library.html
I'd suggest adding MPIvA to the CMAKE_LIBRARY_PATH. See the top answer to the following question for an example:
How do I instruct CMake to look for libraries installed by MacPorts?
Well, this is not a new post but it may be useful to others in the future.
Even though the previous answers can also work, I think that the a better approach is to use the CMAKE_PREFIX_PATH option, ie sth like
CMAKE_PREFIX_PATH=~/my-libs-install-path ccmake ..
Now, some other comments:
All MPI libraries should be interchangeable, ie code that uses the MPI specification should compile and run with any MPI implementation (eg MPIvA and MPIvB which I am assuming are intelmpi,openmpi or mpich).
Regarding this answer (my reputation doesn't allow me to comment so I reply here):
find_package(MPI REQUIRED)
if (MPI_FOUND)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
else (MPI_FOUND)
message(SEND_ERROR "This application cannot compile without MPI")
endif (MPI_FOUND)
even though the functionality would be mostly as expected, the following is functionally equivalent:
find_package(MPI REQUIRED)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
The REQUIRED part in the findpackage(MPI REQUIRED) command will cause the command to fail if MPI is not found, so the if(MPI_FOUND) part is useless and the else clause will actually never be executed.
Finally, regarding the include_directories command, in my tests was not required if you are using targets, eg
target_link_libraries(my_app PUBLIC MPI::C)
is enough.
the built in cmake will interfere with your desired library more often than not, especially if you are using different clusters as usually default compilers are not the latest version you might need, the work around this is to have your own FindMYMPI.cmake and take the control.
Otherwise command line option or changing it with the ccmake GUI is also a possibility as provided in the above answers.
In this specific case, I succeeded using the following environment variable:
export MPI_HOME=/your/path/to/prefix
Please set it before using cmake, or empty the build directory.

Using CMake with multiple compilers for the same language

It seems like CMake is fairly entrenched in its view that there should be one, and only one, CMAKE_CXX_COMPILER for all C++ source files. I can't find a way to override this on a per-target basis. This makes a mix of host-and-cross compiling in a single CMakeLists.txt very difficult with the built-in CMake facilities.
So, my question is: what's the best way to use multiple compilers for the same language (i.e. C++)?
It's impossible to do this with CMake.
CMake only keeps one set of compiler properties which is shared by all targets in a CMakeLists.txt file. If you want to use two compilers, you need to run CMake twice. This is even true for e.g. building 32bit and 64bit binaries from the same compiler toolchain.
The quick-and-dirty way around this is using custom commands. But then you end up with what are basically glorified shell-scripts, which is probably not what you want.
The clean solution is: Don't put them in the same CMakeLists.txt! You can't link between different architectures anyway, so there is no need for them to be in the same file. You may reduce redundancies by refactoring common parts of the CMake scripts into separate files and include() them.
The main disadvantage here is that you lose the ability to build with a single command, but you can solve that by writing a wrapper in your favorite scripting language that takes care of calling the different CMake-makefiles.
You might want to look at ExternalProject:
http://www.kitware.com/media/html/BuildingExternalProjectsWithCMake2.8.html
Not impossible as the top answer suggests. I have the same problem as OP. I have some sources for cross compiling for a raspberry pi pico, and then some unit tests that I am running on my host system.
To make this work, I'm using the very shameful "set" to override the compiler in the CMakeLists.txt for my test folder. Works great.
if(DEFINED ENV{HOST_CXX_COMPILER})
set(CMAKE_CXX_COMPILER $ENV{HOST_CXX_COMPILER})
else()
set(CMAKE_CXX_COMPILER "g++")
endif()
set(CMAKE_CXX_FLAGS "")
The cmake devs/community seems very against using set to change the compiler since for some reason. They assume that you need to use one compiler for the entire project which is an incorrect assumption for embedded systems projects.
My solution above works, and fits the philosophy I think. Users can still change their chosen compiler via environment variables, if it's not set then I do assume g++. set only changes variables for the current scope, so this doesn't affect the rest of the project.
To extend #Bill Hoffman's answer:
Build your project as a super-build, by using some kind of template like the one here https://github.com/Sarcasm/cmake-superbuild
which will configure both the dependencies and your project as an ExternalProject (standalone cmake configure/build/install environment).