variants declaration in CMakelist #cmake #Cmakelist - cmake

file(GLOB FILE_LIST "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp")
Can anyone explain, in which case is GLOB used as the argument of file() in CMakelist.txt?

Related

Dealing with the separator in CMake

I'm trying to compile some Java code with CMake (I'm aware that Java is not really the use-case for CMake) and I want to provide the class paths for the files. The compilation should work on both Unix and Windows systems. The problem I have is with separating the different class paths. Using:
set(CLASS_PATH ${PATH1} ${PATH2})
message(STATUS "${CLASS_PATH}")
prints
<PATH1>;<PATH2>
But this happens on both Unix and Windows. So I have to manually add separators. The way I'm doing it is
if(${CMAKE_HOST_WIN32})
set(SEP "\;")
elseif(${CMAKE_HOST_UNIX})
set(SEP ":")
endif(${CMAKE_HOST_WIN32})
Is this really the best way to deal with separators? I feel like I'm missing something.
Update - MCVE
To describe my thought: FILE_LIST would be contain all the java files that I want to compile. I defined a custom function which I can call on this FILE_LIST and compile the files. Maybe I'm doing something wrong with the function parameters?
cmake_minimum_required(VERSION 3.11)
set(CLASS_PATH E:/tmp/cmake/separator C:/tmp/)
set(FILE_LIST 1.txt 2.txt 3.txt)
add_custom_target(war ALL)
function(compile_java clp)
foreach(java_file ${ARGN})
add_custom_command(
TARGET war
PRE_BUILD
COMMAND echo "${clp}" ${java_file}
)
endforeach(java_file)
endfunction()
compile_java("${CLASS_PATH}" ${FILE_LIST}) # I have to pass CLASS_PATH in quotes
So, based on comments, you want the path list as a single command-line argument, with a platform-specific separator. You can achieve this using string operations:
function(compile_java clp)
if(NOT CMAKE_HOST_WIN32)
string(REPLACE ";" ":" clp "${clp}")
endif()
foreach(java_file ${ARGN})
add_custom_command(
TARGET war
PRE_BUILD
COMMAND echo "${clp}" ${java_file}
)
endforeach(java_file)
endfunction()

CMake - Check if a directory contains a file of a specific type

