Multiple source directories for one executable with CMake

19,453

Solution 1

Here the my simple example

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
project(foo CXX)
# get all *.cpp files recursively
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
add_executable(foo ${SRC_FILES})

Solution 2

Another (arguably better for big code bases) variant is to use a separate CMakeLists.txt for each sub-directory where you isolate adding sources of the directory to a target using target_sources and maybe some particular configuration settings \ include conditions for those sources:

target_sources( SomeExeOrLib PRIVATE source1.h source1.cpp )

here you also have more control of the scope by specifying PRIVATE, other options are INTERFACE or PUBLIC. See details here: https://cmake.org/cmake/help/v3.3/command/target_sources.html

Solution 3

Yes, that would work.

Update: What follows is not very relevant anymore because nowadays CMake supports response files, so there shouldn't be problems with too long command lines.

However you might have troubles when the number of files get too high, and the command line too long for your compiler to be able to handle it. A possible solution is to add a static library for each subdirectory, add them to a list "ALL_MY_SUB_LIBS", and link them to the main target foo in this way:

target_link_libraries(foo "-Wl,--whole-archive") #like opening a parenthesis
target_link_libraries(foo ${ALL_MY_SUB_LIBS}) 
target_link_libraries(foo "-Wl,--no-whole-archive") #like closing a parenthesis

ld linker question: the --whole-archive option

Share:
19,453
realh
Author by

realh

Updated on June 20, 2022

Comments

  • realh
    realh about 2 years

    I want my source organised in a number of subdirectories but be able to create a single executable without having to build a library for each subdirectory. Can CMake do this? Something like:

    ADD_EXECUTABLE(foo a/main.cpp a/other.cpp b/another.cpp)

    Is it that simple? With the / working as a directory separator regardless of platform?

  • realh
    realh almost 11 years
    Yes, I suppose there's no real reason why I shouldn't still build a library for each subdirectory, although I don't anticipate a large number of sources. I just feel it would be easier to manage one top-level CMakeLists.txt instead of one for every sub-directory, all 90% identical. The main reason for the grouping is that some files platform-specific, some need different flags etc.
  • realh
    realh almost 11 years
    Actually there is a good reason not to use libraries in my case; the directories depend on each other both ways and the linker can't cope with that. Otherwise, aside from teething problems of a CMake newbie, this does work.
  • Antonio
    Antonio almost 11 years
    @realh Did you try? We are using this technique in one of our projects, a lot of dependencies among the helper-libraries, yet link with whole-archive cope well with it.
  • Antonio
    Antonio almost 11 years
    @realh You can also check this, another parenthesis you could open for the compiler :) stackoverflow.com/a/17168671/2436175 (Anyway, I repeat, I doubt it is necessary for this case)
  • thiagowfx
    thiagowfx over 10 years
    Is this CXX (second line) needed? Could I use project(foo) only?
  • Sergei Nikulov
    Sergei Nikulov over 10 years
    @thiagowfx yes, it is optional - refere to cmake.org/cmake/help/v2.8.12/cmake.html#command:project
  • Loebre
    Loebre over 7 years
    @Antonio. Hello. I am trying to use your solution in my subdirectories cmakelist.txt being foo the parent directory but The CMakeList.txt of my subdirectories complain saying that "Attempt to add link library "-Wl,--whole-archive" to target "foo" which is not built in this directory." Am I missing something in my parent directoryes.? thnx
  • Antonio
    Antonio over 7 years
    @Loebre Nowadays CMake supports response files, so you shouldn't have problems with too long command lines. Just update all components of your build chain.
  • András Aszódi
    András Aszódi almost 7 years
    Great suggestion. I have found a tutorial at crascit.com/2016/01/31/… which explains the details very well.
  • Raulp
    Raulp about 3 years
    can we replace the last line with : add_executable(openshell ${SOURCES})??