cmake/ninja build failing

A couple of llvm sub-projects have been failing to build for me for a while (compiler-rt asan and util/unittests, at least). It turns out to be due to the fact that some paths on my system include spaces and other special characters, but the the build.ninja file was not generated with correctly quoted strings. Specifically I'm on OS X and the command is setting -isysroot to a location inside the Xcode.app, but Xcode is installed at a path which includes spaces and parentheses.

I see the problem in the build.ninja commands, where FLAGS includes the problematic setting of isysroot. The cause seems to come down to the line in the compiler-rt CMakeLists.txt:

  set(DARWIN_iossim_CFLAGS
   -mios-simulator-version-min=7.0 -isysroot ${IOSSIM_SDK_DIR})

where IOSSIM_SDK_DIR is the path including spaces and parens.

I'm not sure why these flags are finding their way into my build since I'm not doing anything with iOS or the iOS simulator, but DARWIN_iossim_CFLAGS is getting set based on "if(APPLE)", and for some reason the iOS CFLAGS are making their way into the build.ninja file. Simply deleting the cmake commands setting these iOS related variables fixes my build errors but since I don't know why these variables are used on OS X in the first place I can't say if removing them this way is the correct solution, or if maybe the CMakeLists.txt files just needs to properly quote these strings.

Here's my shortened version of that whole `if(APPLE)` block:

if(APPLE)
set(SANITIZER_COMMON_SUPPORTED_DARWIN_OS osx)

if(COMPILER_RT_USES_LIBCXX)
   set(SANITIZER_MIN_OSX_VERSION 10.7)
else()
   set(SANITIZER_MIN_OSX_VERSION 10.6)
endif()
set(DARWIN_osx_CFLAGS -mmacosx-version-min=${SANITIZER_MIN_OSX_VERSION})
set(DARWIN_osx_LINKFLAGS)
endif()

So, can anyone who's familiar with CMakeLists.txt comment on the correct way to fix CMakeLists.txt and/or the generated build.ninja?

Thanks,
Seth

It looks like the _CFLAGS values are used in the module
cmake/Modules/CompilerRTUtils.cmake:

function(set_target_compile_flags target)
   foreach(arg ${ARGN})
     set(argstring "${argstring} ${arg}")
   endforeach()
   set_property(TARGET ${target} PROPERTY COMPILE_FLAGS "${argstring}")
endfunction()

but that makes no attempt to escape or quote anything.

The COMPILE_FLAGS target property was a very early CMake feature
and is treated as a raw string to put on the command line. That
is why it needs manual escaping.

CMake 2.8.12 added the COMPILE_OPTIONS property and supporting command:

http://www.cmake.org/cmake/help/v2.8.12/cmake.html#prop_tgt:COMPILE_OPTIONS
http://www.cmake.org/cmake/help/v2.8.12/cmake.html#command:target_compile_options

The property holds a ;-list of options to be passed to the compiler.
CMake handles conversion to a command-line string with all needed
escaping.

-Brad

Well, I updated to cmake 2.8.12.2 but the result of changing that COMPILE_FLAGS to COMPILE_OPTIONS is that quotes are applied incorrectly: quotes are added surrounding the entire set of flags rather than around each individual item in the list. Obviously the build doesn't work (with the compiler looking for files named " -m64 ... ") but checking the relevant build command in build.ninja at least shows me that the relevant path is indeed getting added via set_target_compile_flags: the path is now part of one of these quoted strings.

Well, I updated to cmake 2.8.12.2 but the result of changing that
COMPILE_FLAGS to COMPILE_OPTIONS is that quotes are applied incorrectly

That's because the set_target_compile_flags function in LLVM is
creating the space-separated command-line string that the old
COMPILE_FLAGS option wants:

function(set_target_compile_flags target)
  foreach(arg ${ARGN})
    set(argstring "${argstring} ${arg}")
  endforeach()
  set_property(TARGET ${target} PROPERTY COMPILE_FLAGS "${argstring}")
