3
votes

I have minimal hello world sample:

#include <cstdlib>
#include <iostream>
#include <string_view>

int main(int /*argc*/, char* /*argv*/ [])
{
    using namespace std;

    string_view output_phrase("hello world");

    cout << output_phrase << endl;

    bool is_good = cout.good();

    int result = is_good ? EXIT_SUCCESS : EXIT_FAILURE;
    return result;
}

So I create minimal CMakeLists.txt file:

cmake_minimum_required(VERSION 3.14)
project(01-1-hello-world CXX)
add_executable(01-1-hello-world main.cxx)
target_compile_features(01-1-hello-world PUBLIC cxx_std_17)

Now If I use known for CMake compiler all works as expected (like MSVC, clang++, g++). But if I try some custom compiler(based on clang) from some SDK with toolchain file cmake say:

CMake Error at CMakeLists.txt:5 (target_compile_features): target_compile_features The compiler feature "cxx_std_17" is not known to CXX compiler

"Clang"

So I try to set CMAKE_CXX_COMPILE_FEATURES in my toolchain file

set(CMAKE_CXX_COMPILE_FEATURES cxx_std_17) # we know custom-clang have c++17 support

Also I try to set CMAKE_CXX_KNOWN_FEATURES but nothing changes. How to make target_compile_features(01-1-hello-world PUBLIC cxx_std_17) works in toolchain file for cmake for custom compiler? Thanks in advance!

2
What is in CMakeError.log? Interesting lines are Detecting CXX [-std=c++17] compiler features failed to compile with the following output: or something similar.S.M.
i would give CXX_STANDARD a try instead.nauman

2 Answers

1
votes

Also I try to set CMAKE_CXX_KNOWN_FEATURES

You most probably forgot to clear your build tree. Variables in toolchain file are not "refreshed" when you re-run cmake. You have to remove the build files compleatly and reconfigure cmake when making modifications to the toolchain file. It should work. Note that CMAKE_*_KNOWN_FEATURES is a list of features, o use list(APPEND CMAKE_CXX_COMPILE_FEATURES ...).

For reference for feature readers and because cmake uses a lot of global variables, I want to post what is working with sdcc compiler for C language. For C because it's simpler, it's exactly the same for C++ it's similar with CXX* variables. What is the meaning of variables can be deduced from their names.

cat > toolchain-sdcc.cmake <<EOF
find_program(CMAKE_C_COMPILER NAMES sdcc)
set(CMAKE_CROSSCOMPILING TRUE)    
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)

set(CMAKE_C_STANDARD_DEFAULT "11") # this is the default C standard the compiler uses without any option
set(CMAKE_C90_STANDARD_COMPILE_OPTION "--std-c89")
set(CMAKE_C90_EXTENSION_COMPILE_OPTION "--std-sdcc89")
set(CMAKE_C99_STANDARD_COMPILE_OPTION "--std-c99")
set(CMAKE_C99_EXTENSION_COMPILE_OPTION "--std-sdcc99")
set(CMAKE_C11_STANDARD_COMPILE_OPTION "--std-c11")
set(CMAKE_C11_EXTENSION_COMPILE_OPTION "--std-sdcc11")

list(APPEND CMAKE_C_COMPILE_FEATURES
    c_std_90
    c_std_99
    c_std_11
    c_function_prototypes
    c_restrict
    c_static_assert
    c_variadic_macros
)

EOF

cat > CMakeLists.txt <<EOF
cmake_minimum_required(VERSION 3.11)
set(CMAKE_TOOLCHAIN_FILE sdcc.cmake)
project(a LANGUAGES C)
file(WRITE a.c "int main() {}")
add_executable(a a.c)
target_compile_features(a PUBLIC
    c_std_90
    c_std_99
    c_std_11
    c_function_prototypes
    c_restrict
    c_static_assert
    c_variadic_macros
)

EOF

after that cmake finds the compile features and the project can build.

There is also CMakeDetermineCompileFeatures.cmake that defines cmake_determine_compile_features that is run auto-magically from project() call. Then if the macro cmake_record_c_compile_features is defined by your toolchain, then that macro is used to determine C language compile features. So you can:

cat > toolchain-sdcc.cmake <<EOF
# ...
# remove list(APPEND CMAKE_C_COMPILE_FEATURES, not needed anymore  

# this macro will be called from `project()`
macro(cmake_record_c_compile_features)
    list(APPEND CMAKE_C90_COMPILE_FEATURES c_std_90 c_function_prototypes)
    list(APPEND CMAKE_C99_COMPILE_FEATURES c_std_99 c_restrict c_variadic_macros)
    list(APPEND CMAKE_C11_COMPILE_FEATURES c_std_11 c_static_assert)
    set(_result 0) # expected by cmake_determine_compile_features
endmacro()

EOF

After that you will see that well known Detecting C compile features message that are generated by CMakeDetermineCompileFeatures.cmake when it calls cmake_record_c_compile_features macro:

$ cmake -S . -B _build
...
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Configuring done
...

Last but not least, you can define CMAKE_C*_STANDARD__HAS_FULL_SUPPORT macros and use Compiler/CMakeCommonCompilerMacros module that internally defines the cmake_determine_compile_features macro, and it checks if CMAKE_C*_STANDARD__HAS_FULL_SUPPORT is defines, if it is, it enables all features for that standard of the language:

cat > toolchain-sdcc.cmake <<EOF
# ...
set(CMAKE_C90_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C99_STANDARD__HAS_FULL_SUPPORT ON)
set(CMAKE_C11_STANDARD__HAS_FULL_SUPPORT ON)
# will define cmake_record_c_compile_features macro
# that will inspect CMAKE_C*_STANDARD__HAS_FULL_SUPPORT variables
include(Compiler/CMakeCommonCompilerMacros)
EOF

But the real proper place would be to create Compilers/SDCC-C.cmake in a CMAKE_MODULE_PATH paths and put include(Compiler/CMakeCommonCompilerMacros) there, like for example MSVC-CXX.cmake does.

0
votes
set_property(TARGET 01-1-hello-world PROPERTY CXX_STANDARD 17)

CXX_STANDARD