cdleary
cdleary

Reputation: 71424

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

Upvotes: 31

Views: 17882

Answers (5)

SupAl
SupAl

Reputation: 1061

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.

Upvotes: 0

dangarbri
dangarbri

Reputation: 551

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.

Upvotes: 5

Gabriel
Gabriel

Reputation: 9432

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

Upvotes: 1

Bill Hoffman
Bill Hoffman

Reputation: 1752

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

Upvotes: 5

ComicSansMS
ComicSansMS

Reputation: 54589

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.

Upvotes: 14

Related Questions