If LDFLAGS are set in environment, then cmake picks that up and adds it to the list of linker flags. What is the way to avoid that? I tried to define CMAKE_EXE_LINKER_FLAGS_INIT
, CMAKE_CXX_LINK_FLAGS
etc in the toolchain file, but it did not help.
The docs state that it happens, though setting CMAKE_EXE_LINKER_FLAGS_INIT
should do it. Could you please provide a small example showing the issue?
$ cat CMakeLists.txt
project(helloworld)
add_executable(helloworld helloworld.cpp)
set(CMAKE_EXE_LINKER_FLAGS_INIT )
$ env | grep LDFLAGS
LDFLAGS=-Wl,--as-needed
If I build this I can see cmake passing LDFLAGS to the linker
[ 50%] Building CXX object CMakeFiles/helloworld.dir/helloworld.cpp.o
/usr/bin/c++ -o CMakeFiles/helloworld.dir/helloworld.cpp.o -c /usr/local/src/cmake_example/helloworld.cpp
[100%] Linking CXX executable helloworld
/usr/bin/cmake -E cmake_link_script CMakeFiles/helloworld.dir/link.txt --verbose=1
/usr/bin/c++ -Wl,--as-needed -rdynamic CMakeFiles/helloworld.dir/helloworld.cpp.o -o helloworld
make[2]: Leaving directory '/usr/local/src/cmake_example/build'
[100%] Built target helloworld
make[1]: Leaving directory '/usr/local/src/cmake_example/build'
/usr/bin/cmake -E cmake_progress_start /usr/local/src/cmake_example/build/CMakeFiles 0
I can see that the environment variable LDFLAGS
is added to CMAKE_EXE_LINKER_FLAGS
irrespective of CMAKE_EXE_LINKER_FLAGS_INIT
. cmake also picks up CFLAGS
from the environment.
CMake initializes the flags in the project()
call (which enables the C
and CXX
language toolchains), so your setting is too late in your example.
I thought that if you call set
without a value then it clears whatever variable you’ve provided as a first argument. Try:
set(CMAKE_EXE_LINKER_FLAGS_INIT "")
Does not help to put CMAKE_EXE_LINKER_FLAGS_INIT
before project
.
Does not help to do
set(CMAKE_EXE_LINKER_FLAGS_INIT "")
Also tried to put CMAKE_EXE_LINKER_FLAGS_INIT
in a toolchain file but cmake still picks up environment variable.
I can confirm that the behavior differs from the documentation, so either the docs or implementation is buggy.
The content of CMAKE_EXE_LINKER_FLAGS_INIT
and LDFLAGS
seems to be concatened and used for initialization of CMAKE_EXE_LINKER_FLAGS
. Only the latter one is stored in the cache file, the _INIT
is not.
The easiest solution for you is to delete the environment variables. So you don’t need to know exactly how it is used by CMake.
set(ENV{LDFLAGS})
Wait, that’s a cache variable so you need the word CACHE in your set call. Or you can add them in your generation call with -D I believe…
For this one both works. The last one defined seems to win.
Please try and play with this self-contained example:
cmake_minimum_required(VERSION 3.7)
set(ENV{LDFLAGS} "--illegal-flag-via-env")
set(CMAKE_EXE_LINKER_FLAGS_INIT "--illegal-flag-via-cache" CACHE STRING "")
set(CMAKE_EXE_LINKER_FLAGS_INIT "--illegal-flag-via-var")
project(helloworld LANGUAGES CXX)
add_executable(helloworld helloworld.cpp)
file(GENERATE OUTPUT helloworld.cpp CONTENT "")
Calling the following command
cmake . ; cat CMakeCache.txt | grep illegal
will fail at the compiler check and you can see --illegal-flag-via-var --illegal-flag-via-env
used on the command line by CMake.
This is also the value used in the cache file for CMAKE_EXE_LINKER_FLAGS
I think the *_INIT
variables are never written to the cache file by CMake itself, because they are used only once on the first configure for initializing the cache variable without the _INIT suffix. That makes them irrelevant for future configure calls.
I removed the environment variables CFLAGS
and LDFLAGS
to avoid them being picked up by cmake.
This cmake behavior is quite problematic and undesirable. In my case a build machine had these environment variables defined giving a different build result. This kind of behavior is not good for reproducible builds and can be hard to track down. A toolchain file should be the input to the compiler and linker flags.
Please file an issue with your example. However, pulling {C,CXX,CPP,LD}FLAGS
from the environment has a long history. Changing this will almost certainly need a policy (and docs/tests to demonstrate the old and new behaviors).
Rather than changing the behavior and requiring a policy, another choice is to add support for a new variable which can be set to true in a toolchain file to say “Don’t pick up flags like CFLAGS, LDFLAGS, etc. from the environment, ignore them”.
A variable telling cmake to not pick up compiler and linker flags from environment sounds good. Although I thought that was the intent with the variable CMAKE_EXE_LINKER_FLAGS_INIT
? Maybe fixing or describing how those variables work is sufficient?
Fixing the docs is certainly required, but I don’t think that gets you the behavior you’re looking for. That is what will require a policy (or just a brand-new mechanism since policy manipulations in toolchain files are…probably also a little odd).
Created issue