8

I have a C++ project where all implementation source files (*.cpp) reside in a src directory within the project directory. Some of the files are in further subdirectories. Let's say there are 50 files in src/foo/. I need to list these files as part of the add_library and/or the target_sources function.

Now, everywhere one looks, adding all files from a directory automtically is discouraged, which is fine with me. So I am going to list all the files manually; but repeating the common prefix src/foo/ 50 times seems really silly and is annoying.

In the documentation for target_sources it says

Relative source file paths are interpreted as being relative to the current source directory (i.e. CMAKE_CURRENT_SOURCE_DIR).

So I've added set(CMAKE_CURRENT_SOURCE_DIR "src/foo/") before the call to target_source but it didn't work. (I get a "Cannot find source file" error.)

So what is the correct way to achieve what I want if it is even possible?

N.B.: The (public) header files (*.hpp) of the project are in an include directory (outside of src). This is nicely configured (without having to list the individual files) with the target_include_directories function.

Community
  • 1
  • 1
Chris K
  • 1,376
  • 1
  • 14
  • 18
  • 1
    I think the answer by @Kamil Cuk answers your question. But I wanted to add that setting `CMAKE_CURRENT_SOURCE_DIR` doesn't work because this is a CMake set variable. Also, the "source" directory according to CMake doesn't necessarily have anything to do with the directory of your source files. This is simply the current directory CMake is processing (i.e. where the current CMakeLists.txt is). – Developer Paul Apr 03 '19 at 12:10
  • 1
    Regarding the first part, yes you are right, thanks. Also I found that one needs at least CMake 3.13 for the path extension and set `cmake_policy(SET CMP0076 NEW)`. Regarding the second part, this is kind of a pitty. It would be nice (I think) if there were a clear, consistent nomenclature where *SOURCE* always refers to implementation files and *INCLUDE* always to header files. – Chris K Apr 03 '19 at 12:29
  • 2
    It's safe to assume that if a variable starts with `CMAKE_` it's managed by CMake (usually). The usefulness of `CMAKE_CURRENT_SOURCE_DIR` as opposed to `CMAKE_SOURCE_DIR` comes in when you are using `add_subdirectory()` in your project and need to know where exactly CMake is currently processing a script. – Developer Paul Apr 03 '19 at 12:35

4 Answers4

9

but repeating the common prefix src/foo/ 50 times

Just prepend the prefix to the sources.

set(target_sources
    source1.c
    source2.c
)
list(TRANSFORM target_sources PREPEND "src/foo/")
KamilCuk
  • 120,984
  • 8
  • 59
  • 111
  • 4
    That works and is quite elegant (imho) even though the "new way" (as some say) of CMake is supposed to get away from (directly) setting variables, to a "property-based" approach. Also, for CMake beginners reading this, the transformed list is then used as `add_library(MyProj SHARED ${target_sources})` – Chris K Apr 03 '19 at 12:21
  • 2
    Note that `TRANSFORM` is only available starting from CMake 3.12. – Gino Mempin Jun 27 '19 at 02:46
3

You can also use add_subdirectory(src/foo) and a CMakeLists.txt in src/foo in which you only have to put

target_sources( <your target> PRIVATE|PUBLIC|INTERFACE
  your
  list
  of
  sources
)

I think that would be rather elegant.

RL-S
  • 734
  • 6
  • 21
0

Setting CMAKE_CURRENT_SOURCE_DIR as a relative variable to the old CMAKE_CURRENT_SOURCE_DIR is not going to work. If it's set to a value, then it's fair to assume that removing that value and using a custom one will be wrong because you are missing what it was set to before.

You might want to set it as an absolute path, or use set(CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/src/foo/"), or do as lots of other people and copy paste the prefix all the time. That's the standard practice (which is also one of the reason I still use GLOB, because I'm lazy), following up on explicit is better than implicit (which is the point of not using GLOB).

Matthieu Brucher
  • 21,634
  • 7
  • 38
  • 62
  • Thanks, I did forget to concatenate the additional path to CMAKE_CURRENT_SOURCE_DIR but this was not at the heart of the problem (still did not work). – Chris K Apr 03 '19 at 12:17
  • 1
    See this answer [link](https://stackoverflow.com/questions/73042171) with solution `list(TRANSFORM SOURCES PREPEND "src/") `after I posted similar question. – Yifangt Jul 19 '22 at 20:09
0

I would have suggested (if you have bash or some similar shell)

function prepend() { while read line; do echo "${1}${line}"; done; }
ls *.cc *hh | sort | prepend  "\${CMAKE_CURRENT_SOURCE_DIR}/"

then copy and paste :)

user3589502
  • 51
  • 1
  • 1
  • 3