CMake: migration guide/ cheat sheet for make users - cmake

I'm looking at replacing a configure/make style build process with CMake. CMake performs well on the complicated stuff, but it is more verbose on simple things.
For instance the GNU Make file:
hello:
echo "hello world" >$#
In CMake it would be:
add_custom_command(OUTPUT hello
COMMAND echo "hello world" > hello)
add_custom_target(all ALL DEPENDS hello)
See also Adding a custom command with the file name as a target.
Which is actually more like:
hello:
echo "hello world" >hello
all: hello
With more complex builds the absence of automatic variables is very noticeable.
After much routing around (it seems to be hard to search for $#) I found:
Automatic variables in CMake
Which suggests using wrapper functions and
Path to target output file
which suggests using generator expressions that are close to automatic variables,
but not close enough.
I have several related questions:
1a) Has CMake itself or best practice for doing this moved on since that question was asked?
1b) Is it likely CMake will ever provide an equivalent to automatic variables?
If not, why not?
Individual problems are quite well covered on Stack Overflow and elsewhere on the Internet, but:
2a) Are there any good guides or cheat sheets to help with migrating from using GNU make directly.
2b) Are they any good best practice guides for CMake?
That is beyond the suggestions in Makefile equivalent in CMake. I am gradually evolving my own style, but I would like to avoid horseless carriage type mistakes and needless complexity.

This is hard to answer, because CMake is not equivalent to make. It's much easier to compare CMake to autotools, for example, because it is a build system generator rather than a build system by itself.
Regardless, let's try to provide some answers.
1a+b) No, because it is not in the scope and philosophy of CMake to provide such constructs.
CMake's syntax is usually more on the side of verbosity, with explicit variable names such as ${CMAKE_CURRENT_SOURCE_DIR} as well as named command parameters. It looks more like a "classical" imperative programming language rather than a specialized textual description of a dependency graph which Makefiles are.
Also, CMake's output can be Makefiles or pretty much anything else, so a certain level of abstraction is needed.
The best practice in your case would be to use macros:
macro(build_echo_foo ${target})
add_custom_command(OUTPUT ${target}
COMMAND echo "hello world" > ${target})
add_custom_target(${target}_target ALL DEPENDS ${target})
endmacro()
build_echo_foo(hello)
build_echo_foo(another_hello)
Where Makefiles encourage the author to be as generic as possible, to minimize typing, CMake tries to make things as unambiguous as possible, for example by encouraging the maintainer to explicitly list source files instead of providing wildcards.
2a+b) Answering this is not exactly in the scope of Stack Overflow, but I'll say this.
The best source of inspiration is open-source projects using this system. As of 2014, there are a good number of high-profile projects that have migrated to CMake. You can even study CMake's own source code, which uses itself as build system.

Related

Setting project wide compiler options [duplicate]

This question already has an answer here:
What is the modern method for setting general compile flags in CMake?
(1 answer)
Closed 1 year ago.
I want to use CMake to create modular embedded C++ software. I separated hal-drivers static library, some common-utils library and top target device depends on those two what is marked using target_link_libraries like this:
target_link_libraries(device
PRIVATE
hal-drivers
common-utils
)
It is easy to propagate compile definitions and option up in "dependency ladder" using commands like this:
target_compile_definitions(hal-drivers
INTERFACE
STM32F415xx
USE_HAL_DRIVER
)
This way any target utilising hal-drivers header files will preprocess those headers correctlym, and I found this CMake scripts feature (propagation of "settings") great, but it is not the point of this question.
The question is how should I propagate common compiler options like for example -fdata-sections or -Wall for every target in my project? I know I can
create dummy (no source and no header files, just compile options) interface target which will be consumed by every other target in project but this looks like a workaround...
specify mentioned compiler options for every target separatly, since I have only about 5 targets, but it will be very problematic to maintain.
In my commercial work project (50 targets) my boss ended up with an ugly compromise: setting common compile options in top CMakeLists.txt as cached variable and then applying this variable in all targets manually, but we dont like it at all.
Bear in mind: I do have solutions that work, I am interested in recomended solutions. Also I am using Professional CMake: A Practical Guide 9th Edition on daily basis (its a great book), but I failed to found answer on my question in this book.
I found an answer.
I guess my whining about lack of elegant solution is due to my attachment to syntactic sugar like target_compile_options, but the thing is CMake evolved in hardship and not every CMake feature is pretty, but it works.
There is an answer: https://cmake.org/cmake/help/latest/variable/CMAKE_LANG_FLAGS.html
The flags in this variable will be passed to the compiler before those in the per-configuration CMAKE_<LANG>_FLAGS_<CONFIG> variant, and before flags added by the add_compile_options() or target_compile_options() commands.
So I have to append my custom options to this special CMake variable like this:
project(Device C CXX ASM)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fdata-sections")
This way it will flood all targets with fdata-sections.
Leaving this thread as interesting note.

