Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Excluding directory somewhere in file structure from cmake sourcefile list

Tags:

cmake

In any subdirectory of my project it shall be possible to create anywhere a directory called 'hide' and put some code files (.c, .cpp, .h, ...) inside. CMake shall ignore those files. How can I achieve this? Any proposals for a simple approach? Searched the net but could not find a solution.

What I tried:

file & glob

file(GLOB_RECURSE SOURCE_FILES "*.cpp" "*.c")
file(GLOB_RECURSE REMOVE_SOURCES  
  "*/hide/*"
  "${PROJECT_SOURCE_DIR}/CMakeFiles/*"
  "*main.c")
file(GLOB_RECURSE REMOVE_SOURCES "*/hide/*")
list(REMOVE_ITEM SOURCE_FILES ${REMOVE_SOURCES})

The 2rd line works fine if the directory path is known (as for the 'CMakeFiles' directory) or if the file is known (as for the 'main.c' file). But it does not work if there are two '*' for a string. I can not find a simple solution for a directory which is located somewhere.

Regex

Then I tried with REGEX.

file(GLOB_RECURSE SOURCE_FILES "*.cpp" "*.c")
string(REGEX REPLACE ";.*/hide/.*;" ";" FOO ${SOURCE_FILES})

Because the source file list is separated by semicolon, the line above shall remove the string from one semicolon to the next in case it contained the string 'hide'. The expression seems to have a problem with the semicolon. Having any semicolon makes the command to find nothing.

foreach loop

I tried with some foreach loops, but could not achieve to get a list of all my 'hide'-directories.

like image 693
Led Avatar asked Jun 30 '14 13:06

Led


3 Answers

One of the ways, I suppose, would be just like this:

set (EXCLUDE_DIR "/hide/")
file (GLOB_RECURSE SOURCE_FILES "*.cpp" "*.c")
foreach (TMP_PATH ${SOURCE_FILES})
    string (FIND ${TMP_PATH} ${EXCLUDE_DIR} EXCLUDE_DIR_FOUND)
    if (NOT ${EXCLUDE_DIR_FOUND} EQUAL -1)
        list (REMOVE_ITEM SOURCE_FILES ${TMP_PATH})
    endif ()
endforeach(TMP_PATH)

Simply searching for /hide/ substring in strings from the list. If the substring found --- remove whole string from the list.

Beware, this might be only solution for Linux. And might not work on older versions of CMake (<2.8.5, according to this).

In mentioned case You can do something like:

# try to replace substring with empty string, compare to original:
string (REPLACE ${EXCLUDE_DIR} "" REPLACED_PATH ${TMP_PATH})
string (COMPARE EQUAL ${TMP_PATH} ${REPLACED_PATH} EXCLUDE_DIR_FOUND)

NOTE: GLOB_RECURSE is considered to be root of all evil.

NOTE2: another thing to be aware of - CMake bug in matching empty variable to string.

NOTE3: took into account gg99's comment

like image 174
Kamiccolo Avatar answered Oct 21 '22 09:10

Kamiccolo


Found a solution that works for me. Added a function to make it easy to exclude another directory.

# Function:                 EXCLUDE_FILES_FROM_DIR_IN_LIST
# Description:              Exclude all files from a list under a specific directory.
# Param _InFileList:        Input and returned List 
# Param _excludeDirName:    Name of the directory, which shall be ignored.
# Param _verbose:           Print the names of the files handled

FUNCTION (EXCLUDE_FILES_FROM_DIR_IN_LIST _InFileList _excludeDirName _verbose)
  foreach (ITR ${_InFileList})
    if ("${_verbose}")
      message(STATUS "ITR=${ITR}")
    endif ("${_verbose}")

    if ("${ITR}" MATCHES "(.*)${_excludeDirName}(.*)")                   # Check if the item matches the directory name in _excludeDirName
      message(STATUS "Remove Item from List:${ITR}")
      list (REMOVE_ITEM _InFileList ${ITR})                              # Remove the item from the list
    endif ("${ITR}" MATCHES "(.*)${_excludeDirName}(.*)")

  endforeach(ITR)
  set(SOURCE_FILES ${_InFileList} PARENT_SCOPE)                          # Return the SOURCE_FILES variable to the calling parent
ENDFUNCTION (EXCLUDE_FILES_FROM_DIR_IN_LIST)


EXCLUDE_FILES_FROM_DIR_IN_LIST("${SOURCE_FILES}" "/hide/" FALSE)
like image 25
Led Avatar answered Oct 21 '22 09:10

Led


Generalizing the function solution mentioned above you get something like:

# Remove strings matching given regular expression from a list.
# @param(in,out) aItems Reference of a list variable to filter.
# @param aRegEx Value of regular expression to match.
function (filter_items aItems aRegEx)
    # For each item in our list
    foreach (item ${${aItems}})
        # Check if our items matches our regular expression
        if ("${item}" MATCHES ${aRegEx})
            # Remove current item from our list
            list (REMOVE_ITEM ${aItems} ${item})
        endif ("${item}" MATCHES ${aRegEx})
    endforeach(item)
    # Provide output parameter
    set(${aItems} ${${aItems}} PARENT_SCOPE)
endfunction (filter_items)

You can then use it thus:

file(GLOB_RECURSE MyFunFiles "*.fun")
filter_items(MyFunFiles ".*NotCool.*")
like image 44
Slion Avatar answered Oct 21 '22 07:10

Slion