Using CMake's include_directories command with white spaces - cmake

I am using CMake to build my project and I have the following line:
include_directories(${LLVM_INCLUDE_DIRS})
which, after evaluating LLVM_INCLUDE_DIRS, evaluates to:
include_directories(C:\Program Files\LLVM\include)
The problem is that this is being considered two include directories, "C:\Program" and "Files\LLVM\include".
Any idea how can I solve this problem? I tried using quotation marks, but it didn't work.
EDIT: It turned out that the problem is in the file llvm-3.0\share\llvm\cmake\LLVMConfig.cmake. I enclosed the following paths with quotation marks and the problem was solved:
set(LLVM_INSTALL_PREFIX C:/Program Files/LLVM)
set(LLVM_INCLUDE_DIRS ${LLVM_INSTALL_PREFIX}/include)
set(LLVM_LIBRARY_DIRS ${LLVM_INSTALL_PREFIX}/lib)

In CMake,
whitespace is a list separator (like ;),
evaluating variable names basically replaces the variable name with its content and
\ is an escape character (to get the symbol, it needs to be escaped as well)
So, in your example, include_directories(C:\\Pogram Files\\LLVM\\include) is the same as
include_directories( C:\\Program;Files\\LLVM\\include)
that is, a list with two items. To avoid this, either
escape the whitespace as well:
include_directories( C:\\Program\ Files\\LLVM\\include) or
surround the path with quotation marks:
include_directories( "C:\\Program Files\\LLVM\\include")
Obviously, the second option is the better choice as it is
simpler and easier to read and
can be used with variable evaluation like in your example (since the result of the evaluation is then surrounded by quotation marks and thus, treated a single item)
include_directories("${LLVM_INCLUDE_DIRS}")
This works as well, if LLVM_INCLUDE_DIRS is a list of multiple directories because the items in this list will then be explicitly separated by ; so that there is no need for unquoted whitespace as implicit list item separator.
Side note:
When using hard-coded path-names (for whatever reason) in my CMake files, I usually uses forward slashes as directory separators as this works on Windows as well and avoids the need to escape all backslashes.

This is more likely to be an error at the point where LLVM_INCLUDE_DIRS is set rather than a problem with include_directories.
To check this, try calling include_directories("C:\\Program Files\\LLVM\\include") - it should work correctly.
The problem seems to be that LLVM_INCLUDE_DIRS was constructed without using quotation marks. Try for example running this:
set(LLVM_INCLUDE_DIRS C:\\Program Files\\LLVM\\include)
message("${LLVM_INCLUDE_DIRS}")
set(LLVM_INCLUDE_DIRS "C:\\Program Files\\LLVM\\include")
message("${LLVM_INCLUDE_DIRS}")
The output is:
C:\Program;Files\LLVM\include
C:\Program Files\LLVM\include
Note the semi-colon in the first output line. This is a list with 2 items.
So the way to fix this is to modify the way in which LLVM_INCLUDE_DIRS is created.

Related

How to pass feature file path with included spaces on command line via karate.options

On Windows systems, paths with included spaces are allowed. For our framework built on top of Karate, I would like to robustly handle such eventualities. But if there are spaces in the feature file path given to karate.options, Karate interprets the value as multiple paths, as this is by design.
So I've already tried enclosing the path with single and double quotes, as well as all possible pairs of parentheses. Unfortunately, none of these seem to work. Is there no syntax to express this intention?

Cmake match beginning of string