Change toolchain in a subfolder 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).

How to get cmake to find size of type in third-party header mpi.h?

I am working on a free-software project which involves high performance computing and the MPI library.
In my code, I need to know the size of the MPI_Offset type, which is defined in mpi.h.
Normally such projects would be build using autotools and this problem would be easily solved. But for my sins, I am working with a CMake build and I can't find any way to perform this simple task. But there must be a way to do - it is commonly done on autotools projects, so I assume it is also possible in CMake.
When I use:
check_type_size("MPI_Offset" SIZEOF_MPI_OFFSET)
It fails, because mpi.h is not included in the generated C code.
Is there a way to tell check_type_size() to include mpi.h?
This is done via CMAKE_EXTRA_INCLUDE_FILES:
INCLUDE (CheckTypeSize)
find_package(MPI)
include_directories(SYSTEM ${MPI_INCLUDE_PATH})
SET(CMAKE_EXTRA_INCLUDE_FILES "mpi.h")
check_type_size("MPI_Offset" SIZEOF_MPI_OFFSET)
SET(CMAKE_EXTRA_INCLUDE_FILES)
It may be more common to write platform checks with autotools, so here is some more information on how to write platform checks with CMake.
On a personal note, while CMake is certainly not the most pleasant exercise, for me autotools is reserved for the capital sins. It is really hard to me to defend CMake, but in this instance, it is even documented. Naturally, setting a separate "variable" that you even have to reset after the fact, instead of just passing it as a parameter, is clearly conforming to the surprising "design principles" of CMake.

link library to all targets in cmake project

Let me describe what I think is a sufficiently common use case, that it should be supported. Consider a project which consists of a library and a set of executable that use that library. A straightforward approach is to add_library, followed by a sequence of add_executable() target_link_lib() pairs.
This is a lot of boilerplate coding. It would be nice to able to do something like set(PROJECT_LINK_LIBS, lib1 ...), and have cmake remove the extra boilerplate.
Thinking on this more, I realize I would like a link_libraries function that behaves similarly to include_directories. I would argue that this:
Would be useful in a lot of cases.
Would lead to dryer CMakeLists.
Would encourage better code organizations -- there would be a natural incentive to organize the folders, code, and executables in such a way that all executables have the same dependancies -- certainly a clean practice.
Is there anything like this?
As mentioned at https://stackoverflow.com/a/50295894/129550 the requested link_libraries(example example2) function is actually now a part of cmake.
This answer might be obsolete:
Check the new set of variables CMAKE_<LANG>_STANDARD_LIBRARIES
Original Answer:
It appears that now a CMAKE_STANDARD_LIBRARIES variable exists, where you can append the libraries according to your need. However, this variable seemingly expect full path to the libraries.
See here.

Extract compiler command from cmake

The various clang-based completion tools (like youcompleteme) need to be told what compiler flags a source is to be compiled with. It would be nice if the compiler options to be used could be extracted from the project files. What would be easiest way to extract the flags (automatically, not manually) from either the cmake projects or the generated result in make or ninja format?
See http://clang.llvm.org/docs/LibTooling.html
Set CMAKE_EXPORT_COMPILE_COMMANDS=ON.
Ninja is actually able to print out commands to build all or specific target. And it does it extremely fast. As in on my machine in 0.033s for 1122 commands. It can print them either as shell commands or as compilation database and ycm has utility to use the compilation database.
It is important to note that the compdb ninja tool requires a rule name as argument. That does not seem to be mentioned in documentation.
The easiest is usually to do something in essence of CC=echo CXX=echo make and extract the arguments from it.
There's already an implementation of this in the clang_complete plugin, see the cc_args.py script at https://github.com/Rip-Rip/clang_complete/blob/master/bin/cc_args.py and documented in https://github.com/Rip-Rip/clang_complete/blob/master/doc/clang_complete.txt for more informations. If I'm not mistaken YCM can read .clang_complete files.
For example in clang_complete you run it like make CC='~/.vim/bin/cc_args.py gcc' CXX='~/.vim/bin/cc_args.py g++' -B
I'd not be surprised if YCM had a similar mechanism already available out of the box.
[EDIT] Yes it has, see https://github.com/Valloric/YouCompleteMe#c-family-semantic-completion-engine-usage and the "Clang's CompilationDatabase" support from the YCM documentation. Basically, either have make generate a file with the compilation flags for YCM to use or have clang generate a compilation database and have YCM use that.