CMake : How to get the name of all subdirectories of a directory?

Cmake

Cmake Problem Overview


I have two questions relative to CMake

  1. Assume that we have a variable ${MY_CURRENT_DIR} that contains the path of a directory that contains several subdirectories : mydir1, mydir2 and mydir3. I want to detect these subdirectories and put their names into ${SUBDIRS} (not the complete path of these directories, only their name). How to do that automatically ?

  2. Assume that ${SUBDIRS} contains "mydir1 mydir2 mydir3". How to replace

     ADD_SUBDIRECTORY(mydir1)
     ADD_SUBDIRECTORY(mydir2)
     ADD_SUBDIRECTORY(mydir3)
    

by a loop over ${SUBDIRS}?

Cmake Solutions


Solution 1 - Cmake

  1. Use this macro:

     MACRO(SUBDIRLIST 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()
    

Example:

    SUBDIRLIST(SUBDIRS ${MY_CURRENT_DIR})

2. Use foreach:

    FOREACH(subdir ${SUBDIRS})
      ADD_SUBDIRECTORY(${subdir})
    ENDFOREACH()

Solution 2 - Cmake


In regard to answer above: Use this macro:

MACRO(SUBDIRLIST 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()

Example:

SUBDIRLIST(SUBDIRS ${MY_CURRENT_DIR})

I had trouble with this FILE(GLOB command. (I'm on cmake 3.17.3) Otherwise the macro works great. I was getting FILE GLOB errors, something like "FILE GLOB requires a glob expression after the directory." (Maybe it didn't like RELATIVE and/or just using the curdir as the fourth paramter.)

I had to use:

FILE(GLOB children ${curdir}/*)

(taking out RELATIVE and the first ${curdir} (Please note my cmake version above, that could've been my issue (I'm unfamiliar with glob so far.).)

Solution 3 - Cmake

For a modern simpler solution try this
For cmake 3.7 and above the GLOB module got a LIST_DIRECTORIES option

This link explains glob patterns

file(GLOB sources_list LIST_DIRECTORIES true YourGLOBPattern)
foreach(dir ${sources_list})
    IF(IS_DIRECTORY ${dir})
        add_subdirectory(${dir})
    ELSE()
        CONTINUE()
    ENDIF()
endforeach()

Solution 4 - Cmake

@refaim answer didn't work for me with CMake 3.21.1, I had to do small changes:

MACRO(SUBDIRLIST result curdir)
    FILE(GLOB children ${curdir}/*) # This was changed
    SET(dirlist "")
    FOREACH(child ${children})
        IF(IS_DIRECTORY ${child}) # This was changed
            LIST(APPEND dirlist ${child})
        ENDIF()
    ENDFOREACH()
    SET(${result} ${dirlist})
ENDMACRO()

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionVincentView Question on Stackoverflow
Solution 1 - CmakerefaimView Answer on Stackoverflow
Solution 2 - CmakeskittlebizView Answer on Stackoverflow
Solution 3 - CmakeJN98ZKView Answer on Stackoverflow
Solution 4 - CmakeMartin HofbauerView Answer on Stackoverflow