11

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
  • 962
  • 2
  • 7
  • 22

3 Answers3

15

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})
Sergei Nikulov
  • 5,029
  • 23
  • 36
7

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

Roman Kruglov
  • 3,375
  • 2
  • 40
  • 46
  • 1
    Great suggestion. I have found a tutorial at https://crascit.com/2016/01/31/enhanced-source-file-handling-with-target_sources/comment-page-1/#comment-414 which explains the details very well. – András Aszódi Sep 07 '17 at 15:30
1

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

Community
  • 1
  • 1
Antonio
  • 19,451
  • 13
  • 99
  • 197
  • 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 Jul 30 '13 at 16:31
  • 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. – realh Jul 30 '13 at 22:25
  • @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 Jul 31 '13 at 06:49
  • @realh You can also check this, another parenthesis you could open for the compiler :) http://stackoverflow.com/a/17168671/2436175 (Anyway, I repeat, I doubt it is necessary for this case) – Antonio Aug 02 '13 at 14:44
  • @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 – Loebre Jan 26 '17 at 10:24
  • @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. – Antonio Feb 13 '17 at 12:15