[CMake] Generated LLVMConfig.cmake and LLVMExports.cmake broken under Visual Studio 2015

Hi,

Myself and a colleague of mine are trying to use LLVM's exported
targets [1] on trunk and I've noticed that the generated CMake files
(LLVMConfig.cmake and LLVMExport.cmake) are broken when trying to use
Visual Studio 2015 (using CMake 3.2.1).

## Broken target properties in LLVMExports.cmake

LLVM itself builds fine but when our project tries to do
``find_package(LLVM)`` we get the following error message (see [2] for
context).

-- Looking for LLVM
CMake Warning (dev) at
C:/Users/me/Documents/halide/llvm-build/share/llvm/cmake/LLVMExports.cmake:232
(set_target_properties):
  Syntax error in cmake code at

    C:/Users/me/Documents/halide/llvm-build/share/llvm/cmake/LLVMExports.cmake:233

  when parsing string

    LLVMObject;LLVMSupport;C:\Program Files (x86)\Microsoft Visual
Studio 14.0\DIA SDK\lib\diaguids.lib

  Invalid escape sequence \P

  Policy CMP0010 is not set: Bad variable reference syntax is an error.  Run
  "cmake --help-policy CMP0010" for policy details.  Use the cmake_policy
  command to set the policy and suppress this warning.
Call Stack (most recent call first):
  c:/Users/me/Documents/halide/llvm-build/share/llvm/cmake/LLVMConfig.cmake:174
(include)
  CMakeLists.txt:14 (find_package)
This warning is for project developers.  Use -Wno-dev to suppress it.

The issue is the that that generated LLVMExports.cmake file has this in it

# Create imported target LLVMDebugInfoPDB
add_library(LLVMDebugInfoPDB STATIC IMPORTED)

set_target_properties(LLVMDebugInfoPDB PROPERTIES
  INTERFACE_LINK_LIBRARIES "LLVMObject;LLVMSupport;C:\Program Files
(x86)\Microsoft Visual Studio 14.0\DIA SDK\lib\diaguids.lib"
)

The problem is that the path to diaguids.lib is a windows path and not
a CMake style path so the backslashes get interpreted as escape
sequences.

I think this is a bug in CMake.

@Brad: Do you agree?

## Broken paths in LLVMConfig.cmake

This is a minor issue but I'm not sure if this a bug or an artifact of
using Visual Studio but some of the paths specified in
LLVMConfig.cmake are not real paths because they contain
``$(Configuration)``.

set(LLVM_BUILD_LIBRARY_DIR
"C:/Users/alexander.APRELEV/Documents/halide/llvm-build/$(Configuration)/lib")
...
set(LLVM_TOOLS_BINARY_DIR
"C:/Users/alexander.APRELEV/Documents/halide/llvm-build/$(Configuration)/bin")

The problem is that I was trying to check if

${LLVM_TOOLS_BINARY_DIR}/clang${CMAKE_EXECUTABLE_SUFFIX}

exists at configure time (which works on OSX and Linux) but this fails
when using Visual Studio because ``$(Configuration)`` is in the path.

Is this intentional?

[1] http://llvm.org/docs/CMake.html#embedding-llvm-in-your-project
[2] CMake build system fixes by delcypher · Pull Request #825 · halide/Halide · GitHub

Thanks,
Dan.

I think this is a bug in CMake.

@Brad: Do you agree?

Hmm actually this might be a bug in the
``/lib/DebugInfo/PDB/CMakeLists.txt`` file. CC'ing Zach Turner seeing
as he appears to be the author.

I have an untested patch to the CMakeLists.txt that **might** fix the
broken LLVMExports.cmake file I'm seeing I'm seeing but unfortunately
I can't test it right now as I don't have access to a Visual Studio
box right now.

Anyone feel like testing it?

libpdb_additional_libraries_cmake_path.patch (552 Bytes)

That should resolve the issue for LLVM with no changes to CMake.

However, CMake should also be taught to escape the backslashes correctly
when generating the export files. Take a look at

Source/cmExportFileGenerator.cxx
Source/cmExportBuildFileGenerator.cxx
Source/cmExportInstallFileGenerator.cxx

in the CMake source tree. There are several places that just generate
double quotes around a raw value that should instead use EscapeForCMake.

Thanks,
-Brad

FYI, llvm/clang r240139 with Dan's patch seems to build fine on Windows with VS2015.

Thanks for testing. I've committed my patch in r240181.

Thanks for the explanation. Would you like me to file a bug on the
CMake bug tracker?
Alternatively I could try writing a patch but I don't really know what
I'm doing.

Did you have any thoughts on the other issue I saw which was paths
containing "$(Configuration)". E.g.

set(LLVM_TOOLS_BINARY_DIR
"C:/Users/alexander.APRELEV/Documents/halide/llvm-build/$(Configuration)/bin")

I have a feeling that this something to do with using Visual Studio as
a generator. When using ninja/CMake there is only a single build
configuration but when using the Visual Studio CMake generator it
seems there are multiple configuration present at the same time. I
noticed this because I tried to hack around the issue by reading the
LOCATION property of one of the llvm executable targets. This didn't
work very well and I discovered that LLVMExports.cmake has multiple
locations for the same target.

Thanks,
Dan.

However, CMake should also be taught to escape the backslashes correctly
when generating the export files. Take a look at

Thanks for the explanation. Would you like me to file a bug on the
CMake bug tracker?
Alternatively I could try writing a patch but I don't really know what
I'm doing.

Please bring the issue over to the cmake developers' list because such
discussion will be more relevant there.

Did you have any thoughts on the other issue I saw which was paths
containing "$(Configuration)". E.g.

set(LLVM_TOOLS_BINARY_DIR
"C:/Users/alexander.APRELEV/Documents/halide/llvm-build/$(Configuration)/bin")

This is indeed for multi-configuration generators like Visual Studio.
Paths like this are meant only for reference in the build system
files. The $(Configuration) placeholder will be replaced by the
native build system tools (like msbuild) at build time. Generally
these paths should not be exported from a project install tree but
may be from its build tree.

Any code path that needs to get one of these directories for use
somewhere other than build system files must choose a specific
configuration to get the corresponding path. The LOCATION_<CONFIG>
target property or the $<TARGET_FILE:...> generator expression
can be used to reference them. The latter can be used with
commands like file(GENERATE) to write into external files.

-Brad

Hi,

Please bring the issue over to the cmake developers' list because such
discussion will be more relevant there.

Done

http://public.kitware.com/pipermail/cmake-developers/2015-June/025502.html