Keeping file hierarchy across subdirectories in CMake

前端 未结 3 1217
北恋
北恋 2020-12-06 12:57

Till date I still do not really understand what the \'best practice\' is for doing this for a CMake project with many subdirectories.

Say I have a project hierarchy

相关标签:
3条回答
  • 2020-12-06 13:32

    There is a fourth way if you're using newer versions of CMake.

    Take a look at target_sources() command of CMake.

    It seems like you are declaring your target in your CMakeLists.txt

    add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
    add_subdirectory(subd1)
    add_subdirectory(subd2)
    

    Instead of propagating your Source files up to the root you can depend on the target you have defined in the root CMakeLists.txt. That means subd1/CMakeLists.txt may look like:

    target_sources(my_target PRIVATE "subd1/Source.cpp" "subd1/Source2.cpp")
    

    [EDIT]

    As stated in the comments you must give the relative path of the source-files to target_sources(). I use target_sources() because I do not want the explicit source file listing to pollute the targets CMakeLists.txt. Another use case is that target_sources() can be invoked with the PUBLIC or INTERFACE keyword to propagate source files to depending targets. Well I never used target_sources() that way.

    [/EDIT]

    If you're using IDEs like Visual Studio that support folders you make want to also declare a source_group() in the CMakeLists.txt that contains your target. So the root CMakeLists.txt may look like:

    add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
    add_subdirectory(subd1)
    add_subdirectory(subd2)
    ...
    source_group(subd1 REGULAR_EXPRESSION "subd1/*")
    source_group(subd2 REGULAR_EXPRESSION "subd2/*")
    

    I'm using this approach because it leads to much cleaner CMakeLists.txt files, its lesser work and I think the introduction of not needed variables only raises the complexity of your CMakeLists.txt files.

    CMakeLists.txt as target sources

    I currently use the CMakeLists.txt of the sub folders as source files of the target because otherwise CMake will complain that the add_executable command has no source files given.

    0 讨论(0)
  • 2020-12-06 13:34

    In your case there's no need to use add_subdirectory since you have only one target which is created in the root CMakeLists.txt. You can simply write this:

    add_executable(myProg
        SubD1/Source.cpp
        SubD1/SubSubD1/Source2.cpp)
    

    Use add_subdirectory for subdirectories creating their own targets so there's no information to pass upwards.

    0 讨论(0)
  • 2020-12-06 13:46

    There are 3 ways I have used before. I normally prefer the 1st way, but have already used all 3 depending on the use case:

    1. You directly name the sources in your root CMakeLists.txt file

    set(
        SUBD1_SOURCES
        "SubD1/SubSubD1/Source2.cpp"
        "SubD1/Source.cpp"
    )
    
    set(
        SUBD2_SOURCES
        "SubD2/Source3.cpp"
    )
    
    add_executable(myProg ${SUBD1_SOURCES} ${SUBD2_SOURCES})
    

    2. You use OBJECT intermediate libraries to collect/group your sources

    SubD1/SubSubD1/CMakeLists.txt:

    add_library(SubSubD1Objs OBJECT Source2.cpp)
    

    SubD1/CMakeLists.txt:

    add_subdirectory(SubSubD1)
    add_library(SubD1Objs OBJECT Source.cpp)
    

    CMakeLists.txt:

    add_executable(myProg $<TARGET_OBJECTS:SubSubD1Objs> $<TARGET_OBJECTS:SubD1Objs>)
    

    3. You write your own function() to collect the data (and do the prefixing)

    CMakeLists.txt:

    function(my_collect_sources)
        foreach(_source IN ITEMS ${ARGN})
            if (IS_ABSOLUTE "${_source}")
                set(source_abs "${_source}")
            else()
                get_filename_component(_source_abs "${_source}" ABSOLUTE)
            endif()
            set_property(GLOBAL APPEND PROPERTY GlobalSourceList "${_source_abs}")
        endforeach()
    endfunction(my_collect_sources)
    
    add_subdirectory(SubD1)
    #add_subdirectory(SubD2)
    
    get_property(MY_SOURCES GLOBAL PROPERTY GlobalSourceList)
    add_executable(myProg ${MY_SOURCES})
    

    SubD1/CMakeLists.txt:

    add_subdirectory(SubSubD1)
    my_collect_sources(Source.cpp)
    

    SubD1/SubSubD1/CMakeLists.txt:

    my_collect_sources(Source2.cpp)
    
    0 讨论(0)
提交回复
热议问题