I'd like to detect the current project language, for example if I have something like this:
cmake_minimum_required (VERSION 3.0)
project (foo VERSION 1.0 LANGUAGES CXX)
I need something like this
if (project_lang EQUAL "CXX")
# do something for c++
endif ()
Thanks!
You can use global property ENABLED_LANGUAGES:
get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES)
message("languages: ${languages}")
for project(Foo), i.e. default values:
languages: C;CXX;RC
for project(Foo LANGUAGES CXX), i.e. C++ project:
languages: CXX;RC
for project(Foo LANGUAGES C), i.e. C project:
languages: C;RC
etc.
The best command to check that the exact language is enabled is if(... IN_LIST ...) (available since CMake 3.3):
if("CXX" IN_LIST languages)
message("C++ enabled")
endif()
Related
How do I add the math library to my CMake file? This post references adding a target link library, yet I am not too familiar with C. An Additional post - Could someone please demonstrate an example. Documentation I am using C and I receive an undefined reference to 'pow' with the pow method of the math header.
cmake_minimum_required(VERSION 3.3)
project(CSCI-E-28-Unix-Linux-Systems-Programming)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
set(SOURCE_FILES
CMakeLists.txt
getchar.c
main.cpp
hw0
more01.c)
#target_link_libraries(<math.h> m)
add_executable(main main.cpp)
add_executable(getchar getchar.c)
add_executable(more01 more01.c)
add_executable(argu print_all_arguments.c)
add_executable(chars chars.c)
add_executable(ch4 ch4.c)
Many mathematical functions (pow, sqrt, fabs, log etc.) are declared in math.h and require the library libm to be linked. Unlike libc, which is automatically linked, libm is a separate library and often requires explicit linkage. The linker presumes all libraries to begin with lib, so to link to libm you link to m.
You have to use it like target_link_libraries(ch4 m) to link libmto your target. The first argument must be a target. Thus it must be used after add_executable(ch4 ch4.c) like:
add_executable(ch4 ch4.c)
target_link_libraries(ch4 m)
For various targets it's a good idea to test if adding a library is needed or not and if so where it's located of how it's named. Here's one way to do it:
:
include(CheckLibraryExists)
CHECK_LIBRARY_EXISTS(m sin "" HAVE_LIB_M)
if (HAVE_LIB_M)
set(EXTRA_LIBS ${EXTRA_LIBS} m)
endif (HAVE_LIB_M)
:
//More tests & build-up of ${EXTRA_LIBS}
:
add_executable(ch4 ch4.c)
target_link_libraries(ch4 PUBLIC ${EXTRA_LIBS})
For targets where libm is part of libc, the above test should fail, i.e. ${EXTRA_LIBS} will miss it and target_link will not try to add.
I am frankly a bit surprised that this kind of question still doesn't have a proper answer for Modern CMake. These days, the recommended (and portable) approach is this:
find_library(MATH_LIBRARY m)
if(MATH_LIBRARY)
target_link_libraries(MyTarget PUBLIC ${MATH_LIBRARY})
endif()
In a project with a mixture of C++ and C code in one directory, I need the -std=c++11 flag to apply for the C++ code, but not the C code. (Because that causes an error on MacOS.)
Currently I do this:
add_compile_options( -std=c++11 )
However, there don't seem to be any options on the add_compile_options() function to allow me to specify that these flags should only be used for C++ files.
In autotools this would be achieved by setting CXXFLAGS for C++ and CFLAGS for C code. Is there some way to do the same in CMake?
Don't use add_compile_options for anything, ever! In the worst case, you can use target_compile_options, but for setting the language standard, CMake has special support that should always be preferred.
For the target you want to compile as C++11, simply write:
target_compile_features(my_target PRIVATE cxx_std_11)
You should use the target_compile_features in other answer, if not, use set_property as also presented in other answer. Still, you can pass compile_options specifically to C++ compiler with generator expression:
# prefer other answers to it
add_compile_options(
$<$<COMPILE_LANGUAGE:CXX>:-std=c++11>
)
Here is one way to do it. Note you must specify the required property. And I like to disable extensions to not rely on any compiler specific flags.
set_target_properties(myTarget
PROPERTIES
CXX_STANDARD 11
CXX_STANDARD_REQUIRED YES
CXX_EXTENSIONS NO
)
This can be done using
# Setting your C++ standard.
set_property(TARGET your_target PROPERTY CXX_STANDARD 11)
# Setting your C standard.
set_property(TARGET your_target PROPERTY C_STANDARD 11)
Of course the standard number has to be a supported version number:
For C++ this includes: 98, 11, 14, 17, 20 and 23.
For C this includes: 90, 99 and 11.
You do not have to use both of them. You can thus ask CMake to use C++11 while still using the default C standard.
At the beginning I had a bunch of CMake projects handled separately: each one had its own target for generating documentation called doc. Now I need to wrap all these projects with a super-project: the problem is that super-project compilation fails complaining that exist multiple targets with the same name doc.
The simple solution I thought is to prepend each doc target with the name of the project, but it does not satisfy me.
I would like not to have to use make projectX_doc when compiling a single sub-project and to have a global target make doc for generating the documentation of all projects when compiling super-project.
Are my requests possible? Is there any mechanism to handle target collision?
well each subproject could verify if there are inside a super project with:
if("^${CMAKE_SOURCE_DIR}$" STREQUAL "^${PROJECT_SOURCE_DIR}$")
set(IS_SUBPROJECT FALSE)
else()
set(IS_SUBPROJECT TRUE)
endif()
Thus in your projects CMakeLists.txt you can do:
if (NOT IS_SUBPROJECT)
set(DOC_TGT doc)
else()
set(DOC_TGT ${PROJECT_NAME}_doc)
endif()
add_custom_target(${DOC_TGT} EXCLUDE_FROM_ALL ...
note: you can merge both snippets to avoid IS_SUBPROJECT variable
In your super project CMakeLists.txt:
add_custom_target(doc EXCLUDE_FROM_ALL
DEPENDS projectX_doc projectY_doc...
So when configuring/building each sub project standalone you have
make doc otherwise when you are in your super project target doc become a meta target...
note: You can also use this trick to modify default options etc...
e.g. gflags:
https://github.com/gflags/gflags/blob/master/CMakeLists.txt#L126
https://github.com/gflags/gflags/blob/master/cmake/utils.cmake#L61
https://github.com/gflags/gflags/blob/master/CMakeLists.txt#L163
There are plenty of examples of using cmake to set a preprocessor value. I'm having the reverse problem -- I want to find the value of __GLIBCXX__ and then perform other cmake commands conditionally based on the result.
Up until now, I had been using the GCC version as a surrogate for libstdc++ functionality, like this:
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6)
....
# other gcc versions
....
endif()
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
# and so on
endif()
The problem I'm now having is the fallout from a known issue with libstdc++ and gcc-4.8 c++11 regex support, and the fact on many setups clang reuses the system libstdc++, therefore inheriting the same problem. Under these circumstances, there's no version test for clang that will help, since it's specifically related to libstdc++, and my surrogate method of using the compiler version no longer works.
In order to fallback on Boost.Regex or PCRE if either clang or gcc are using the libstdc++ distributed with gcc-4.8 or earlier, the best way I can think of is to check if __GLIBCXX__ <= 20140404, but I can't see how to get cmake to do it in a straight-forward way, since clang might not always be using libstdc++, e.g. most OS X systems.
CheckVariableExists doesn't seem to help, I suppose for at least two reasons; firstly, a preprocessor macro isn't a variable, and secondly, it doesn't give the value, only indicates its presence.
You could use CHECK_CXX_SOURCE_COMPILES to compile a specific test which fails when your condition is not met:
INCLUDE (CheckCXXSourceCompiles)
CHECK_CXX_SOURCE_COMPILES(
"
#include <cstdio>
#ifdef __GLIBCXX__
#if __GLIBCXX__ <= 20140404
#error test failed
#endif
#endif
int main() { return 0;}
" GLIBCXX_TEST)
IF(NOT GLIBCXX_TEST)
MESSAGE(STATUS "__GLIBCXX__ test failed")
ENDIF()
Based on m.s.'s idea and taking Marc Glisse's observation about __GLIBCXX__ not being a reliable way to test for this, I wrote a CMake module to test for broken implementations of regex support. In order for this test to pass, the compiler will need to be targetting C++11 or higher.
Gist is here: https://gist.github.com/anonymous/7520ce6f64c63e2f8e79
Sample use:
include(CheckForRegex)
check_cxx_native_regex_works(USE_NATIVE_REGEX)
add_definitions("-DUSE_NATIVE_REGEX=${USE_NATIVE_REGEX}")
if (NOT USE_NATIVE_REGEX)
find_package(Boost REQUIRED COMPONENTS regex)
endif()
In the multi-platform/os project I'm working on, I'm striving to simplify the platform specific code into subdirectories, with a common directory holding a common implementation. I have a prototype implementation in autotools, but want to move to a cmake implementation if possible. My current sticking point is how to support multiple OSes. My current filesystem structure looks like the following:
/* A common header file for all platforms that presents an interface */
include/my_socket_utils.h
include/my_time_utils.h
/* Platform specific source files */
src/common/my_socket_utils.cpp
src/linux/my_socket_utils.cpp
src/vxworks/my_socket_utils.cpp
src/qnx/my_socket_utils.cpp
src/common/my_time_utils.cpp
src/vxworks/my_time_utils.cpp
The idea is that there is a common interface and a "common" implementation. The implementation is either a stub or a common implementation written to a posix standard that allows it to work for most platforms. Those platforms that require a custom implementation MAY override the common one, but it's optional.
With autotools, I am able to achieve this using VPATH to set a source tree hierarchy, so I set:
VPATH=#srcdir#/src/#target_platform#;#srcdir#/src/common
This makes autotools look for the source file in src/#target_platform# first, then, if it wasn't found, grab it from src/common.
What is the cmake way to do this?
Update:
To help all those lost souls in need, this is what I ended up doing for the time being. I'm not sure it's the best solution, but it works well enough.
FILE(GLOB common_files "src/common/.c")
FILE(GLOB platform_files "src/${os}/.c)
Then, do the dirty n^2 algorithm to override. Not sure how to do any better in cmake "script", but the number of files is low, so it's plenty fast. The diag messages are, of course, optional.
#
# For each common file, check to see if a platform file exists to override it.
#
foreach(fqfn ${common_files})
set(platform_override FALSE)
get_filename_component(filename ${fqfn} NAME)
#
# If filename exists in platform, override it with the platform,
# otherwise fall back to the common implementation. Oh for a real
# language.
#
foreach(platform_fqfn ${platform_files})
get_filename_component(platform_filename ${platform_fqfn} NAME)
message("pf=${platform_filename} cf=${filename}")
if(filename STREQUAL platform_filename)
message("filename == platform_filename")
list(APPEND proj_files ${platform_fqfn})
set(platform_override TRUE)
endif(filename STREQUAL platform_filename)
endforeach(platform_fqfn ${platform_files})
if(NOT ${platform_override})
list(APPEND proj_files ${fqfn})
message("Appended ${fqfn}")
endif(NOT ${platform_override})
endforeach(fqfn ${common_files})
message("proj_files=${proj_files}")
add_executable (cc_dfi_main ${proj_files})
One possible way is to define variable TARGET_BUILD_PLATFORM and set it to exact platform you want to build (linux/qnx/vxworks).
set(PROJECT_NAME some_name_for_project)
project(${PROJECT_NAME} CXX)
file(GLOB COMMON_SRC ${PROJECT_SOURCE_DIR}/common/*.cpp)
file(GLOB PLATFORM_SRC ${PROJECT_SOURCE_DIR}/${TARGET_BUILD_PLATFORM}/*.cpp)
set(SRC_FILES ${COMMON_SRC} ${PLATFORM_SRC})
add_executable(${PROJECT_NAME} ${SRC_FILES})