endfunction()

Try changing the function to just:

function(set_target_compile_flags target)
   set_property(TARGET ${target} PROPERTY COMPILE_OPTIONS "${ARGN}")
endfunction()

Of course an upstream version of this change would be simpler
if it just dropped set_target_compile_flags and set the property
directly at the call sites. One could even use the APPEND option
of set_property to add options incrementally.

-Brad

Brad,

How does COMPILE_FLAGS and COMPILE_OPTIONS work together? I.e. are their contents joined to produce a single compiler invocation?
Also, why there is no COMPILE_OPTIONS property for source files?

Looks like we really need to switch to newer CMake and make use of target_compile_options…

How does COMPILE_FLAGS and COMPILE_OPTIONS work together? I.e. are their
contents joined to produce a single compiler invocation?

Both are used but the order is not defined. Of course the
preference is to set COMPILE_OPTIONS only and drop any use
of COMPILE_FLAGS.

Also, why there is no COMPILE_OPTIONS property for source files?

AFAIK there is no reason besides the author of the feature
not including it in the implementation. The change was made
as part of a sweeping "usage requirements" feature which
makes sense at the target level but not per-source. There
is also an INTERFACE_COMPILE_OPTIONS property which can also
be managed by the target_compile_options command and specifies
options needed to compile objects in consumers of a library
before linking it.

There is a per-source COMPILE_DEFINITIONS for macros and
still the old per-source COMPILE_FLAGS as a last resort.

-Brad

Okay, so after setting COMPILE_OPTIONS properly there was a similar problem with set_target_link_flags. There didn't seem to be a LINK_OPTIONS available so I just manually added quotes when concatenating link flags. Then it turned out that at one point one of the items in the ARGN list of link flags gets added as a single string but is really two items, so I hacked around that by inserting quotes into the string where it's added. With these changes building is successful.

diff --git cmake/Modules/CompilerRTUtils.cmake cmake/Modules/CompilerRTUtils.cmake
index fce37e3..a36096a 100644
--- cmake/Modules/CompilerRTUtils.cmake
+++ cmake/Modules/CompilerRTUtils.cmake
@@ -2,15 +2,12 @@
# define a handy helper function for it. The compile flags setting in CMake
# has serious issues that make its syntax challenging at best.
function(set_target_compile_flags target)
- foreach(arg ${ARGN})
- set(argstring "${argstring} ${arg}")
- endforeach()
- set_property(TARGET ${target} PROPERTY COMPILE_FLAGS "${argstring}")
+ set_property(TARGET ${target} PROPERTY COMPILE_OPTIONS "${ARGN}")
endfunction()

function(set_target_link_flags target)
   foreach(arg ${ARGN})
- set(argstring "${argstring} ${arg}")
+ set(argstring "${argstring} \"${arg}\"")
   endforeach()
   set_property(TARGET ${target} PROPERTY LINK_FLAGS "${argstring}")
endfunction()
diff --git lib/asan/CMakeLists.txt lib/asan/CMakeLists.txt
index 64239fe..2c8d385 100644
--- lib/asan/CMakeLists.txt
+++ lib/asan/CMakeLists.txt
@@ -75,7 +75,7 @@ if(APPLE)
     # Dynamic lookup is needed because shadow scale and offset are
     # provided by the instrumented modules.
     set(ASAN_RUNTIME_LDFLAGS
- "-undefined dynamic_lookup")
+ "-undefined\" \"dynamic_lookup")
     add_compiler_rt_darwin_dynamic_runtime(clang_rt.asan_${os}_dynamic ${os}
       ARCH ${ASAN_SUPPORTED_ARCH}
       SOURCES $<TARGET_OBJECTS:RTAsan.${os}>

Thanks,
Seth

FYI, there is upstream discussion of development for LINK_OPTIONS:

http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/9203

-Brad