I am trying to compile some CUDA and I wish to display compiler warnings. Equivalent to:
g++ fish.cpp -Wall -Wextra
Except NVCC doesn't understand these, and you have to pass them through:
nvcc fish.cu --compiler-options -Wall --compiler-options -Wextra
nvcc fish.cu --compiler-options "-Wall -Wextra"
(I favour the latter form, but ultimately, it doesn't really matter.)
Given this CMakeLists.txt (a very cut-down example):
cmake_minimum_required(VERSION 3.9)
project(test_project LANGUAGES CUDA CXX)
list(APPEND cxx_warning_flags "-Wall" "-Wextra") # ... maybe others
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options ${cxx_warning_flags}>")
add_executable(test_cuda fish.cu)
But this expands to:
nvcc "--compiler-options -Wall" -Wextra ...
which is obviously wrong. (Omitting the quotes around the generator expression just lands us in broken expansion hell.)
... skip ahead several thousand iterations of Monte Carlo programming ...
I've arrived at this gem:
set( temp ${cxx_warning_flags} )
string (REPLACE ";" " " temp "${temp}")
set( temp2 "--compiler-options \"${temp}\"" )
message( "${temp2}" )
which prints out the encouraging-looking
--compiler-options "-Wall -Wextra"
But then
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:${temp2}>")
expands to:
nvcc "--compiler-options \"-Wall -Wextra\"" ...
I'm at a loss; am I onto a dead end here? Or have I missed some crucial combination of punctuation?
I'm answering my own question, since I've found a few solutions that work, but I'm still interested to hear if there is a better (read: cleaner, more canonical) way.
TL;DR:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${flag}>")
endforeach()
Blow-by-blow account:
I tried this:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options ${flag}>")
endforeach()
but that still gives
nvcc "--compiler-options -Wall" "--compiler-options -Wextra"
nvcc fatal : Unknown option '-compiler-options -Wall'
Adding in a temporary however:
foreach(flag IN LISTS cxx_warning_flags)
set( temp --compiler-options ${flag}) # no quotes
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:${temp}>")
endforeach()
Gives a new outcome:
nvcc --compiler-options -Wall -Wextra ...
nvcc fatal : Unknown option 'Wextra'
What I assume is happening here is that CMake is combining the repeated --compiler-options flags, but I'm just speculating.
So, I tried eliminating the spaces using an equals:
foreach(flag IN LISTS cxx_warning_flags)
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${flag}>")
endforeach()
Hurrah! We have a winner:
nvcc --compiler-options=-Wall --compiler-options=-Wextra ...
Epilogue:
Can we do it without the loop?
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${cxx_warning_flags}>")
doesn't work (--compiler-options=-Wall -Wextra), but:
string (REPLACE ";" " " temp "${cxx_warning_flags}")
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:--compiler-options=${temp}>")
does work ("--compiler-options=-Wall -Wextra").
I'm slightly surprised about this last option, but I guess it makes sense. On balance, I think the looping option is clearest in its intention.
EDIT:
In Confusing flags passed to MSVC through NVCC with CMake, I spent a lot of time discovering that it might be better to use:
add_compile_options("$<$<COMPILE_LANGUAGE:CUDA>:-Xcompiler=${flag}>")
since CMake appears to do some rationalisation of flags to remove duplicates and ambiguity, but does not realise that --compiler-options is the same as its favoured -Xcompiler.
Related
I'm using a customized clang/llvm to build my project. The customization is basically the addition of optimization passes. To pass options to my passes when compiling with clang I'm using:
clang [..] -mllvm -MyOption [..]
Now it happens that I need to pass multiple options this way:
clang [..] -mllvm -MyOption -mllvm -MyOption2=value [..]
This in combination with CMake's target_compile_options() stops working, CMake removes the second -mllvm because it seems to think it is duplicated.
target_compile_options(vslib INTERFACE -mllvm -MyOption)
target_compile_options(vslib INTERFACE -mllvm -MyOption2=val)
I tried putting " around both options, doesn't work.
Is there a way to achieve this with CMake?
https://cmake.org/cmake/help/v3.12/command/target_compile_options.html:
The set of options is de-duplicated to avoid repetition. While beneficial for individual options, the de-duplication step can break up option groups. For example, -D A -D B becomes -D A B. One may specify a group of options using shell-like quoting along with a SHELL: prefix. The SHELL: prefix is dropped and the rest of the option string is parsed using the separate_arguments() UNIX_COMMAND mode. For example, "SHELL:-D A" "SHELL:-D B" becomes -D A -D B.
So in your case that would be:
target_compile_options(vslib INTERFACE "SHELL:-mllvm -MyOption" "SHELL:-mllvm -MyOption2=val")
Try:
get_property(tmp TARGET vslib PROPERTY INTERFACE_COMPILE_OPTIONS)
list(APPEND tmp -mllvm)
list(APPEND tmp -MyOption)
list(APPEND tmp -mllvm)
list(APPEND tmp -MyOption2=value)
set_property(TARGET vslib PROPERTY INTERFACE_COMPILE_OPTIONS "${tmp}")
or maybe just:
set_property(TARGET vslib APPEND PROPERTY INTERFACE_COMPILE_OPTIONS -mllvm -MyOption)
set_property(TARGET vslib APPEND PROPERTY INTERFACE_COMPILE_OPTIONS -mllvm -MyOption2=value)
I have a CMakeLists.txt which builds a number of targets. Call one foo and one bar
At the moment foo and bar both share some settings given to ccmake configuration
CMAKE_CXX_FLAGS = -W -Wall
CMAKE_CXX_FLAGS_DEBUG = -g -pg
etc
I need to add -fPIC to foo but not bar. According to this answer I want to use TARGET_COMPILE_OTIONS
target_compile_options(foo PUBLIC "$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>")
target_compile_options(foo PUBLIC "$<$<CONFIG:RELEASE>:${MY_RELEASE_OPTIONS}>")
Note that target_compile_options add [sic] options
This sounds like it's what I need but what does this syntax mean?
"$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>"
To clarify, I want to add -fPIC as an additional flag when compiling foo but not when compiling bar
Please explain the $<$< business and show me, concretely, how -fPIC would be added as a flag for foo.
Looks like $<$< falls into the generator expressions category: https://cmake.org/cmake/help/v3.0/manual/cmake-generator-expressions.7.html#manual:cmake-generator-expressions(7),
precisely into
logical expressions
So in your case,
"$<$<CONFIG:DEBUG>:${MY_DEBUG_OPTIONS}>"
expands to MY_DEBUG_OPTIONS when the DEBUG configuration is used, and otherwise expands to nothing.
So in your case you should add -fPIC for example to MY_DEBUG_OPTIONS.
To be a little bit more precise:
$<CONFIG:DEBUG>
evaluates to 1 or 0 depending weather CONFIG is DEBUG or not, respectively.
Then you will have either:
$<0:${MY_DEBUG_OPTIONS}>
or
$<1:${MY_DEBUG_OPTIONS}>
The two expressions above will evaluate in the following way:
$<0:${MY_DEBUG_OPTIONS}> will evaluate to
Empty string (ignores ${MY_DEBUG_OPTIONS})
while $<1:${MY_DEBUG_OPTIONS}> will evaluate to
Content of ${MY_DEBUG_OPTIONS}
as the documentation states.
In the last case then -fPIC will be added to one of CMAKE_CXX_FLAGS or CMAKE_CXX_FLAGS_DEBUG.
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()
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.
When using gcc, can individual optimisation flags be enabled without a -O level being specified?
gcc -ffasst-math foo.c
OR
gcc -O1 -ffast-math foo.c
Which one works?
Thanks!
Yes, you can enable individual optimization flags.
Info from the gcc man page:
-O
-O turns on the following optimization flags:
-fauto-inc-dec -fcprop-registers -fdce -fdefer-pop -fdelayed-branch -fdse -fguess-branch-probability -fif-conversion2 -fif-conversion -finline-small-functions -fipa-pure-const -fipa-reference -fmerge-constants -fsplit-wide-types -ftree-builtin-call-dce -ftree-ccp -ftree-ch -ftree-copyrename -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-sra -ftree-ter -funit-at-a-time
-O also turns on -fomit-frame-pointer on machines where doing so does not interfere with debugging.
-ffast-math
Sets -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling-nans and -fcx-limited-range.
This option causes the preprocessor macro "FAST_MATH" to be defined.
This option is not turned on by any -O option since it can result in incorrect output for programs which depend on an exact implementation of IEEE or ISO rules/specifications for math functions. It may, however, yield faster code for programs that do not require the guarantees of these specifications.