I'm trying to compile a project I recently started working on, and was asked to compile the code in clang instead of gcc. There is a CMake file for the project, and I tried to cmake the project using
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ../src
However an error is thrown, which I believe is because clang doesn't have a Fortran compiler and part of the project has Fortran code. Is there a way to make it use gfortran (previously used when gcc is used) when compiling the Fortran code, and clang/clang++ for the rest?
The part of the cmake file which I think is relevant is:
enable_language(Fortran)
string(REGEX MATCH gfortran HAVE_GFORTRAN ${CMAKE_Fortran_COMPILER})
string(REGEX MATCH xlf HAVE_XLF ${CMAKE_Fortran_COMPILER})
string(REGEX MATCH pg77 HAVE_PG77 ${CMAKE_Fortran_COMPILER})
string(REGEX MATCH g77 HAVE_G77 ${CMAKE_Fortran_COMPILER})
string(REGEX MATCH ifort HAVE_ifORT ${CMAKE_Fortran_COMPILER})
string(REGEX MATCH f77 HAVE_F77 ${CMAKE_Fortran_COMPILER})
if(HAVE_GFORTRAN)
set(F_LIBRARY gfortran CACHE string "fortran library")
find_library(F_LIBRARY NAMES gfortran)
set(FORTRAN_UNDERSCORE end CACHE string "What type of fortran underscore style - linux,end,none")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_END")
elseif(HAVE_XLF)
set(F_LIBRARY xlf90 CACHE string "fortran library")
find_library(F_LIBRARY NAMES xlf90)
set(FORTRAN_UNDERSCORE none CACHE string "What type of fortran underscore style - linux,end,none")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_NONE")
elseif(HAVE_PGF77)
set(F_LIBRARY pgftnrtl CACHE string "fortran library")
find_library(F_LIBRARY NAMES pgftnrtl)
set(FORTRAN_UNDERSCORE end CACHE string "What type of fortran underscore style - linux,end,none")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_END")
elseif(HAVE_G77)
set(F_LIBRARY g2c CACHE string "fortran library")
find_library(F_LIBRARY NAMES g2c)
set(FORTRAN_UNDERSCORE linux CACHE string "What type of fortran underscore style - linux,end,none")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_LINUX")
elseif(HAVE_ifort)
set(F_LIBRARY ifcore CACHE string "fortran library")
find_library(F_LIBRARY NAMES ifcore)
set(FORTRAN_UNDERSCORE end CACHE string "What type of fortran underscore style - linux,end,none")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_END")
elseif(HAVE_F77)
set(FORTRAN_UNDERSCORE end CACHE string "What type of fortran underscore style - linux,end,none")
set(FORTRAN_LIBRARY "" CACHE string "fortran library")
set(DEF_FORTRAN_UNDERSCORE "#define FORTRAN_UNDERSCORE_END")
endif()
# f77 on redstorm currently an exception - doesn't need it
if(NOT F_LIBRARY AND NOT HAVE_F77)
message(FATAL_ERROR "Cannot find fortran library")
endif(NOT F_LIBRARY AND NOT HAVE_F77)
Terminal output says that this is threw an error when I tried cmake:
message(FATAL_ERROR "Cannot find fortran library")
Please let me know if I need to post any more info. Many thanks in advance!
In order not to leave the question open:
The variable CMAKE_Fortran_COMPILER must be set to the name of the compiler executable (gfortran) if cmake is not able to determine it automatically.
Related
I am a novice in the filed of CMake and I learn how to write my own find_package() module by following the example in the book CMake Cookbook. The following CMakeLists.txt file is provided with the official example.
if(NOT ZeroMQ_ROOT)
set(ZeroMQ_ROOT "$ENV{ZeroMQ_ROOT}")
endif()
if(NOT ZeroMQ_ROOT)
find_path(_ZeroMQ_ROOT NAMES include/zmq.h)
else()
set(_ZeroMQ_ROOT "${ZeroMQ_ROOT}")
endif()
find_path(ZeroMQ_INCLUDE_DIRS NAMES zmq.h HINTS ${_ZeroMQ_ROOT}/include)
if(ZeroMQ_INCLUDE_DIRS)
set(_ZeroMQ_H ${ZeroMQ_INCLUDE_DIRS}/zmq.h)
function(_zmqver_EXTRACT _ZeroMQ_VER_COMPONENT _ZeroMQ_VER_OUTPUT)
set(CMAKE_MATCH_1 "0")
set(_ZeroMQ_expr "^[ \\t]*#define[ \\t]+${_ZeroMQ_VER_COMPONENT}[ \\t]+([0-9]+)$")
file(STRINGS "${_ZeroMQ_H}" _ZeroMQ_ver REGEX "${_ZeroMQ_expr}")
string(REGEX MATCH "${_ZeroMQ_expr}" ZeroMQ_ver "${_ZeroMQ_ver}")
set(${_ZeroMQ_VER_OUTPUT} "${CMAKE_MATCH_1}" PARENT_SCOPE)
endfunction()
_zmqver_EXTRACT("ZMQ_VERSION_MAJOR" ZeroMQ_VERSION_MAJOR)
_zmqver_EXTRACT("ZMQ_VERSION_MINOR" ZeroMQ_VERSION_MINOR)
_zmqver_EXTRACT("ZMQ_VERSION_PATCH" ZeroMQ_VERSION_PATCH)
# We should provide version to find_package_handle_standard_args in the same format as it was requested,
# otherwise it can't check whether version matches exactly.
if(ZeroMQ_FIND_VERSION_COUNT GREATER 2)
set(ZeroMQ_VERSION "${ZeroMQ_VERSION_MAJOR}.${ZeroMQ_VERSION_MINOR}.${ZeroMQ_VERSION_PATCH}")
else()
# User has requested ZeroMQ version without patch part => user is not interested in specific patch =>
# any patch should be an exact match.
set(ZeroMQ_VERSION "${ZeroMQ_VERSION_MAJOR}.${ZeroMQ_VERSION_MINOR}")
endif()
if(NOT ${CMAKE_C_PLATFORM_ID} STREQUAL "Windows")
find_library(ZeroMQ_LIBRARIES
NAMES
zmq
HINTS
${_ZeroMQ_ROOT}/lib
${_ZeroMQ_ROOT}/lib/x86_64-linux-gnu
)
else()
find_library(ZeroMQ_LIBRARIES
NAMES
libzmq
"libzmq-mt-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
"libzmq-${CMAKE_VS_PLATFORM_TOOLSET}-mt-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
libzmq_d
"libzmq-mt-gd-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
"libzmq-${CMAKE_VS_PLATFORM_TOOLSET}-mt-gd-${ZeroMQ_VERSION_MAJOR}_${ZeroMQ_VERSION_MINOR}_${ZeroMQ_VERSION_PATCH}"
HINTS
${_ZeroMQ_ROOT}/lib
)
endif()
endif()
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ZeroMQ
FOUND_VAR
ZeroMQ_FOUND
REQUIRED_VARS
ZeroMQ_INCLUDE_DIRS
ZeroMQ_LIBRARIES
VERSION_VAR
ZeroMQ_VERSION
)
I have two questions toward the above example. The first one is that in the function scope _zmqver_EXTRACT we first set the CMAKE_MATCH_1 to 0 and then we do this command set(${_ZeroMQ_VER_OUTPUT} "${CMAKE_MATCH_1}" PARENT_SCOPE). However, it seems that the value of CMAKE_MATCH_1 is always 0. In my opinion, the version information should be stored in the variable ZeroMQ_ver.
What's more, I do not know what the usage of the variable ZeroMQ_FIND_VERSION_COUNT. It seems that this variable is undefined.
I'm trying to have a definition with a string value: "v1.1.1"
However, when I tried the following command:
add_definitions(-DVERSION="v1.1.1")
//or set(CMAKE_CXX_FLAGS -DVERSION=\"v1.1.1\")
//as well as set(CMAKE_CXX_FLAGS -DVERSION="\"v1.1.1\"")
and used v1.1.1 in my source file, in a command like printf("%s\n", v1.1.1)
I got v1.1.1 in my c/c++ sources code without the quotes, which is not a valid string literal.
how do I define this correctly in a CMakeList.txt file?
I'm trying to compile some Java code with CMake (I'm aware that Java is not really the use-case for CMake) and I want to provide the class paths for the files. The compilation should work on both Unix and Windows systems. The problem I have is with separating the different class paths. Using:
set(CLASS_PATH ${PATH1} ${PATH2})
message(STATUS "${CLASS_PATH}")
prints
<PATH1>;<PATH2>
But this happens on both Unix and Windows. So I have to manually add separators. The way I'm doing it is
if(${CMAKE_HOST_WIN32})
set(SEP "\;")
elseif(${CMAKE_HOST_UNIX})
set(SEP ":")
endif(${CMAKE_HOST_WIN32})
Is this really the best way to deal with separators? I feel like I'm missing something.
Update - MCVE
To describe my thought: FILE_LIST would be contain all the java files that I want to compile. I defined a custom function which I can call on this FILE_LIST and compile the files. Maybe I'm doing something wrong with the function parameters?
cmake_minimum_required(VERSION 3.11)
set(CLASS_PATH E:/tmp/cmake/separator C:/tmp/)
set(FILE_LIST 1.txt 2.txt 3.txt)
add_custom_target(war ALL)
function(compile_java clp)
foreach(java_file ${ARGN})
add_custom_command(
TARGET war
PRE_BUILD
COMMAND echo "${clp}" ${java_file}
)
endforeach(java_file)
endfunction()
compile_java("${CLASS_PATH}" ${FILE_LIST}) # I have to pass CLASS_PATH in quotes
So, based on comments, you want the path list as a single command-line argument, with a platform-specific separator. You can achieve this using string operations:
function(compile_java clp)
if(NOT CMAKE_HOST_WIN32)
string(REPLACE ";" ":" clp "${clp}")
endif()
foreach(java_file ${ARGN})
add_custom_command(
TARGET war
PRE_BUILD
COMMAND echo "${clp}" ${java_file}
)
endforeach(java_file)
endfunction()
I always think that if you want to compare two strings (but not variables) all you need to do is to quote it like that:
if("${A}" STREQUAL "some string")
but now I find out that this code sometimes print oops:
cmake_minimum_required(VERSION 2.8)
if("d" STREQUAL "")
message("oops...")
endif()
May be it's bug (because it prints with Xcode, but not with make)?
Or there is some special variables?
cmake: 2.8.12, 2.8.11.2
xcode: 4.6.2, 5.0.1
Update
There is command string without described problems:
string(COMPARE EQUAL "${A}" "" result)
if(result)
message("...")
endif()
Update 2
The behaviour I've expected implemented since CMake 3.1.0 (see CMP0054).
Output of the 3.0.2 test:
CMake version: 3.0.2
Quoted test
Surprise!
Unquoted test
Surprise!
Output of the 3.1.0 test:
CMake version: 3.1.0
Quoted test
OK
Unquoted test
Surprise!
You ran into a rather annoying "it's not a bug, it's a feature" behavior of CMake. As explained in the documentation of the if command:
The if command was written very early in CMake's history, predating the ${}
variable evaluation syntax, and for convenience evaluates variables named
by its arguments as shown in the above signatures.
Well, the convenience turned out to be an inconvenience. In your example the the string "d" is treated as a variable named d by the if command. If the variable d happens to be defined to the empty string, the message statement will print "oops...", e.g.:
set (d "")
if("d" STREQUAL "")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
This can give surprising results for statements like
if("${A}" STREQUAL "some string")
because there can be an unintended double expansion of the first argument if the variable A happens to be defined to a string which is also the name of a CMake variable, e.g.:
set (A "d")
set (d "some string")
if("${A}" STREQUAL "some string")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
Possible work-arounds:
You can add a suffix character to the string after the ${} expansion which prevents the if statement from doing the automatic evaluation:
set (A "d")
set (d "some string")
if("${A} " STREQUAL "some string ")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
Do not use ${} expansion:
set (A "d")
set (d "some string")
if(A STREQUAL "some string")
message("oops...")
else()
# this branch will be taken
message("fine")
endif()
To prevent unintended evaluation on the right side of STREQUAL use MATCHES with a CMake regular expression instead:
if(A MATCHES "^value$")
...
endif()
Addendum: CMake 3.1 no longer does double expansions for quoted arguments. See the new policy.
As of CMake 3.1, there are new rules variable expansions in if(). They are enabled if you either:
set cmake_minimum_required(3.1) (or higher) at the top of you project file, or
use a lower minimum version number but manually set policy CMP0054 to NEW.
Even in that case, it remains true is that the first argument to if is expanded with the value of a variable matching that name, if it exists:
set (d "")
if(d STREQUAL "")
# this branch will be taken
message("oops...")
else()
message("fine")
endif()
However, this is now disabled if the first argument is quoted:
set (d "")
if("d" STREQUAL "")
message("oops...")
else()
# due to quotes around "d" in if statement,
# this branch will be taken
message("fine")
endif()
If you do want to test a variable's contents against a value, you can either use the classic unquoted syntax, or use the "${d}" syntax you suggested. Thanks to the new rules, this will never suffer the double-expansion problem mentioned in sakra's answer:
set (A "d")
set (d "some string")
if("${A}" STREQUAL "d")
# this branch will be taken
message("fine")
elseif("${A}" STREQUAL "some string")
message("oops...")
else()
message("??")
endif()
I need to add various flags to my C and C++ compile lines in my CMake files (CMake 2.8.10.2). I see some people use add_definitions but from what I can see that is intended for preprocessor flags (-D). I have some flags that I don't want passed to the preprocessor.
So I've been trying to modify CMAKE_C_FLAGS and CMAKE_CXX_FLAGS. I see that some people were using something like:
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -new -flags -here")
but then I read in the cmake docs that this is less efficient, and the right way to do it is to use list(APPEND ...), like this:
list(APPEND CMAKE_C_FLAGS -new -flags -here)
However, when I do this my compile line contains the flags separated by semicolons and is a syntax error. I read that this is now lists are stored internally, but I figured this would be taken care of by cmake when I used the variable. This seems so basic; am I doing something wrong? I mean, what the heck good are these lists if they can't be used unless you happen to want a semicolon-separated list of values (and who wants that, other than I guess Windows %PATH% settings or something)? Should I be using the quoted version even though the docs suggest it's less efficient/appropriate?
In CMake, a "list" is a string of items separated by semi-colons. For example:
set(FOO "a")
list(APPEND FOO "b") # now FOO="a;b"
list(APPEND FOO "c") # now FOO="a;b;c"
In CMake, a string of space-seperated items is just a string, not a list. Use the string(APPEND) command to append to it. For example:
set(FOO "a")
string(APPEND FOO " b") # now FOO="a b"
string(APPEND FOO " c") # now FOO="a b c"
On old versions of CMake that lack the string(APPEND) command, you should fallback to the set command. For example:
set(FOO "a")
set(FOO "${FOO} b")
set(FOO "${FOO} c")
In this case, you would indeed normally use the set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -new -flags -here") technique.
You're right in that in most other contexts CMake can "translate" a semi-colon separated list into something meaningful for the compiler (e.g. the list of source files in an executable), but in this case, CMake takes the flags as a single, complete string to pass to the compiler/linker.
You could if you really wanted keep the list of flags as a CMake list, but then before exiting the CMakeLists.txt, you could yourself "translate" the list into a single string value of CMAKE_C_FLAGS, but it's unusual to see this.