Short version: I have build options that only work on one platform. The autotools file I'm converting form has a check of the form if test "$platform_linux" != "yes". Can I do the same thing in my CMakeLists.txt (test if the value is NOT equal)?
Slightly longer version: I've got a test for various platforms following the advice found here:
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
# Linux specific code
SET(OperatingSystem "Linux")
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
I'd like to do a test of the form IF(${CMAKE_SYSTEM_NAME} NOT MATCHES "Linux"). This doesn't appear to work, and the only documentation I can find is a mailing-list post from 2002, which suggests the NOT isn't valid for cmake prior to 1.2. [Link].
Is this still the case in later cmake versions, specifically 2.6 and/or 2.8?
You're close! The correct syntax for IF is
IF(NOT <expression>)
So in your specific case, you want
IF(NOT ${CMAKE_SYSTEM_NAME} MATCHES "Linux")
Related
I have cross compiled a software for an HummingBoard-Pro (arm processor).
The software just receives some data using the lcm protocol.
If I use the cross compiled software, the data received by the application are invalid, while if I use on-board compiled software everything works fine.
-The software is exactly the same!
-I cross compiled using cmake and a specific arm toolchain.
Output example of cross compiled sw:
first value 5.73599e+107
second value 5.73599e+107
third value 5.73599e+107
Output example of on board compiled sw:
first value 1
second value 2
third value 3
Note: It's my first cross compilation attempt so probably something goes wrong but I haven't really idea about what.
CMakelists file
cmake_minimum_required(VERSION 3.1)
set(main_project_dir ${CMAKE_CURRENT_SOURCE_DIR})
set(external_dir ${main_project_dir}/external)
set(external_lcm_dir ${external_dir}/lcm_dir)
set(external_lcm ${external_lcm_dir}/lcm)
set(external_lcm_build ${external_lcm}/build)
set(external_lcm_gen_exe /usr/local/bin/lcm-gen)
set(lcm_input_file ${main_project_dir}/lcm_format_files/lcm_input_files/indrive.sensors.vanet.lcm)
set(lcm_libraries ${main_project_dir}/external/lcm_dir/lcm/build/lcm)
set(lmc_libraries_header ${main_project_dir}/external/lcm_dir/lcm/)
set(lcm_autogenerated_dir ${main_project_dir}/build/lcm_autogenerated_classes)
add_custom_target(
generate-lcm
COMMAND ${external_lcm_gen_exe} -x ${lcm_input_file} --cpp-hpath ${lcm_autogenerated_dir}
COMMENT "=================== Generating lcm files..."
)
add_subdirectory(testSender)
add_subdirectory(testReceiver)
TOOLCHAIN FILE
SET (CMAKE_SYSTEM_NAME Linux)
SET (CMAKE_SYSTEM_VERSION 1)
SET (CMAKE_SYSTEM_PROCESSOR arm)
INCLUDE_DIRECTORIES(/usr/hummingboard/usr/include /usr/hummingboard/include /usr/hummingboard/usr/include/arm-linux-gnueabihf/)
LINK_DIRECTORIES(/usr/hummingboard/usr/lib /usr/hummingboard/lib /usr/hummingboard/lib/arm-linux-gnueabihf )
SET(CMAKE_PREFIX_PATH /usr/arm-linux-gnueabihf/lib/
/usr/hummingboard/
/usr/hummingboard/lib/arm-linux-gnueabihf/
/usr/hummingboard/usr
/usr/hummingboard/usr/lib/arm-linux-gnueabihf/
)
SET (CMAKE_C_COMPILER /usr/bin/arm-linux-gnueabi-gcc)
SET (CMAKE_CXX_COMPILER /usr/bin/arm-linux-gnueabi-g++)
SET (CMAKE_FIND_ROOT_PATH /usr/hummingboard/ /usr/hummingboard/usr)
SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY)
SET (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
Turning my comments into an answer
Your toolchain file looks like a mixture of two GNU toolchains, which is not allowed and could explain strange behavior of your software.
I would e.g. expect there to be a /usr/hummingboard/bin directory. And shouldn't there be a arm-linux-gnueabihf-gcc to match with /usr/arm-linux-gnueabihf/lib/.
My guess would be that you are mixing hard-float (hf) with soft-float libraries and native- with cross-compilers.
It gets visible with the value 5.73599e+107 = 0x7f800000 which means infinite.
To find the root-cause I would recommend to check your floating point settings. Please compare the compiler command lines between both builds (working vs. non-working) using verbose makefiles.
References
Assign infinity to float
Using CMake with GNU Make: How can I see the exact commands?
Disclaimer: I'm aware of this question. However, The OP's needs are different to mine: what he actually wants is to port an app to Linux and therefore the answers go in that line, not answering what I want to know: the reasons of the error.
I'm trying to create a dropdown list in CMake GUI following the instructions in here and here
So I have this very simple CMakeLists.txt:
cmake_minimum_required(VERSION 3.6)
project(datasetprograms)
set(CMAKE_CXX_STANDARD 11)
#LINES TO MAKE THE GUI DROP-DOWN:
set(TARGET_ARCHITECTURE “arm” CACHE STRING “Architecture to compile to”)
set_property(CACHE TARGET_ARCHITECTURE PROPERTY STRINGS arm x86)
#Add subdirectories for each project
add_subdirectory(helloworld)
Basically I just copied and pasted, following the instructions. However, instead of having a nice drop-down in the CMake GUI, I got the following error:
CMake Error at CMakeLists.txt:9 (set_property): set_property could
not find CACHE variable TARGET_ARCHITECTURE. Perhaps it has not yet
been created
Question: What I'm doing wrong?
You may check value of variable TARGET_ARCHITECTURE using message() and you will found CACHE is a part of that value.
This is because you use in set() command double quotes which are not common ones (") but language-specific (“). So CMake treats set() command as not CACHE'd one. That is a reason of the error message.
So I am writing a CMake module to find some libraries which is being used a lot in our company. These libraries all have different versions and are such a mess here. In a certain library, even the name of header files and binary files don't match. So I am writing a CMake script to handle all the problems of finding each library once and for all. What I have in my mind is to write something like how we find boost packages but include the version of each component as well. Something like this:
find_package(OrgName COMPONENTS librarya-1.4.3 libraryb-2.3.1 libraryc-3.6.0)
So I created a FindOrgName.cmake file and iterated on the requested components, then I processed the string which is passed and gained the library name along with its version information something like this (never mind the difference between include and binary files):
IF(OrgName_FIND_COMPONENTS)
FOREACH(comp ${OrgName_FIND_COMPONENTS})
SET(OrgName_${comp}_FOUND 0)
STRING(FIND ${comp} "-" dashind REVERSE)
STRING(LENGTH ${comp} length)
STRING(SUBSTRING ${comp} 0 ${dashind} name)
MATH(EXPR s "${dashind}+1")
MATH(EXPR l "${length}-${dashind}-1")
STRING(SUBSTRING ${comp} ${s} ${l} version)
SET(OrgName_${name}_INCLUDE_DIR "/usr/local/include/OrgName/${comp}/")
find_library(OrgName_${comp}_LIBRARIES NAMES "${comp}" HINTS "/usr/lib")
IF(OrgName_${comp}_INCLUDE_DIR AND OrgName_${comp}_LIBRARIES)
SET(OrgName_${comp}_FOUND 1)
ENDIF()
IF(NOT OrgName_${comp}_FOUND AND OrgName_FIND_REQUIRED_${comp})
MESSAGE(FATAL_ERROR "OrgName ${comp} not available.")
ENDIF()
SET (OrgName_INCLUDE_DIR ${OrgName_INCLUDE_DIR} ${OrgName_${comp}_INCLUDE_DIR})
SET (OrgName_LIBRARIES ${OrgName_LIBRARIES} ${OrgName_${comp}_LIBRARIES})
ENDFOREACH()
ENDIF()
Now here is the problem, imagine someone didn't enter the version part in components names. I want to search for the versions which he has installed (assume the path to library is always the same) and use the last version it can find, so I have to search for the files which their name contains the library name (${name}). First of all how can I do this? Second, Am I doing things right? I mean is there an easier way to do this task?
OK, after a lot of searching and getting exhausted I finally found a solution. I just need to use the following command:
file(GLOB files "Mylib*")
Which will create a list named files and adds each file that its name matches the pattern "Mylib*" to it. I really don't know why they didn't implement it in find_file command but never mind, I'll put it here in case anyone got confused like me.
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()
Note: This is my first time using CMake. I don't know much about it, so I'm just posting a bunch of information to see if anyone can see my problem.
I would like the ability to automatically determine which c++11 flag is appropriate, given my compiler. There are many examples of this line. Here is my CMakeLists.txt following such an example:
cmake_minimum_required (VERSION 2.8)
#Add the c++11 flag, whatever it is
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X)
if(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
elseif(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
else()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler.")
endif()
project(AnalyzeGames)
set(AnalyzeGames_SRCS AnalyzeGames.cpp)
add_executable(AnalyzeGames ${AnalyzeGames_SRCS})
Here is my cmake output when trying to use this file: http://pastebin.com/3AUwqffD
Here is CMakeError.log: http://pastebin.com/EbNKvGt8
Here is CMakeOutput.log: http://pastebin.com/kVJ0enJC
echo $CC: /usr/bin/gcc
echo $CXX: /usr/bin/g++
I can compile a simple test executable with g++ using either flag manually.
cmake --version: cmake version 2.8.12.2
For some reason CMake is not recognizing that my compiler does support both of those flags.
The cmake output tells you that it does not recognize the '.cxx' extension because it doesn't know that your project is a C++ project. To fix this, you should enable C++ in the project command. Try to change the following line:
project(AnalyzeGames)
to:
project(AnalyzeGames CXX)
and then move it to the 2nd line of the CMakeLists.txt, right under cmake_minimum_required. The configuration should work as expected after this.
TLDR
Compiler checks are only performed in the variable passed is not previously defined, which includes in the cache from previous failed attempts. Use unset(my_var CACHE) to force checking to always occur, or just be aware of this behaviour and clear the cache manually when needed.
Detail
I too had this problem (with cmake 2.8.12.2) and I had to turn on trace output, and step through the code to get a similar toy build to work I had make sure the variables I used (COMPILER_SUPPORTS_CXX11_*) in these calls:
CHECK_CXX_COMPILER_FLAG(-std=c++11 COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG(-std=c++0x COMPILER_SUPPORTS_CXX0X)
Were set such that they named themselves:
set(COMPILER_SUPPORTS_CXX11 "COMPILER_SUPPORTS_CXX11")
The other posters solution didn't work for me, it mainly just seemed to limit the detecting of compilers to just CXX and ignored the C compiler.
The issue appears to be with this line of code in the cmake module:
if("${VAR}" MATCHES "^${VAR}$")
Which in the trace output is:
/usr/share/cmake/Modules/CheckCXXSourceCompiles.cmake(30): if(COMPILER_SUPPORTS_CXX0X MATCHES ^COMPILER_SUPPORTS_CXX0X$ )
It looks as if the expression on the left of the MATCHES is replaced with the variables value, but the expression on the right is assumed to be plain text.
If the MATCH fails then the main part of the macro is skipped and according the to the log the check fails.
Looking at later versions of this macro online it looks as if this line has changed to only perform the compile check if the variable is undefined.
It as at this point that I realise that this is the intent / hack of the original code; if the X is undefined then "X" MATCHES "^X$" will be true, but then the compile check can be performed, fail for some other reason and then never be performed again.
So the solution is either force unset of variable in cache before calling the macro using:
unset(COMPILER_SUPPORTS_CXX0X CACHE)
Or clear the cache manually and be prepared for this behaviour.