I am getting some compile definitions from an external library. Unfortunately, they provide a list that sometimes starts with a leading semi-colon. For example:
;-Dfoo;Dbar
I think this is crashing the build command later in the process. I thought that I could simply remove potential leading semi-colons with this regex:
string(REGEX REPLACE "^;" "" stripped_defs ${defs})
but the problem is that Cmake seems to be ignoring the carrot ^ which signifies the start of the string, with the consequence being that all semi-colons are deleted. That is, I am getting the output
-Dfoo-Dbar
when I want
-Dfoo;-Dbar
As Sergei points out, the problem is that my defs variable was being interpreted as a list, not a string. So the regex was acting on each element of the list individually. All I need to do to force the string interpretation is to add quotes. Specifically, instead of
string(REGEX REPLACE "^;" "" stripped_defs ${defs})
I should have had
string(REGEX REPLACE "^;" "" stripped_defs "${defs}")
Rather than using a regular expression in this case, using list operations to delete empty elements would be my preferred approach in this case:
set(stripped_defs ${defs})
list(REMOVE_ITEM stripped_defs "")
This may involve one more command, but it's easier to understand what the snippet does.

PATHS: trailing backslash or not trailing backslash?

I've many VBA scripts and functions where I read a manually inserted (in Excel cell) local disk paths and I'm still confused about whether to normalize the inserted paths by adding or trimming the trailing backslash.
What do you use as the general standard? with or without the trailing backslash?
My confusion is fueled by the fact that for example ActiveWorkbook.path returns a path without trailing backslash while the CopyFile (FileSystemObject) method for the "Destination" parameter wants the trailing backslash otherwise it considers it as a file instead than a directory (and can give unexpected Permission denied errors)
The general idea is to always end a directory's name with a backslash. This is advised in the URL you mention, but there are quite some other situations as well (check my answer on a regularly occuring xcopy problem).
As mentioned: when you don't put a backslash, the question might arise "Is it a file or a directory?". Putting the backslash solves that question.
In top of that, while programming, regularly you might have following situation:
complete_filename = path + filename
Obviously, if you have forgotten to put the backslash at the end, this might cause problems (e.g. you don't want to create a file, called "C:\Tempoutput.txt" instead of "C:\Temp\output.txt", I presume? :-) )

Add space separated string to cmake `include_directories`

I have a space separated string that represents include directories I'd like to add, let's call it ${MYSTRING}, and let's say it contains the stringmy/dir1 my/dir2 my/dir3.
Using:
include_directories(${MYSTRING})
Results in an incorrect makefile, as the CXX_FLAGS that is added is:
-Imy/dir1 my/dir2 my/dir3
Rather than:
-Imy/dir1 -Imy/dir2 -Imy/dir3
Is there anyway I can work around this? the string is generated via an external command, and I'd rather not have to depend on external tools such as sed.
Use separate_arguments which takes a space-separated string of values and turns it into a list:
set(MY_LIST ${MYSTRING})
separate_arguments(MY_LIST)
include_directories(${MY_LIST})

How do you pass SOME_LIB="-lmylib -lmylib2" in a BUILD_COMMAND for ExternalProject_Add()?

I'm trying to pass a quoted string through BUILD_COMMAND in ExternalProject_Add() and every way I try it's getting mangled. The code is this:
set (mylibs "-lmylib -lmylib2")
ExternalProject_Add(Foo
URL http://foo
BUILD_COMMAND make SOME_LIB=${mylibs}
BUILD_IN_SOURCE 1
...)
I've tried using backslash quotes, double quotes, inlining the whole thing, but every time, either the whole SOME_LIB=... part gets quoted or my injected quotes get escaped. Is it not possible to get quotes through to the command line so they just cover the parameters?
Even though I'm unable to get the resulting make call to look like make SOMELIB="-lmylib -lmylib2", you can make it call make "SOMELIB=-lmylib -lmylib2" which seems to do the same thing.
Have you tried quoting like this?
ExternalProject_Add(
...
BUILD_COMMAND make "SOME_LIB=\"${mylibs}\""
...
)
The outer pair of double quotes says "this is all one argument here", and the inner pair of escaped double quotes says "these are embedded IN the argument".
It may need extra escaping, though. I haven't tried this and I'm not certain it will work. But there should be a way to add escape characters until it does work... Or, worst case, you could write out a script file (bash .sh or batch .bat) that has proper shell syntax for calling make like you want it and then invoke executing the script file as the BUILD_COMMAND.