Does the "#" symbol have a special meaning when surrounding a CMake variable? - cmake

While looking through the ITK source code I've come across a number of files like this, which have the suffix .cmake.in and which define a number of variables (strings?), where the value is identical to the variable name, but with # symbols prepended/appended. For example:
set(ExternalData_OBJECT_STORES "#ExternalData_OBJECT_STORES#")
What is the purpose of these declarations? Does the # symbol have a special meaning in this context? I tried searching for this in the CMake Language Syntax Wiki, but there were no occurrences of # on the page.

Files with suffix .in are usually intended for configuration via command configure_file. All sequences #NAME# within such files are translated to value of variable NAME.
Outside of configure_file / string(CONFIGURE) symbol # has no special meaning in CMake.

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?

Strip filename (shortest) extension by CMake (get filename removing the last extension)

get_filename_component can be used to remove/extract the longest extension.
EXT = File name longest extension (.b.c from d/a.b.c)
NAME_WE = File name without directory or longest extension
I have a file with a dot in its name, so I need the shortest extension:
set(MYFILE "a.b.c.d")
get_filename_component(MYFILE_WITHOUT_EXT ${MYFILE} NAME_WE)
message(STATUS "${MYFILE_WITHOUT_EXT}")
reports
-- a
but I want
-- a.b.c
What is the preferred way to find the file name without the shortest extension?
I would do:
string(REGEX REPLACE "\\.[^.]*$" "" MYFILE_WITHOUT_EXT ${MYFILE})
The regular expression matches a dot (\\., see next paragraph), followed by any number of characters that is not a dot [^.]* until the end of the string ($), and then replaces it with an empty string "".
The metacharacter dot (normally in a regular expression it means "match any character") needs to be escaped with a \ to be interpreted as a literal dot. However, in CMake string literals (like C string literals), \ is a special character and need to be escaped as well (see also here). Therefore you obtain the weird sequence \\..
Note that (almost all) metacharacters do not need to be escaped within a Character Class: therefore we have [^.] and not [^\\.].
Finally, note that this expression is safe also if there's no dot in the filename analyzed (the output corresponds to the input string in that case).
Link to string command documentation.
As of CMake 3.14 it is possible to do this with get_filename_component directly.
NAME_WLE: File name without directory or last extension
set(INPUT_FILE a.b.c.d)
get_filename_component(OUTPUT_FILE_WE ${INPUT_FILE} NAME_WE)
get_filename_component(OUTPUT_FILE_WLE ${INPUT_FILE} NAME_WLE)
OUTPUT_FILE_WE would be set to a, and OUTPUT_FILE_WLE would be set to a.b.c.
I'd solve this with a simple regex:
string(REGEX MATCH "^(.*)\\.[^.]*$" dummy ${MYFILE})
set(MYFILE_WITHOUT_EXT ${CMAKE_MATCH_1})
In CMake 3.20 and greater, the cmake_path command now provides an elegant solution:
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
where STEM refers to the portion of the filename before the extension. The cmake_path command supersedes the get_filename_component command.
So, in your example a.b.c.d, the following code grabs the stem of the filename:
cmake_path(GET MYFILE STEM MYFILE_WITHOUT_EXT)
message(STATUS ${MYFILE_WITHOUT_EXT})
which yields:
a
But this code with LAST_ONLY grabs the stem, but considers only the last extension as the file extension:
cmake_path(GET MYFILE STEM LAST_ONLY MYFILE_WITHOUT_EXT)
message(STATUS ${MYFILE_WITHOUT_EXT})
which yields:
a.b.c

Is there any limitation in giving file name in Unix?

