CMake won't build without set_source_files_properties with LANGUAGE CXX - c++

I have a small library that I have made (mostly wrappers for a more obtuse library underneath) which I have been compiling and using no problem in a contained project. I am now using this library in another project and have attempted to change the CMakeLists.txt appropriately (see below).
cmake_minimum_required (VERSION 3.5)
set(project "foobar")
project(${project} LANGUAGES CXX)
set(${project}_VERSION_MAJOR 0)
set(${project}_VERSION_MINOR 1)
add_library(${project} SHARED
./driver/foo.h
./driver/foo.c
./bar.cpp
./bar.hpp)
set_source_files_properties(./driver/foo.c PROPERTIES LANGUAGE CXX)
target_compile_features(${project}
PUBLIC
cxx_std_11)
target_include_directories(${project} PUBLIC ./driver/ .)
set_target_properties(${project} PROPERTIES LINKER_LANGUAGE CXX)
add_executable(bno055-test
./testingProject.cpp
)
target_link_libraries(test ${project})
install(
TARGETS ${project}
RUNTIME DESTINATION bin)
The error I have encountered is with the line set_source_files_properties(./driver/foo.c PROPERTIES LANGUAGE CXX). When it comes to compiling this C file with the C++ flag above I get many warnings of the type clang-8: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated [-Wdeprecated]. This is expected, as I am using deprecated methods and should not be compiling this file using the C++ flag. However, whenever I remove this line, or alter it to specify C instead of C++, my entire project no longer builds and fails with error:
CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
Missing variable is:
CMAKE_C_COMPILE_OBJECT
-- Generating done
CMake Generate step failed. Build files cannot be regenerated correctly.
Makefile:283: recipe for target 'cmake_check_build_system' failed
make: *** [cmake_check_build_system] Error 1
"/usr/bin/make -j4 all" terminated with exit code 2. Build might be incomplete.
I'm not familiar enough with CMake to see why this line of code and error are related like this. Is there some alternative piece of code I should include to create the missing variable CMAKE_C_COMPILE_OBJECT?
I assume that when I initially created this project using Eclipse this line was automatically generated and I am unclear as to why it now creates a problem when I had been compiling these files with the same CMakeLists.txt before (without library linking).
This is with clang#8.0.0 on Ubuntu 16.04.
Any help would be much appreciated! Apologies if I have missed something simple!

Is there some alternative piece of code I should include to create the missing variable CMAKE_C_COMPILE_OBJECT?
No, as the CMake error states, this is an "internal CMake variable" which should be initialized by CMake. It is not something you should have to set yourself. It should be set indirectly when you call project(). However, you only tell CMake you are using C++ (with CXX option) in the project() command. If you want CMake to make use of C and C++, you need to add both:
project(${project} LANGUAGES C CXX)
Even better, CMake enables C and C++ by default, so you can simply do:
project(${project})

Related

Issues when building C++ using CMake with Intel oneApi

I my library I use boost's float128 wrapper therefore changing the compiler is not an option.
Following Intel's developer guide I added find_package(IntelDPCPP REQUIRED) to my CMakeLists.txt and ran cmake -DCMAKE_C_COMPILER=icx -DCMAKE_CXX_COMPILER=icx -GNinja on the VS 2022 terminal. I get the following error message
Found package configuration file:
C:/Program Files (x86)/Intel/oneAPI/compiler/latest/windows/IntelDPCPP/IntelDPCPPConfig.cmake
but it set IntelDPCPP_FOUND to FALSE so package "IntelDPCPP" is considered
to be NOT FOUND. Reason given by package:
Unsupported compiler family and compiler icx!!
Anyone with a similar issue that can help out?
EDIT: as suggested by #Botje here the output information relevant to this case
IntelDPCPPConfig.cmake(84): string(COMPARE EQUAL ${CMAKE_CXX_COMPILER} nocmplr )
IntelDPCPPConfig.cmake(85): if(nocmplr)
IntelDPCPPConfig.cmake(93): if(NOT x${CMAKE_CXX_COMPILER_ID} STREQUAL xClang AND NOT x${CMAKE_CXX_COMPILER_ID} STREQUAL xIntelLLVM )
IntelDPCPPConfig.cmake(95): set(IntelDPCPP_FOUND False )
This is a known issue, it will be fixed in the OneAPI 2023.1 release.
You can try reversing the order of find_package and project or removing find_package(IntelDPCPP REQUIRED) in CMakeLists.txt. Because CMake identifies and sets up all the compiler-related variables when the project() is called.
Also, you can set the compiler option for the DPC++ compiler in CMakeLists.txt using the below command.
set(CMAKE_CXX_COMPILER dpcpp)

