How should SSE flags be added with modern CMake? - c++

I'm trying to follow the guidelines for modern cmake >= 3.0 at least, where I don't assume anything about the compiler and use target based commands.
See: https://www.youtube.com/watch?v=bsXLMQ6WgIk
or search "effective cmake".
So, how then, when my target depends on SSE 4.1, should I be declaring this information?
I was actually expecting FindSSE to include an interface target with no source but carries it's own appropriate linker flags. But it only states if SSE versions are present on the host.
This varies by platform, so like:
/arch:sse4.1 vs -msse4.1
So am I missing something internal to cmake that handles this setting for different compilers or do I just need to check the platform and set target_compile_options accordingly?

Based on lubgr's reply, I devised this:
add_library(sse4_1 INTERFACE IMPORTED)
if(MSVC)
target_compile_options(sse4_1 INTERFACE /arch:SSE4.1)
else()
target_compile_options(sse4_1 INTERFACE -msse4.1)
endif()

For global flags, that are used by all targets in the project it is perfectly fine to still use the non-target based approach, eg. by calling add_compile_options.
For maintainability reasons, you should do this in one place only, preferably close to the root CMakeLists.txt.
This saves you from having to repeat the same target dependency everywhere throughout the project. Note though that this relies somewhat on programmer discipline: As soon as you have singular targets that need different flags or you start introducing multiple places where the global flags are being set, this can quickly turn into a maintenance nightmare.

Related

CMake Treat Warnings as Errors

How can I configure CMake to treat compiler warnings as errors during the build?
I am aware of the possibility to manually configure command line options for the compiler like -Werror through commands like target_compile_options, but I would prefer a portable solution that does not require fiddling with tool-dependent options.
This can be configured in CMake version 3.24 and higher via the COMPILE_WARNING_AS_ERROR target property.
For example, to enable warnings as errors for the my_app target you could write:
set_property(TARGET my_app PROPERTY COMPILE_WARNING_AS_ERROR ON)
You can also set a global default for all targets in your project via the CMAKE_COMPILE_WARNING_AS_ERROR variable:
set(CMAKE_COMPILE_WARNING_AS_ERROR ON)
add_executable(my_app1 [...])
add_executable(my_app2 [...])
add_executable(my_app3 [...])
If a user finds it annoying that this is set in the CMakeLists.txt file, they can still override it using the --compile-no-warning-as-error configure option.
Treating warnings as errors is a good practice for CI systems with a fixed and predictable toolchain, but it is inappropriate to force on all users. Many are likely using a different toolchain with different sets of warnings and sensitivities for those warnings. Enabling -Werror by default causes broken builds for your consumers and is a bad practice.
Notably, this exact issue was the source of one major debacle in the last year in the Linux kernel: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b339ec9c229aaf399296a120d7be0e34fbc355ca
It is also prohibited by the Gentoo packaging archives (important because it is a source-based distribution): https://devmanual.gentoo.org/ebuild-writing/common-mistakes/index.html
Do a bit more searching and you will hear the shouting from the mountaintops that warnings as errors is good for developers, but not for consumers.
The best way to do this, then, is to set the new (as of CMake 3.24) variable CMAKE_COMPILE_WARNING_AS_ERROR set to ON only when you know it is safe to do so. That is to say, it should not be on by default (but if you insist, then there must be a way to disable it).
There are many good ways to set this up:
You could add it to the cacheVariables section of a preset
You could set it to ON in a toolchain file
You can simply pass it at the command line when you want to toggle it on or off.
Speaking as someone who regularly uses top-of-tree compiler builds, where warnings break frequently, hard-coded warnings-as-errors is a blight. It forces me and countless other package maintainers, devops teams, and so on, to patch your build.

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

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

target_compile_options() for only C++ files?

Is it possible to use target_compile_options() for only C++ files? I'd like to use it for a target that is uses as a dependency for other applications so that the library can propagate its compiler flags to those apps. However, there are certain flags, such as -std=c++14, that cause the build to fail if they are used with C or ObjC files.
I've read that I should CXX_FLAGS instead to only add those flags to C++ files, however this won't (automatically) propagate through cmake's packages system.
Solution
You can do this with generator expressions:
target_compile_options(MyLib PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-std=c++14>)
Alternative
But the more platform independent way of doing it in this particular case would be to use target_compile_features(). I'm not sure which compiler feature you're using, so the following is only an example:
target_compile_features(MyLib PUBLIC cxx_explicit_conversions)
I've read that I should CXX_FLAGS instead to only add those flags to C++ files, however this won't (automatically) propagate through cmake's packages system.
In CMake, if you use any function prefixed with target_* it only has the scope of one build target. If you want your whole project to build with given standard you can use set(CMAKE_CXX_STANDARD 14). If some of the targets requires another setting, you can override it locally with the target prefixed function and CXX_STANDARD variable (it's default value is ${CMAKE_CXX_STANDARD}).
As pointed out by RAM this option is available since v3.1. But judging by https://repology.org/project/cmake/versions it is already widely supported.
It is also often pointed out that you should not set cpp version fixed. I have not formed my opinion on this yet, but you can but you can use the keyword CACHED to make it overridable.

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