We are using crontab to schedule jobs and it was not picking the files for processing that have [ or ] or ¿ . Is there any limitation in giving file name or these characters means something in UNIX? Is there any other variables like these we shouldnt use in file name?? Thanks in advance.
Following are general rules for both Linux, and Unix (including *BSD) like systems:
All file names are case sensitive. So filename vivek.txt Vivek.txt VIVEK.txt all are three different files.
You can use upper and lowercase letters, numbers, "." (dot), and "_" (underscore) symbols.
You can use other special characters such as blank space, but they are hard to use and it is better to avoid them.
In short, filenames may contain any character except / (root directory), which is reserved as the separator between files and directories in a pathname. You cannot use the null character.
No need to use . (dot) in a filename. Some time dot improves readability of filenames.
And you can use dot based filename extension to identify file. For example:
.sh = Shell file
.tar.gz = Compressed archive
Most modern Linux and UNIX limit filename to 255 characters (255 bytes). However, some older version of UNIX system limits filenames to 14 characters only.
A filename must be unique inside its directory. For example, inside /home/vivek directory you cannot create a demo.txt file and demo.txt directory name. However, other directory may have files with the same names. For example, you can create demo.txt directory in /tmp.
Linux / UNIX: Reserved Characters And Words
Avoid using the following characters from appearing in file names:
/
>
<
|
:
&
Please note that Linux and UNIX allows white spaces, <, >, |, \, :, (, ), &, ;, as well as wildcards such as ? and *, to be quoted or escaped using \ symbol.
It will be good if you can avoid white spaces in your filename. It will make your scripting a lot more easier.
I got the answer from this link. I am just pasting it here so that this info will be available even if that website goes down.
The only characters that are actually illegal in *nix filenames are / (reserved as the directory separator) and NUL (because it's the C string terminator). Everything else is fair game, although various utilities may fail on certain characters - typically characters that have special meaning to the shell. These will need quoting or escaping to be handled correctly.

How do I exclude a single file from a cmake `file(GLOB ... )` pattern?

My CMakeLists.txt contains this line:
file(GLOB lib_srcs Half/half.cpp Iex/*.cpp IlmThread/*.cpp Imath/*.cpp IlmImf/*.cpp)
and the IlmImf folder contains b44ExpLogTable.cpp, which I need to exclude from the build.
How to achieve that?
You can use the list function to manipulate the list, for example:
list(REMOVE_ITEM <list> <value> [<value> ...])
In your case, maybe something like this will work:
list(REMOVE_ITEM lib_srcs "IlmImf/b44ExpLogTable.cpp")
FILTER is another option which could be more convenient in some cases:
list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
This line excludes every item ending with the required filename:
list(FILTER lib_srcs EXCLUDE REGEX ".*b44ExpLogTable\\.cpp$")
Here is Regex Specification for cmake:
The following characters have special meaning in regular expressions:
^ Matches at the beginning of input
$ Matches at the end of input
. Matches any single character
[ ] Matches any character(s) inside the brackets
[^ ] Matches any character(s) not inside the brackets
- Inside brackets, specifies an inclusive range between
characters on either side e.g. [a-f] is [abcdef]
To match a literal - using brackets, make it the first
or the last character e.g. [+*/-] matches basic
mathematical operators.
* Matches preceding pattern zero or more times
+ Matches preceding pattern one or more times
? Matches preceding pattern zero or once only
| Matches a pattern on either side of the |
() Saves a matched subexpression, which can be referenced
in the REGEX REPLACE operation. Additionally it is saved
by all regular expression-related commands, including
e.g. if( MATCHES ), in the variables CMAKE_MATCH_(0..9).
try this : CMakeLists.txt
install(DIRECTORY ${CMAKE_SOURCE_DIR}/
DESTINATION ${CMAKE_INSTALL_PREFIX}
COMPONENT copy-files
PATTERN ".git*" EXCLUDE
PATTERN "*.in" EXCLUDE
PATTERN "*/build" EXCLUDE)
add_custom_target(copy-files
COMMAND ${CMAKE_COMMAND} -D COMPONENT=copy-files
-P cmake_install.cmake)
$cmake <src_path> -DCMAKE_INSTALL_PREFIX=<install_path>
$cmake --build . --target copy-files
I have an alternative solution worth noticing: mark source as header file.
This way it will not be part of the build process, but will be visible in IDE (verified on Visual Studio and Xcode):
set_source_files_properties(b44ExpLogTable.cpp,
PROPERTIES HEADER_FILE_ONLY TRUE)
I use this when some source file is platform specific. It is great since if some symbol has to be modified in many places and working on one platform then other platform specific source will can be visible and can be updated too.
For that I've created a helper function which works great in my current project.
I didn't use this method with file GLOB yet.

Using CMake's include_directories command with white spaces

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.