31

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++)?

1

5 Answers 5

14

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.

Sign up to request clarification or add additional context in comments.

7 Comments

Seems like add_directory(other_build_kind_folder) is a possibility as well, as opposed to making a custom wrapper, since that's what I've been doing and it seems to work. :-)
@cdleary Could you clarify how that works? How does add_subdirectory (or did you really mean add_directory?) allow you to switch toolchains?
Mostly correct, but there are techniques to massage CMake to use both a host and a toolchain set of compilers controlled from the one build. See this question and answer for a similar scenario which I've been using successfully in a couple of real world projects for some time now. @Bill's answer recommending ExternalProject is also good advice.
@ComicSancMs I strongly disagree on the reasoning behind the 3rd paragraph ,Indeed you can't link with different architectures but that's not the only reason to have diffrent c++ compilers, for example I used to use templight as a wrapper for clang and ccache is also a compiler wrapper , both these projects count as different compilers but there are just different tools that by principal you can use at will at any separate cpp files you want
In VS it's fine to have one solution with even static library projects compiled with different compilers. Because they all binary compatible. Compilers are VC, Intel, Clang. They all use the same VC stl. Designed to be binary compatible.
|
5

You might want to look at ExternalProject: http://www.kitware.com/media/html/BuildingExternalProjectsWithCMake2.8.html

1 Comment

Link now redirects to a PDF which doesn't appear to mention ExternalProject.
5

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.

Comments

1

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

Comments

1

For those who are using a modern (CMake >= v3.19), take a look at presets.

With these you can have a preset that is used for building with one compiler and another preset for another compiler.

It does not completely solve the problem, but with modern editors (vs code), the switching between the compilers becomes a breeze.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.