target_link_libraries: document quoting behavior of each item kind
Hello,
I found a bug where target_link_libraries
improperly quotes linker flags if the link flag contains spaces.
Curiously, target_link_options
does not exhibit the bug when given the same linker flag.
I've reproduced the bug using multiple generators (Ninja, NMake Makefiles).
For example:
target_link_libraries(target_link_libraries_link_flags_with_spaces PRIVATE
"-MANIFESTDEPENDENCY:type='Win32' name='Flag.Not.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86'"
)
Results in the following:
[3/3] Linking CXX executable target_link_libraries_link_flags_with_spaces.exe
FAILED: target_link_libraries_link_flags_with_spaces.exe
cmd.exe /C "cd . && D:\Downloads\cmake-3.13.0-rc1-win64-x64\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\target_link_libraries_link_flags_with_spaces.dir --manifests -- C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\b
in\Hostx64\x86\link.exe /nologo CMakeFiles\target_link_libraries_link_flags_with_spaces.dir\main2.cpp.obj /out:target_link_libraries_link_flags_with_spaces.exe /implib:"static lib\target_link_libraries_link_flags_with_spaces.lib" /pdb
:target_link_libraries_link_flags_with_spaces.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:console -MANIFESTDEPENDENCY:type='Win32' name='Flag.Not.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86' kernel3
2.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
LINK Pass 1: command "C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\bin\Hostx64\x86\link.exe /nologo CMakeFiles\target_link_libraries_link_flags_with_spaces.dir\main2.cpp.obj /out:target_link_libraries_link_flags_with_spa
ces.exe /implib:static lib\target_link_libraries_link_flags_with_spaces.lib /pdb:target_link_libraries_link_flags_with_spaces.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:console -MANIFESTDEPENDENCY:type='Win32' name='F
lag.Not.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86' kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\target_link_
libraries_link_flags_with_spaces.dir/intermediate.manifest CMakeFiles\target_link_libraries_link_flags_with_spaces.dir/manifest.res" failed (exit code 1104) with the following output:
LINK : fatal error LNK1104: cannot open file 'name='Flag.Not.Properly.Quoted''
ninja: build stopped: subcommand failed.
Whereas this:
target_link_options(target_link_options_link_flags_with_spaces PRIVATE
"-MANIFESTDEPENDENCY:type='Win32' name='Flag.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86'"
)
Succeeds:
Comparing the build.ninja results, it's easy to see what happened:
// build.ninja
- LINK_LIBRARIES = -MANIFESTDEPENDENCY:type='Win32' name='Flag.Not.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86' ...
+ LINK_FLAGS = ... "-MANIFESTDEPENDENCY:type='Win32' name='Flag.Properly.Quoted' version='6.0.0.0' processorArchitecture='X86'"
target_link_libraries
does not properly quote its linker flags and erroneously attempts to link in the following:
'name='Flag.Not.Properly.Quoted'
version='6.0.0.0'
processorArchitecture='X86'
And any other space delimited option...
target_link_options
does properly quote its linker flags and avoids this failure.
Once CMake 3.13 is released, I can obviously work around this by using target_link_options
, since it appears to have the correct quoting behavior.
However, both target_link_libraries | CMake 3.12
and target_link_libraries | CMake 3.13.0-rc1
suggest I should still be able to pass in a linker flag by using -
if I wanted.
Context / Primary Motivation
I'm a Windows developer and am attempting to use the /MANIFESTDEPENDENCY
linker flag to specify manifest dependencies in my application. This linker flag is set to a string containing the assemblyIdentity
, which is comprised of a series of key value pairs delimited by spaces. There appears to be a bug in the quoting rules of target_link_libraries
, which prevents me from setting this linker flag in my project.
Additional Testing
While trying to isolate the bug, I discovered a few other quoting issues with target_link_libraries
. These quoting issues primarily centered around attempting to link against a library whose name had a space in it, e.g. "moo cow.lib"
or "sheep baa.lib
".
Some overloads of target_link_libraries
properly quote the libraries with spaces in their name, others do not.
Absolute Paths / Target Name
target_link_libraries(test_spaces_absolute_path PRIVATE
"${CMAKE_BINARY_DIR}/static lib/moo cow.lib" # properly quoted: "moo cow.lib"
"${CMAKE_BINARY_DIR}/static lib/sheep baa.lib" # properly quoted: "sheep baa.lib"
)
or
target_link_libraries(test_spaces_target_name PRIVATE
moocow # properly quoted: "moo cow.lib"
sheepbaa # properly quoted: "sheep baa.lib"
)
Succeeds
Relative Paths
target_link_libraries(test_spaces_relative_path PRIVATE
"static lib/moo cow.lib" # not properly quoted: moo cow.lib
"static lib/sheep baa.lib" # not properly quoted: sheep baa.lib
)
Fails with the following:
[1/5] Linking CXX executable test_spaces_relative_path.exe
FAILED: test_spaces_relative_path.exe
cmd.exe /C "cd . && D:\Downloads\cmake-3.13.0-rc1-win64-x64\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\test_spaces_relative_path.dir --manifests -- C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\bin\Hostx64\x86\link
.exe /nologo CMakeFiles\test_spaces_relative_path.dir\main.cpp.obj /out:test_spaces_relative_path.exe /implib:"static lib\test_spaces_relative_path.lib" /pdb:test_spaces_relative_path.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL
/subsystem:console static lib/moo cow.lib.lib static lib/sheep baa.lib.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
LINK Pass 1: command "C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\bin\Hostx64\x86\link.exe /nologo CMakeFiles\test_spaces_relative_path.dir\main.cpp.obj /out:test_spaces_relative_path.exe /implib:static lib\test_spaces_
relative_path.lib /pdb:test_spaces_relative_path.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:console static lib/moo cow.lib.lib static lib/sheep baa.lib.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ol
e32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\test_spaces_relative_path.dir/intermediate.manifest CMakeFiles\test_spaces_relative_path.dir/manifest.res" failed (exit code 1104) with the foll
owing output:
LINK : fatal error LNK1104: cannot open file 'static.obj'
Plan Library Name
target_link_libraries(test_spaces_plain_library_name PRIVATE
"moo cow" # not properly quoted: moo cow.lib
"sheep baa" # not properly quoted: sheep baa.lib
)
Fails with the following:
[3/5] Linking CXX executable test_spaces_plain_library_name.exe
FAILED: test_spaces_plain_library_name.exe
cmd.exe /C "cd . && D:\Downloads\cmake-3.13.0-rc1-win64-x64\bin\cmake.exe -E vs_link_exe --intdir=CMakeFiles\test_spaces_plain_library_name.dir --manifests -- C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\bin\Hostx64\x86
\link.exe /nologo CMakeFiles\test_spaces_plain_library_name.dir\main.cpp.obj /out:test_spaces_plain_library_name.exe /implib:"static lib\test_spaces_plain_library_name.lib" /pdb:test_spaces_plain_library_name.pdb /version:0.0 /machin
e:X86 /debug /INCREMENTAL /subsystem:console moo cow.lib sheep baa.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib oleaut32.lib uuid.lib comdlg32.lib advapi32.lib && cd ."
LINK Pass 1: command "C:\PROGRA~2\MIB055~1\2017\PROFES~1\VC\Tools\MSVC\1414~1.264\bin\Hostx64\x86\link.exe /nologo CMakeFiles\test_spaces_plain_library_name.dir\main.cpp.obj /out:test_spaces_plain_library_name.exe /implib:static lib\te
st_spaces_plain_library_name.lib /pdb:test_spaces_plain_library_name.pdb /version:0.0 /machine:X86 /debug /INCREMENTAL /subsystem:console moo cow.lib sheep baa.lib kernel32.lib user32.lib gdi32.lib winspool.lib shell32.lib ole32.lib ol
eaut32.lib uuid.lib comdlg32.lib advapi32.lib /MANIFEST /MANIFESTFILE:CMakeFiles\test_spaces_plain_library_name.dir/intermediate.manifest CMakeFiles\test_spaces_plain_library_name.dir/manifest.res" failed (exit code 1104) with the foll
owing output:
LINK : fatal error LNK1104: cannot open file 'moo.obj'
Admittedly, my examples are somewhat contrived. But hopefully they help isolate the problem and will aid in your troubleshooting.
It's a bit of a stretch, but perhaps you could even imagine a scenario where you're dealing with a 3rd Party library with a space in its name...
Environment
- Visual Studio 2017
- CMake 3.13.0-rc1
- Generators: [Ninja, NMake Makefiles]
Example Code
"C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\VC\Auxiliary\Build\vcvarsall.bat" amd64_x86
cd <example source folder>
mkdir build && cd build
cmake -G Ninja ..
cmake --build .