CMAKE_C_FLAGS has variables inconsistently expanded depending on whether or not it is used in compiler or linker
Steps to reproduce:
(1) Make a very simple, minimal cmake project with an executable. I took this one from the tutorial:
CMakeLists.txt
cmake_minimum_required (VERSION 3.9.20170630)
project (HELLO)
add_executable (hello hello.c)
hello.c
int main() { return 0; }
(2) Create a build directory and run the following cmake command:
cmake .. -DCMAKE_C_FLAGS="-Wl,-rpath,\$ORIGIN"
(3) Run make VERBOSE=1
Expected result: There are a few possible things that this might do:
-
We might pass
-Wl,-rpath,$ORIGIN
to the underlying commands. When I wrote this code, this is what I intended. -
We might pass some macro-expanded version of this to the underlying commands. While not what I necessarily wanted, this would also be reasonable, and the user could just add extra escaping to prevent macro expansion.
Actual result: On cmake version 3.9.20170630-gc705f:
[ 50%] Building C object CMakeFiles/hello.dir/hello.c.o
/home/ezyang/local/anaconda2/bin/cc -Wl,-rpath,RIGIN -o CMakeFiles/hello.dir/hello.c.o -c /home/ezyang/local/labs/cmake-rpath/hello.c
[100%] Linking C executable hello
/home/ezyang/local/cmake/usr/usr/local/bin/cmake -E cmake_link_script CMakeFiles/hello.dir/link.txt --verbose=1
/home/ezyang/local/anaconda2/bin/cc -Wl,-rpath,$ORIGIN CMakeFiles/hello.dir/hello.c.o -o hello
Look carefully! The macro expansion is inconsistent! When we call cc
to build the executable, some sort of macro expansion occurs, which gobbles up the $O
in the string. However, when we call cc
to LINK the executable, no macro expansion takes place! This cannot possibly be intentional.
(As an aside, I also determined that the macro expansion that happens during compiler calls is expanding according to the environment e.g., try swapping $ORIGIN
with $PATH
).
I don't have advice for how to fix this in a backwards compatible manner. Both interpretations are plausible, and the non-macro-expanding interpretation is more useful for linking, due to the special $ORIGIN
token that often needs to be passed. But even if this doesn't get fixed, at the very least there should be documentation on this hazard; I'd quite like it if cmake emitted a warning when the two things don't expand the same way.
P.S. I know cmake has alternative mechanisms for setting rpaths (e.g., CMAKE_INSTALL_RPATH
or CMAKE_EXE_LINKER_FLAGS
). But the point of this ticket still stands: dollar variables in CMAKE_C_FLAGS are interpreted inconsistently. Indeed, for this particular problem, I am planning to work around it by using CMAKE_EXE_LINKER_FLAGS
instead (CMAKE_INSTALL_RPATH
is not suitable as the rpath is only applied upon install, which is too late for my build.)