CMake Interface dependency with custom build type

So, I've found really strange behaviour in CMake creating dependency on target_link_library..
It's hard to explain in one sentence, so here is a list of requirements (I hope this all will make sence in the end)
your project must have custom build type defined through CMAKE_CONFIGURATION_TYPES ('Tools' in this example)
you must have at least 3 targets:
executable (or simply main target) (test-exe in this example)
interface library which link to main target (this could be something other than INTERFACE library, but the next target must be linked to it via interface property only) (test-env in this example)
static library which links to the interface library with specific generator expression, which is depends on custom build type (something like that 'target_link_libraries(test-env INTERFACE $<$CONFIG:Tools:test-lib>)') (test-lib in this example)
Here is the code of the CMakeLists.txt file to make it little bit clearer:
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)
set(CMAKE_CONFIGURATION_TYPES Debug Release Tools)
set(CMAKE_CXX_FLAGS_TOOLS ${CMAKE_CXX_FLAGS_DEBUG})
set(CMAKE_EXE_LINKER_FLAGS_TOOLS ${CMAKE_EXE_LINKER_FLAGS_DEBUG})
set(CMAKE_STATIC_LINKER_FLAGS_TOOLS ${CMAKE_STATIC_LINKER_FLAGS_DEBUG})
add_library(test-env INTERFACE)
# EXCLUDE_FROM_ALL used to not build this target by default
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Tools>:test-lib>)
add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)
(Files test-exe.cpp and test-lib.cpp are trivial, test-lib.cpp has a simple function, and test-exe.cpp declares this function and then calls it from main.)
When you would try to build this project with visual studio 2019/2017 generators (with "Tools" as configuration type of course: cmake --build . --config Tools), you will have next error:
LINK : fatal error LNK1104: cannot open file 'Tools\test-lib.lib' [<none_important_path_to_the_project>\test-exe.vcxproj]
And, what is important, you will not see in the terminal target test-lib being build.
So, what happened is target test-exe knows it must be linked against test-lib, but the build system doesn't know that target test-exe is dependent on target test-lib.
And now the most strange thing! If we will link this library like that: target_link_libraries(test-env INTERFACE $<$<CONFIG:Debug>:test-lib>) (so build type must be Debug), and still build project with Tools as a build type, you will see in the terminal that target test-lib is now building! (yes we have link error because test-exe can't find the function which is defined in test-lib, but this is at least expected)
So, what actually happens, the link flag of the target test-exe is correctly depends on the generator expression BUT, the actual build dependency, somehow, transforms any custom build type in this generator expression to the Debug.
Again this only happens with requirements I pointed up above, so it's not only the fault of generator expression, it's also connected to the interface dependency as well..
If we can't break any of the requirements, one possible solution will be to add direct dependency of test-lib target to test-env (like that: add_dependecies(test-env test-lib)), but this is not perfect, because even if we will use test-lib only then where is Tools as build type, we still will build this library each time, which can be undesired behavior.
I'm not really asking for solution here (but if you have one please share), I'm asking for the explanation why this even happening? Is this a bug or a really strange feature?
EDIT Small update I've found just now:
It must not even be the custom build type. The same bug can be encountered even with Release build type, so the final code can look as simple as this:
cmake_minimum_required(VERSION 3.19.0 FATAL_ERROR)
project(multiconfiguration-test LANGUAGES CXX)
add_library(test-env INTERFACE)
add_library(test-lib STATIC EXCLUDE_FROM_ALL "test-lib.cpp")
target_link_libraries(test-env INTERFACE $<$<CONFIG:Release>:test-lib>)
add_executable(test-exe "test-exe.cpp")
target_link_libraries(test-exe PRIVATE test-env)
and be build with next command: cmake --build . --config Release
Looks like a bug with the Visual Studio generator to me. I've just tested the Ninja Multi-Config generator both on Linux and on Windows and there cmake --build <build-dir> --config Release works just fine.

CMake not invoking FLEX/BISON

I have the following CMake file, which is part of a bigger project (and as such in its folder and imported by upper levels using add_subdirectory(...)
find_package(BISON REQUIRED)
find_package(FLEX REQUIRED)
include_directories(${PROJECT_SOURCE_DIR}/include/Parser)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
bison_target(XPathParser
XPath.yy
${CMAKE_CURRENT_BINARY_DIR}/XPathParser.cpp
DEFINES_FILE ${CMAKE_CURRENT_BINARY_DIR}/XPathParser.h)
flex_target(XPathScanner
XPath.flex
${CMAKE_CURRENT_BINARY_DIR}/XPathScanner.cpp
COMPILE_FLAGS "-Cm -B -L --c++ --nounistd")
add_flex_bison_dependency(XPathScanner XPathParser)
set_source_files_properties(${BISON_XPathParser_OUTPUTS}
${FLEX_XPathScanner_OUTPUTS}
PROPERTIES
COMPILE_FLAGS -Wno-sign-compare
COMPILE_FLAGS -Wno-effc++)
add_library(xpath OBJECT
${BISON_Parser_OUTPUTS}
${FLEX_Lexer_OUTPUTS}
${CMAKE_CURRENT_LIST_DIR}/XPathParserDriver.cpp)
In my knowledge, this CMake should execute FLEX and BISON, that in turn would generate the C++ files, before the actual C++ compiler invocation.
For some reason beyond my understanding, this is not true. I tried to clear CMake cache and rerun it from scratch; still, there is no sign of FLEX nor BISON within the CMake generated files.
Of course, CMake finds both FLEX and BISON and properly sets the bison_target and flex_target macros (I tested it by messing with them adding random values: CMake gets angry and throws me an error).
Any clue on what is going on and what am I missing?
In add_library, you add BISON_Parser_OUTPUTS and FLEX_Lexer_OUTPUTS dependencies. Instead, it should be BISON_XPathParser_OUTPUTS and FLEX_XPathScanner_OUTPUTS respectively (since you gave them such names).

CMake Command Line Definitions Not Perpetuating To Toolchain File

I have a cmake cross compiler toolchain file, abridged as:
set(CMAKE_SYSTEM_NAME Linux)
if( DEFINED TC_PATH )
message( STATUS " TC_PATH IS defined. ${TC_PATH}" )
else()
message( FATAL_ERROR " TC_PATH not defined." )
endif()
set(CMAKE_C_COMPILER ${TC_PATH}/usr/bin/i586-linux/i586-linux-gcc )
set(CMAKE_CXX_COMPILER ${TC_PATH}/usr/bin/i586-linux/i586-linux-g++ )
set(CMAKE_LINKER ${TC_PATH}/usr/bin/i586-linux/i586-linux-ld )
I call cmake, setting the TC_PATH as well as the toolchain file:
~/CMakeTest/output $ cmake -DTC_PATH:PATH=/opt/toolchain -DCMAKE_TOOLCHAIN_FILE=../toolchain.cmake ../
It appears cmake is invoking the toolchain file multiple times. On the first two time, the TC_PATH check succeeds, but later, after identifying the compilers, it throws an error:
-- TC_PATH IS defined. /opt/toolchain
-- TC_PATH IS defined. /opt/toolchain
-- The C compiler identification is GNU 4.9.1
-- The CXX compiler identification is GNU 4.9.1
-- Check for working C compiler: /opt/toolchain/usr/bin/i586-linux/i586-linux-gcc
CMake Error at /home/gnac/CMakeTest/toolchain.cmake:4 (message):
TC_PATH not defined.
Call Stack (most recent call first):
/home/gnac/CMakeTest/output/CMakeFiles/3.0.2/CMakeSystem.cmake:6 (include)
CMakeLists.txt:2 (project)
So, outside of setting a permanent environment variable in the shell, how I can set the TC_PATH variable via the command line so that it will be remain in context while executing the cmake generate command?
When compiling a test project, CMake does not pass variables to it by default.
There is CMAKE_TRY_COMPILE_PLATFORM_VARIABLES option for passing variables into the test project.
In order to fix your issue, this line should be put into the toolchain file:
set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES TC_PATH)
Your toolchain needs to be self-sufficient. The step that fails is a try_compile() which is not getting your cached variables.
Your toolchain file does not look like you're cross-compiling (it does not have a CMAKE_SYSTEM_NAME) so you can do one of the following (besides setting the CC and CXX environment variables as you have mentioned):
It's sufficient to give the full path to your C and/or CXX compiler (depending on which languages you enabled), CMake will detect the rest of your GNU toolchain automatically
cmake -DCMAKE_C_COMPILER:PATH=/opt/toolchain/usr/bin/i586-linux/i586-linux-gcc
-DCMAKE_CXX_COMPILER:PATH=/opt/toolchain/usr/bin/i586-linux/i586-linux-g++ ...
Add the following to your toolchain to skip the compiler tests (because not all options may be passed to it or because your compiler/linker of choice will not produce a valid executable)
set(CMAKE_C_COMPILER_WORKS 1 CACHE INTERNAL "")
set(CMAKE_CXX_COMPILER_WORKS 1 CACHE INTERNAL "")
Or just use the CMakeForceCompiler macros, but the use is "Discouraged. Avoid using this module if possible."
Use configure_file() to put the path into your toolchain file (just make sure to do it before the project() call)
Prefer find_program() if the possible paths of your toolchain are known over setting it from the outside (see e.g. here)
References
CMake FAQ: How do I use a different compiler?
how to specify new gcc path for cmake
CMake Cross Compiling
cmake: problems specifying the compiler (2)
cmake cross-compile with specific linker doesn't pass arguments to armlink
CMake: In which Order are Files parsed (Cache, Toolchain, …)?
I am sorry that I have to revive this but I'm still wondering why I need to resort to hacks like this to propagate variables to the toolchain configuration file:
...
elseif(${OS_FSFW} STREQUAL linux AND TGT_BSP)
if(NOT SOME_VARIABLE_USED_BY_TOOLCHAINFILE)
set(ENV{SOME_VARIABLE_USED_BY_TOOLCHAINFILE} "$ENV{HOME}/raspberrypi/rootfs")
else()
set(ENV{SOME_VARIABLE_USED_BY_TOOLCHAINFILE} "${SOME_VARIABLE_USED_BY_TOOLCHAINFILE}")
endif()
set(CMAKE_TOOLCHAIN_FILE
${CMAKE_CURRENT_SOURCE_DIR}/buildsystem/cmake/CrossCompileConfig.cmake
)
endif()
I mean, it works, but why is the toolchain file unable to handle variables set by the upper CMakeList properly? CMake is even able to print out variables set that way, but doing things like checking their existence does not appear to work unless they are environmental variables.

CMake 3.0 add_library of type INTERFACE breaks get_target_property

I want to add a header only directory to a cmake project which I am using in Windows 7 with Visual Studio 2013 Update 2. I did some research and came up with this Cmakelists.txt file:
add_library(AAA_lib INTERFACE)
target_include_directories(AAA_lib
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
)
This appears to work however in some of our internal cmake code we call get_target_property:
get_target_property(target_libraries ${target} LINK_LIBRARIES)
This generates a CMake error:
CMake Error at x_common_libs/xml/xsdmap.cmake:41 (get_target_property):
INTERFACE_LIBRARY targets may only have whitelisted properties. The
property "LINK_LIBRARIES" is not allowed.
It seems like an odd error since a get should only return targets with the appropriate property. Is this a bug in CMake? Or is there some other way that this should be implemented?
Why do we need to call get_target_property?
We have a cmake helper function which recursively goes through all of dependencies of a project building up a list of all dependent projects that require some custom post processing. So if project X uses project B and C and C uses D, then we get a list of X, B, C, D and then check to see which directories match a requirement and then call a custom_command.
Thanks,
Jason
Seems that it is CMake bug. There is new target type in CMake 3.0 called INTERFACE_LIBRARY. You are supposed to use only some of properties for this type. However, I don't think it was expected to raise an error in case of reading other properties.
I came out with the following workaround:
get_target_property(_TARGET_TYPE ${target} TYPE)
if(_TARGET_TYPE STREQUAL "INTERFACE_LIBRARY")
unset(target_libraries)
else()
get_target_property(target_libraries ${target} LINK_LIBRARIES)
endif()
This is a restriction that was lifted in CMake 3.19.
See https://gitlab.kitware.com/cmake/cmake/-/issues/19145 for details.