0

Goals

Make cmake select clang++ if its version is above 10; otherwise, use g++. If clang++ is below 10 and the default g++ is below 10.1, use g++-10 (REQUIRED).

This is to achieve compiler fallback.

Background

As kindly noted in this answer, one should set the default compiler before the project keyword.

Instead of using

-DCMAKE_CXX_COMPILER=clang++

or

set(CMAKE_CXX_COMPILER clang++)

I used the following statements with reference to the answer here:

find_program(CMAKE_CXX_COMPILER
    NAMES $ENV{CXX} clang++ PATHS ENV PATH NO_DEFAULT_PATH)

if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10)
  find_program(CMAKE_CXX_COMPILER
      NAMES $ENV{CXX} g++ PATHS ENV PATH NO_DEFAULT_PATH)
  if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.1)
    find_program(CMAKE_CXX_COMPILER
      NAMES $ENV{g++-10} g++-10 PATHS ENV PATH NO_DEFAULT_PATH REQUIRED)
  endif()
endif()

Problem

The compiler is not set to g++ when the version of clang++ is less than 10, but I could check that cmake passes the branch

if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10)

I do not understand this behavior. And are there any alternative to this without using command line arguments?

UPDATE

This question was asked in acknowledgment of the fact that setting a compiler in CMakeLists.txt is discouraged.

@KamilCuk suggested two ways to achieve what I stated, and one may take those suggestions if they want to.

Here's what I did.

TL;DR

Do not specify a compiler in CMakeLists.txt.

My suggestion

This is contrary to what I have previously done in this question.

I scrapped all the configuration logic from CMakeLists.txt and decided to create a shell file that extracts compiler versions and select an appropriate compiler. This way of configuration is quite well-known, which can be found in many popular repositories such as ImageMagick and tensorflow.

PHD
  • 595
  • 1
  • 8
  • 18
  • Imagine there is no `CMAKE_CXX_COMPILER_VERSION`. How would you get it? You have to write the code yourself, `CMAKE_CXX_COMPILER_VERSION` is set __after__ the compiler _has been_ chosed. – KamilCuk Dec 31 '20 at 12:07
  • @KamilCuk I just found that `CMAKE_CXX_COMILER_VERSION` before `project` prints out nothing. You are absolutely right. Do I have to provide command line arguments to specify a compiler? – PHD Dec 31 '20 at 12:16
  • You have to write _the logic_ that you want to write, somewhere. – KamilCuk Dec 31 '20 at 12:16

1 Answers1

0

If you want to write the logic in cmake, you could write something along:

cmake_minimum_required(VERSION 3.11)

# Before project()!!!
execute_process(COMMAND clang++ --version OUTPUT_VARIABLE result)
string(REGEX REPLACE "[^0-9]* ([0-9]+).*" "\\1" clang_version "${result}") # extract the version with some regex
execute_process(COMMAND g++ --version OUTPUT_VARIABLE result)
string(REGEX REPLACE "[^0-9]* ([0-9]+).*" "\\1" gcc_version "${result}") # extract the version with some regex
# write your super condition here and set CMAKE_CXX_COMPILER depending on it
set(CMAKE_CXX_COMPILER g++)
if (gcc_version LESS 10)
    set(CMAKE_CXX_COMPILER clang++)
endif()


project(blabla) # uses CMAKE_CXX_COMPILER and configures cmake

You could also use include(CMakeDetermineCXXCompiler) to determine the version, or use the template files from cmake from CMakeCXXCompilerId.cpp.in from cmake installation path that is used by CMakeDetermineCXXCompiler internally.

KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • Can I verify that `CMakeDetermineCXXCompiler` is something to do with `configure_file`? – PHD Dec 31 '20 at 13:52
  • Why not just [browse it's source](https://github.com/Kitware/CMake/blob/master/Modules/CMakeDetermineCXXCompiler.cmake). It's one of many modules shipped and used by cmake. `configure_file` I think is called inside `CMAKE_DETERMINE_COMPILER_ID` inside `CMakeDetermineCompilerId.cmake` – KamilCuk Dec 31 '20 at 14:51