I want to do a Macro that gets a list of the sub-sub-directories that contain a specific type of files, in my case .jar files.
This macro is getting me all the sub-sub-directories:
MACRO(SUBSUBDIRLIST result curdir)
FILE(GLOB children RELATIVE ${curdir} ${curdir}/*/*)
SET(dirlist "")
FOREACH(child ${children})
IF(IS_DIRECTORY ${curdir}/${child})
LIST(APPEND dirlist ${child})
ENDIF()
ENDFOREACH()
SET(${result} ${dirlist})
ENDMACRO()
SUBSUBDIRLIST(TUTORIALS ${CMAKE_CURRENT_SOURCE_DIR})
What I now need is to find a way to check if a directory contains any .jar file.
Can I change the IF to do something like IF(child ${children} AND ${child} CONTAINS *.jar)?
While if command supports many ready-made checks, not all checks can be expressed directly via if. But you are free to use other commands, and check their result via if.
For check whether given directory contains specific type of files, FILE(GLOB) can be effectively used:
FILE(GLOB jars "${child}/*.jar")
if(jars)
# There are .jar files in directory referred by 'child'
endif()

Order of hint paths in cmake find_library

I'm using HINTS with find_library and was surprised to find that the last path had priority. Is this intentional or something that can be configured.
set(MY_HINT_PATHS_A "/path/to/a;/path/to/b")
find_library(MY_LIBRARY_A
NAMES MyLib
HINTS ${MY_HINT_PATHS_A}/lib
ONLY_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH
)
set(MY_HINT_PATHS_B "/path/to/b;/path/to/a")
find_library(MY_LIBRARY_B
NAMES MyLib
HINTS ${MY_HINT_PATHS_B}/lib
ONLY_CMAKE_FIND_ROOT_PATH NO_DEFAULT_PATH
)
message("MY_LIBRARY_A: ${MY_LIBRARY_A}")
message("MY_LIBRARY_B: ${MY_LIBRARY_B}")
prints
MY_LIBRARY_A: /path/to/b/lib/libMyLib.a
MY_LIBRARY_B: /path/to/a/lib/libMyLib.a
I would have expected
MY_LIBRARY_A: /path/to/a/lib/libMyLib.a
MY_LIBRARY_B: /path/to/b/lib/libMyLib.a
CMake list is not a type, but an interpretation of string value. So any operations on list-variables are actually operations on strings.
${MY_HINT_PATHS_A}/lib doesn't append /lib to all elements in the list, it appends /lib only to the last element:
"/path/to/b;/path/to/a/lib"
It is absolutely equivalent to appending /lib to the variable's string-value.
For get desired effect you may use lib with PATH_SUFFIXES option to the find_library command. Or directly append /lib suffix to every element in the list.

CMake exclude files from a given pattern after file(GLOB_RECURSE)

I have an little library which has an file structure like this:
CMakeLists.txt
LibFoo/
Foo.h
FooWin.cpp
FooWin.inl
FooPosix.cpp
FooPosix.inl
And when i have to build the library in a specific OS (for example Windows) they should contain in the list before using file(GLOB_RECURSE) using a macro:
macro( add_recursive dir retVal)
file( GLOB_RECURSE ${retVal} ${dir}/*.h ${dir}/*.cpp ${dir}/*.c ${dir}/*.inl )
endmacro()
and my excluding pattern is like this (when Windows is the build host): *Posix.* but doesn't work, i tried with this approach:
macro( add_recursive dir retVal pattern)
file( GLOB_RECURSE ${retVal} ${dir}/*.h ${dir}/*.cpp ${dir}/*.c ${dir}/*.inl EXCLUDE PATTERN "${pattern}")
endmacro()
but the POSIX files still here anyways, CMake doesn't report an error or anything suggested about that.
You can use list filtering to remove items after the GLOB_RECURSE:
list(FILTER ${retVal} EXCLUDE REGEX "Posix.")
There is no EXCLUDE option for file(GLOB_RECURSE ...) command flow. You probably take this option from file(COPY|INSTALL ...), which is a different command flow.
You may iterate over list, obtained from file(GLOB_RECURSE) and exclude needed files manually:
macro( add_recursive dir retVal)
# Store unfiltered list of files into temporary list
file( GLOB_RECURSE _tmp_list ${dir}/*.h ${dir}/*.cpp ${dir}/*.c ${dir}/*.inl )
# Resulted list is initially empty. Copy all needed elements into it.
set(${retval})
foreach(f ${_tmp_list})
if(NOT f MATCHES "Posix.")
list(APPEND ${retVal} ${f})
endif()
endforeach()
endmacro()
This piece of code almost worked for me.
cmake nags about the set not having enough arguments and discontinues the macro.
This snippet also makes the extention and exclude filter variable
macro( add_recursive retVal dir ext excl)
# Store unfiltered list of files into temporary list
file( GLOB_RECURSE _tmp_list ${dir}/${ext})
# Resulted list is initially empty. Copy all needed elements into it.
set(${retval} "")
foreach(f ${_tmp_list})
if(NOT f MATCHES ${excl})
list(APPEND ${retVal} ${f})
endif()
endforeach()
endmacro( add_recursive )
#example of usage
add_recursive(inc "./" "*.h" "/exclude_folder/")

Query headers added to cmake project

I would like to get all headers added to cmake project. The use case is that I'd get this list of headers and call some custom validation on them. I would really love this to be a query mechanism to mitigate errors in oversight.
I am not interested in globbing the file system as headers may exist that are not appropriate for every platform. It's also bad.
This is what I would like the usage to look like.
add_library(example_lib
foo.h
foo.cpp
bar.h
bar.cpp
)
add_executable(example main_example.cpp)
target_link_libraries(example example_lib)
# this is the feature I am interested in
get_target_headers(example_header example)
# alternatively
get_target_headers(example_header example example_lib)
do_custom_thing("${example_header}")
A more manual way of doing this would be something like the below. I'd just reuse the example_header variable to do the custom validation.
set(example_header
foo.h
bar.h
)
set(example_source
foo.cpp
bar.cpp
)
add_library(example_lib
${example_header}
${example_source}
)
add_executable(example main_example.cpp)
target_link_libraries(example example_lib)
do_custom_thing("${example_header}")
This is what I'm doing now and it works, I am just wondering if there is a better way.
If all your headers have a ".h" suffix, you could use something like:
function(get_target_headers Headers MainTarget)
# Gather list of MainTarget's dependencies
get_target_property(Dependencies ${MainTarget} LINK_LIBRARIES)
set(AllTargets ${MainTarget})
foreach(Dependency ${Dependencies})
# If this is a CMake target, add it to the list
if(TARGET ${Dependency})
list(APPEND AllTargets ${Dependency})
endif()
endforeach()
# Gather each target's list of source files ending in ".h"
foreach(Target ${AllTargets})
get_target_property(Sources ${Target} SOURCES)
foreach(Source ${Sources})
string(REGEX MATCH "^.*\\.h$" Header ${Source})
if(Header)
list(APPEND AllHeaders ${Header})
endif()
endforeach()
endforeach()
# Since functions have their own scope, set the list in the parent scope
set(${Headers} ${AllHeaders} PARENT_SCOPE)
endfunction()
and invoke it using your first choice:
get_target_headers(example_header example)