MKFein
MKFein

Reputation: 91

CMake exclude dir with a regular expression

I want to exclude some dirs from building by using the following:

file(GLOB_RECURSE Foo_SOURCES "*.c" "*.cpp")

# Enter the excluded directories here
set (excludeDirName "")
list (APPEND excludeDirName "/test")
list (APPEND excludeDirName "/std")

set (Foo_SOURCES_FILES "")
foreach (_sourceFile ${Foo_SOURCES})
    foreach (_excludeDirName ${excludeDirName})
        if (NOT "${_sourceFile}" MATCHES "(.*)${_excludeDirName}(.*)")
            list (APPEND Foo_SOURCES_FILES ${_sourceFile})
        endif ()
    endforeach ()
endforeach ()

Sadly no dirs are excluded. I think it depends on using a regex on a file / list mix.

Upvotes: 0

Views: 977

Answers (1)

Tsyvarev
Tsyvarev

Reputation: 66288

The problem of inner loop

foreach (_excludeDirName ${excludeDirName})
    if (NOT "${_sourceFile}" MATCHES "(.*)${_excludeDirName}(.*)")
        list (APPEND Foo_SOURCES_FILES ${_sourceFile})
    endif ()
endforeach ()

is that it matches a file multiple times, and the file is added when any of matches is failed. But you need the opposite behaviore: the file should be added only when all matches are failed.

You may rewrite the loop as:

set(is_matched FALSE)
foreach (_excludeDirName ${excludeDirName})
    if ("${_sourceFile}" MATCHES "(.*)${_excludeDirName}(.*)")
       set(is_matched TRUE) 
    endif ()
endforeach ()
if (NOT is_matched)
    list (APPEND Foo_SOURCES_FILES ${_sourceFile})
endif()

that it will firstly checks all matches, and a file will be added only after none match is succeed.

Alternatively, you may construct regular expression which attempt to match all directories at once, using | operator:

# Join list of directories into the string using '|' delimiter
list(JOIN excludeDirName '|' exclude_dir_regex)

foreach (_sourceFile ${Foo_SOURCES})
    # This would replace the inner loop.
    if (NOT "${_sourceFile}" MATCHES "(.*)(${exclude_dir_regex})(.*)")
       list (APPEND Foo_SOURCES_FILES ${_sourceFile})
    endif ()
 endfor ()

Of course, the last approach would work only if directories doesn't contain characters, special for regular expressions (like . or ().

The last approach could be implemented even without loops using list(FILTER):

# Join list of directories into the string using '|' delimiter
list(JOIN excludeDirName '|' exclude_dir_regex)

# Make output list of files same as input list...
set (Foo_SOURCES_FILES FOO_SOURCES)
# ... and filter out unneeded files
list(FILTER Foo_SOURCES_FILES EXCLUDE "${exclude_dir_regex}")

Upvotes: 1

Related Questions