berak
berak

Reputation: 39816

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?

Upvotes: 134

Views: 92745

Answers (6)

zap
zap

Reputation: 31

Adding on to existing comments, it seems clearest and most robust if the relative path is provided to the glob, because many are finding the glob will give absolute paths otherwise. Something like:

file(GLOB lib_srcs RELATIVE ${CMAKE_SOURCE_DIR} CONFIGURE_DEPENDS
     Half/half.cpp Iex/*.cpp IlmThread/*.cpp Imath/*.cpp IlmImf/*.cpp)
list(REMOVE_ITEM lib_srcs "IlmImf/b44ExpLogTable.cpp")

Note that the CMake best practice is to not use globs for sourcefiles, specifically because they were unable to make CONFIGURE_DEPENDS detect filechanges in all situations, as well as it adds overhead to every build to try.

Upvotes: 0

Foad S. Farimani
Foad S. Farimani

Reputation: 14056

The accepted answer on this page does not work properly as mentioned here. You must fetch the absolute path to the files you want to exclude. So I developed a simple CMake function based on this proposal:

function(efile out_var)
  set(options)
  set(oneValueArgs GLOB)
  set(multiValueArgs EXCLUDE)
  cmake_parse_arguments(EFILE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

  # Use file(GLOB ...) to collect all files matching the provided patterns
  file(GLOB_RECURSE temp_files CONFIGURE_DEPENDS ${EFILE_GLOB})

  # Apply exclusions
  foreach(exclude_pattern ${EFILE_EXCLUDE})
    # Filtering out files from the list that match the exclude patterns
    list(FILTER temp_files EXCLUDE REGEX "${exclude_pattern}")
  endforeach()

  # Set the results to the output variable
  set(${out_var} "${temp_files}" PARENT_SCOPE)
endfunction()

And you may use the efile function, standing for extended file, in your CMake project:

# Assuming you want to include all C files in the src directory but exclude the main.c file
efile(my_sources GLOB "${CMAKE_CURRENT_SOURCE_DIR}/src/*.c" EXCLUDE "main.c")

# Print the list of files collected
message("Sources: ${my_sources}")

please give it a try and let me know if it works properly.

Upvotes: 0

Marek R
Marek R

Reputation: 38209

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.

Upvotes: 1

Eugene
Eugene

Reputation: 3447

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).

Upvotes: 89

James
James

Reputation: 129

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

Upvotes: 4

Lindydancer
Lindydancer

Reputation: 26164

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")

Upvotes: 139

Related Questions