How can I remove an option from the default compile command template for a specific compiler? - cmake

Any normal gcc compatible compiler specifies the source file with -c option (compile but not link). I have to deal with "Tasking" compiler which doesn't like this option. -c option for this TASKING compiler indicates C standard (page 280) indicates the C standard.
I've used the common way to specify the compiler using the toolchain file:
set(CMAKE_C_COMPILER "${AURIX_SDK_ROOT}/bin/ctc" CACHE INTERNAL "")
set(CMAKE_CXX_COMPILER "${AURIX_SDK_ROOT}/bin/cptc" CACHE INTERNAL "")
foreach (_prefix C CXX)
# set(CMAKE_${_prefix}_COMPILER "${AURIX_SDK_ROOT}/bin/cctc")
# This is used only if we skip auto compiler identification
set(CMAKE_${_prefix}_COMPILER_ID "Tasking")
set(CMAKE_${_prefix}_COMPILER_VERSION "6.3r1")
# Skip compiler ID identification: use "Tasking"
set(CMAKE_${_prefix}_COMPILER_ID_RUN TRUE CACHE INTERNAL "")
set(CMAKE_${_prefix}_COMPILER_FORCED TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_WORKS TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_FORCED TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_ID_RUN TRUE CACHE INTERNAL "")
endforeach()
set(CMAKE_AR "${AURIX_SDK_ROOT}/bin/artc")
set(CMAKE_ASM_COMPILER "${AURIX_SDK_ROOT}/bin/astc")
set(CMAKE_LINKER "${AURIX_SDK_ROOT}/bin/ltc")
# Search paths for libraries
set(CMAKE_FIND_ROOT_PATH ${AURIX_SDK_ROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
Is there any way to configure CMake (version 3.16) to not use -c option? I did specify CMAKE_CCOMPILER_ID as "Tasking".
Versions:
CMake >3.16
TASKING VX-toolset for TriCore v6.3r1

If the Tasking compiler really isn't supposed to have -c to specify the file to compile (I wouldn't know, because I don't know that compiler), then you might be able to do this by modifying your CMake installation's Modules/Compiler/Tasking-CXX.cmake file to make it override the default value of CMAKE_CXX_COMPILE_OBJECT which gets set in the Modules/CMakeCXXInformation.cmake file like:
set(CMAKE_CXX_COMPILE_OBJECT
"<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> -c <SOURCE>")
and just put that same line in the Modules/Compiler/Tasking-CXX.cmake except removing the -c argument. Or you could try putting this in your toolchain file.
At least- that's how things look to be set up to work in the CMake modules. Just grep the modules for CMAKE_CXX_COMPILE_OBJECT and you'll see similar overrides for specific compilers or platforms.
Disclaimer: I'm not 100% sure this will work. I just grepped the code to find something that looks like it might be the thing to poke with a stick. Documentation for CMAKE_CXX_COMPILE_OBJECT can be found here.
The places in the CMake source code where CMAKE_CXX_COMPILE_OBJECT is used is in Source/cmMakefileTargetGenerator.cxx and Source/cmNinjaTargetGenerator.cxx (search for regex CMAKE_.*_COMPILE_OBJECT). It's pretty interesting (or very boring)- you can read how the compile command gets built by the CMake executable for various generators.

The solution to this problem, turned out, is the CMake version 3.25. The support for Tasking compiler was added in this version. The toolchain file looks like this:
set(CMAKE_C_COMPILER "${AURIX_SDK_ROOT}/bin/cctc" CACHE INTERNAL "")
foreach (_prefix C)
# set(CMAKE_${_prefix}_COMPILER "${AURIX_SDK_ROOT}/bin/cctc")
# This is used only if we skip auto compiler identification
set(CMAKE_${_prefix}_COMPILER_ID "Tasking")
set(CMAKE_${_prefix}_COMPILER_VERSION "Tricore")
set(CMAKE_${_prefix}_COMPILER_ARCHITECTURE_ID "Tricore")
# Skip compiler ID identification: use "Tasking"
set(CMAKE_${_prefix}_COMPILER_ID_RUN TRUE CACHE INTERNAL "")
set(CMAKE_${_prefix}_COMPILER_FORCED TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_WORKS TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_FORCED TRUE CACHE INTERNAL "")
SET(CMAKE_${_prefix}_COMPILER_ID_RUN TRUE CACHE INTERNAL "")
endforeach()
set(CMAKE_AR "${AURIX_SDK_ROOT}/bin/artc")
set(CMAKE_ASM_COMPILER "${AURIX_SDK_ROOT}/bin/astc")
set(CMAKE_LINKER "${AURIX_SDK_ROOT}/bin/ltc")
# Search paths for libraries
set(CMAKE_FIND_ROOT_PATH ${AURIX_SDK_ROOT})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
Some notes:
The compiler setup emphatically does not support C++. Not sure why. There is a C++ compiler cptc.
The control application cctc should be used instead of the ctc compiler directly.

Related

Cannot find gtk/gtk.h when building nativefiledialog on Fedora 37

I am using nativefiledialog-cmake in my C++ project as a submodule. When I generate the build files using CMake, it does not generate properly as it cannot find the gtk/gtk.h file needed for one of nativefiledialog's source files : nfd_gtk.c.
I have installed the following GTK and GTK dependency packages:
gtk2
gtk3
gtk4
gtk2-devel
gtk3-devel
gtk4-devel
gtk4-devel-tools
glib
glib-devel
gdk-pixbuf2-devel
atk
atk-devel
gobject-introspection
gobject-introspection-devel
libepoxy
libepoxy-devel
and ls /usr/include | grep gtk returns
gtk-2.0
gtk-3.0
gtk-4.0
gtk-unix-print-2.0
The GTK headers are inside these folders.
This is nativefiledialog-cmake's CMakeLists.txt file:
include(CheckIncludeFile)
set(SOURCES src/nfd_common.c)
macro(REQUIRE_INCLUDE_FILE path name)
CHECK_INCLUDE_FILE(${path} ${name})
if (NOT ${name})
message(FATAL_ERROR "${path} not found")
endif ()
endmacro()
# add specific implementations
if (WIN32)
REQUIRE_INCLUDE_FILE(windows.h HAS_WINDOWS)
list(APPEND SOURCES src/nfd_win.cpp)
elseif (APPLE)
REQUIRE_INCLUDE_FILE(AppKit/AppKit.h HAS_APPKIT)
list(APPEND SOURCES src/nfd_cocoa.m)
elseif (UNIX)
REQUIRE_INCLUDE_FILE(gtk/gtk.h HAS_GTK)
list(APPEND SOURCES src/nfd_gtk.c)
elseif (UNIX)
message(FATAL_ERROR "Cannot detect your system, please report to https://github.com/aarcangeli/nativefiledialog-cmake/issues")
endif ()
add_library(nativefiledialog ${SOURCES})
target_include_directories(nativefiledialog PUBLIC src/include)
I have tried adding this line (returned from pkg-config --cflags gtk+-3.0) to tell the compiler where the GTK headers are located with no avail:
set(FLAGS "${FLAGS} -I/usr/include/gtk-3.0 -I/usr/include/pango-1.0 -I/usr/include/glib-2.0 -I/usr/lib64/glib-2.0/include -I/usr/include/sysprof-4 -I/usr/include/harfbuzz -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/fribidi -I/usr/include/libxml2 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/gio-unix-2.0 -I/usr/include/cloudproviders -I/usr/include/atk-1.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/dbus-1.0 -I/usr/lib64/dbus-1.0/include -I/usr/include/at-spi-2.0 -pthread")
How do I get CMake to generate properly?
First of all I am quite not sure how you arrived at the set(FLAGS "${FLAGS} ...") line, because unless you've specified some additional logic, that just creates a variable FLAGS, it is not a standard CMake variable IIRC.
Perhaps what you meant to use was target_compile_options(), where you can specify additional compile options to a given target which in your case is most likely nativefiledialog. That might fix your issue i.e.:
target_compile_options(nativefiledialog PUBLIC "$<$<CONFIG:DEBUG>:${DEBUG_FLAGS}>")
target_compile_options(nativefiledialog PUBLIC "$<$<CONFIG:RELEASE>:${RELEASE_FLAGS}>")
Or in your case:
target_compile_options(nativefiledialog PUBLIC "${FLAGS}")
This however is not good practice and I would recommend rewriting nativefiledialog's CMakeLists.txt.
Bare in mind that this is in no way your fault, the nativefiledialog has a very bad CMakeLists.txt because the author didn't use any prebuild CMake functionalities like find_package(GTK).

build cmake subproject with differents toolchain [duplicate]

I have embedded project using cross compiler. I would like to introduce Google test, compiled with native GCC compiler. Additionally build some unit test targets with CTC compiler.
Briefly:
I have 3 different targets and compile them with 3 different compilers. How to express it in CMakeLists.txt? I Tried SET_TARGET_PROPERTIES;
but it seems impossible to set CXX variable with this command!
I just had the same issue right now, but the other answer didn't help me. I'm also cross-compiling, and I need some utility programs to be compiled with GCC, but my core code to be compiled with avr-gcc.
Basically, if you have a CMakeLists.txt, and you want all targets in this file to be compiled with another compiler, you can just set the variables by hand.
Define these macros somewhere:
macro(use_host_compiler)
if (${CURRENT_COMPILER} STREQUAL "NATIVE")
# Save current native flags
set(NATIVE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the native compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${HOST_C_COMPILER})
set(CMAKE_C_FLAGS ${HOST_C_FLAGS})
set(CURRENT_COMPILER "HOST" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
macro(use_native_compiler)
if (CMAKE_CROSSCOMPILING AND ${CURRENT_COMPILER} STREQUAL "HOST")
# Save current host flags
set(HOST_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the host compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${NATIVE_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${NATIVE_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${NATIVE_C_COMPILER})
set(CMAKE_C_FLAGS ${NATIVE_C_FLAGS})
set(CURRENT_COMPILER "NATIVE" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
At the very beginning of your CMakeLists.txt script (or in a toolchain file), set the following variables according to what you need:
CURRENT_COMPILER
HOST_C_COMPILER
HOST_C_FLAGS
NATIVE_SYSTEM_NAME
NATIVE_C_COMPILER
NATIVE_C_FLAGS
The idea is that CMAKE_C_COMPILER (and company) is a variable like any other, so setting it inside a certain scope will only leave it changed within that scope.
Example usage:
use_host_compiler()
add_executable(foo foo.c) # Compiled with your host (computer)'s compiler.
use_native_compiler()
add_executable(bar bar.c) # Compiled with your native compiler (e.g. `avr-gcc`).
There is no proper way to change compiler for individual target.
According to cmake manual "Once set, you can not change this variable". This is about CMAKE_<LANG>_COMPILER.
The solution suggested by AnthonyD973 does not seem to work, which is sad of course. The ability to use several compilers in a project without custom_command things is very useful.
One solution (that I haven't tried yet) is to use
set_target_properties(your_target CXX_COMPILER_LAUNCHER foo_wrapper)
Then make foo_wrapper a script that just drops the first argument (which will be the default compiler, e.g. c++) and then calls the compiler you want.
There's also CXX_LINKER_LAUNCHER and the same for C_....
CMake is a make file generator. It generates a file that you can then use to build. If you want to more than one target platform, you need to run CMake multiple times with different generators.
So what you want to do is not possible in CMake, but with CMake: You can create a shell script that invokes CMake multiple times.

Adding support to new compiler vendor in CMake (cross-compiling)

I want to cross compile an embedded application using Tasking TriCore toolchain and CMake (3.16 is ok).
I started with a complete toolchain file, where all paths to binaries and rules were specified, but then I read this thread and used the Compiler/IAR* scripts as an example (https://github.com/Kitware/CMake/blob/master/Modules/Compiler) to end up with a cleaner way.
I know that by default in C/CXX projects, CMake tries to compile a simple test program CMakeCCompilerId.c to detect the compiler id vendor and version. With IAR-DetermineCompiler.cmake I created my own Tasking-DetermineCompiler.cmake which would used symbols defined by the ctc compiler. But even if this file is executed by CMake (syntax errors in there are detected) it does not seem to have any impact on the generated test source file.
This means that the default mechanism for compiler identification does not work for my compiler and I get the message "The C compiler identification is unknown". On my toolchain file I need to force the identification:
set(CMAKE_SYSTEM_NAME Generic)
# will load Platform/Generic.cmake under CMAKE_MODULE_PATH
# Normalize, convert Windows backslashes to forward slashes or CMake will crash
get_filename_component(TASKING_ROOT_PATH "$ENV{TASKING_TRICORE_PATH}" ABSOLUTE)
# Specify the compiler
# will load Platform/Generic-ctc.cmake CMAKE_MODULE_PATH
foreach (_prefix C CXX)
if ("${CMAKE_${_prefix}_COMPILER}" STREQUAL "")
set(CMAKE_${_prefix}_COMPILER "${TASKING_ROOT_PATH}/bin/cctc.exe")
endif()
# This is used only if we skip auto compiler identification
set(CMAKE_${_prefix}_COMPILER_ID "Tasking")
set(CMAKE_${_prefix}_COMPILER_VERSION "6.3.1r1")
# Skip compiler ID identification: use "Tasking"
set(CMAKE_${_prefix}_COMPILER_ID_RUN TRUE)
set(CMAKE_${_prefix}_COMPILER_FORCED TRUE)
endforeach()
# will load Compiler/Tasking.cmake under CMAKE_MODULE_PATH
# and Compiler/Tasking-FindBinUtils.cmake as well
So far, this is working but I would like to understand whether it is possible to use the default CMake way of identifying the compiler id and version. I could not find how to add other vendors in the documentation!
Many thanks

How do I detect that I am cross-compiling in CMakeLists.txt?

The CMake documentation suggests that CMAKE_CROSSCOMPILING is set when cross-compiling. In my CMakeLists.txt I have the lines:
IF(CMAKE_CROSSCOMPILING)
message(STATUS "Cross-compiling so skipping unit tests.")
option(GAME_PORTAL_UNIT_TEST "Enable unit testing of Game Portal code" OFF)
ELSE()
message(STATUS "Enabling unit testing of Game Portal code")
option(GAME_PORTAL_UNIT_TEST "Enable unit testing of Game Portal code" ON)
ENDIF()
The output from running:
cmake -DCMAKE_TOOLCHAIN_FILE=../crosscompile/raspberry_pi/CMakeCross.txt .
Includes the text "Enabling unit testing of Game Portal code", so clearly this variable is not being set, or not so it evaluates to true anyway.
I tried modifying CMakeCross.txt to include:
set(CMAKE_CROSSCOMPILING ON CACHE BOOL "Cross-compiling" FORCE)
and after cleaning the old CMakeCache.txt and rerunning my cmake command I can see that the new CMakeCache.txt now includes this variable, but I still get the same result as previously with regards to the unit tests being enabled.
How can I reliably detect that I am cross-compiling so I can properly disable the unit tests?
As requested, the full cross-compile file is:
# Set minimum cmake version required for cross-compiling to work.
cmake_minimum_required(VERSION 2.6)
# Build with rm CMakeCache.txt; cmake -DCMAKE_TOOLCHAIN_FILE=/home/crosscompile/dev/raspberry_pi/CMakeCross.txt ..
# Set target system name.
SET (CMAKE_SYSTEM_NAME Linux)
# Set compiler name.
SET (CMAKE_C_COMPILER arm-linux-gnueabihf-gcc)
SET (CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++)
# Set path(s) to search for libraries/binaries/headers.
SET (CMAKE_FIND_ROOT_PATH /home/crosscompile/dev/raspberry_pi/rootfs/)
# Ensure only cross-compiler directories are searched.
SET (ONLY_CMAKE_FIND_ROOT_PATH TRUE)
# search for programs in the build host directories
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
# Set output/install directory to safe place.
SET (CMAKE_INSTALL_PREFIX /home/crosscompile/dev/raspberry_pi/install/)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rpath-link=/lib/arm-linux-gnueabihf")
set(THREADS_PTHREAD_ARG 0)
set(CMAKE_CROSSCOMPILING ON CACHE BOOL "Cross-compiling" FORCE)
The test for CMAKE_CROSSCOMPILING must come after the "project" instruction in CMakeLists.txt.
With in-source builds, one need to manually cleanup build files when change configuration parameters a lot.
E.g., if you did native build before, and then decide to cross-compile, you need to perform manual cleanup: CMake cannot automatically adjust build directory from one build type to another.
This is one of the reasons why in-source builds are not recommended and should be replaced with out-of-source builds.
This is working in my example:
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(STM32F4Examples C)
set(CMAKE_CROSSCOMPILE OFF CACHE BOOL "is crosscompiled")
message(STATUS "CMAKE_CROSSCOMPILE ${CMAKE_CROSSCOMPILE}")
CMakeToolChain_STM32F4.txt
# cmake toolchain
# Use this file with cmake -DCMAKE_TOOLCHAIN_FILE=[PATH/TO/This/FILE] PATH/TO/SOURCES
set(CMAKE_CROSSCOMPILE ON CACHE BOOL "is crosscompiled" FORCE)
This cmake -DCMAKE_TOOLCHAIN_FILE=.. command will set CMAKE_TOOLCHAIN_FILE.
Check cross compiling with following:
if (CMAKE_TOOLCHAIN_FILE)
# This is in cross compiling condition.
set(PROJECT_OUT_NAME ${PROJECT_NAME}.elf)
else ()
set(PROJECT_OUT_NAME ${PROJECT_NAME})
endif()
add_executable(${PROJECT_OUT_NAME} "main.cpp")

CMake: how to change compiler for individual target

I have embedded project using cross compiler. I would like to introduce Google test, compiled with native GCC compiler. Additionally build some unit test targets with CTC compiler.
Briefly:
I have 3 different targets and compile them with 3 different compilers. How to express it in CMakeLists.txt? I Tried SET_TARGET_PROPERTIES;
but it seems impossible to set CXX variable with this command!
I just had the same issue right now, but the other answer didn't help me. I'm also cross-compiling, and I need some utility programs to be compiled with GCC, but my core code to be compiled with avr-gcc.
Basically, if you have a CMakeLists.txt, and you want all targets in this file to be compiled with another compiler, you can just set the variables by hand.
Define these macros somewhere:
macro(use_host_compiler)
if (${CURRENT_COMPILER} STREQUAL "NATIVE")
# Save current native flags
set(NATIVE_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the native compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${CMAKE_HOST_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${HOST_C_COMPILER})
set(CMAKE_C_FLAGS ${HOST_C_FLAGS})
set(CURRENT_COMPILER "HOST" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
macro(use_native_compiler)
if (CMAKE_CROSSCOMPILING AND ${CURRENT_COMPILER} STREQUAL "HOST")
# Save current host flags
set(HOST_C_FLAGS ${CMAKE_C_FLAGS} CACHE STRING "GCC flags for the host compiler." FORCE)
# Change compiler
set(CMAKE_SYSTEM_NAME ${NATIVE_SYSTEM_NAME})
set(CMAKE_SYSTEM_PROCESSOR ${NATIVE_SYSTEM_PROCESSOR})
set(CMAKE_C_COMPILER ${NATIVE_C_COMPILER})
set(CMAKE_C_FLAGS ${NATIVE_C_FLAGS})
set(CURRENT_COMPILER "NATIVE" CACHE STRING "Which compiler we are using." FORCE)
endif()
endmacro()
At the very beginning of your CMakeLists.txt script (or in a toolchain file), set the following variables according to what you need:
CURRENT_COMPILER
HOST_C_COMPILER
HOST_C_FLAGS
NATIVE_SYSTEM_NAME
NATIVE_C_COMPILER
NATIVE_C_FLAGS
The idea is that CMAKE_C_COMPILER (and company) is a variable like any other, so setting it inside a certain scope will only leave it changed within that scope.
Example usage:
use_host_compiler()
add_executable(foo foo.c) # Compiled with your host (computer)'s compiler.
use_native_compiler()
add_executable(bar bar.c) # Compiled with your native compiler (e.g. `avr-gcc`).
There is no proper way to change compiler for individual target.
According to cmake manual "Once set, you can not change this variable". This is about CMAKE_<LANG>_COMPILER.
The solution suggested by AnthonyD973 does not seem to work, which is sad of course. The ability to use several compilers in a project without custom_command things is very useful.
One solution (that I haven't tried yet) is to use
set_target_properties(your_target CXX_COMPILER_LAUNCHER foo_wrapper)
Then make foo_wrapper a script that just drops the first argument (which will be the default compiler, e.g. c++) and then calls the compiler you want.
There's also CXX_LINKER_LAUNCHER and the same for C_....
CMake is a make file generator. It generates a file that you can then use to build. If you want to more than one target platform, you need to run CMake multiple times with different generators.
So what you want to do is not possible in CMake, but with CMake: You can create a shell script that invokes CMake multiple times.