This is what I think. Full disclaimer: I'm not really a cmake
guru, and this answer is solely based on my research after reading the question. I don't have a project to test this on, and I have never used vpath
in a Makefile
that I've written.
In addition, this question does not post an example Makefile
, nor does it post the macro used by the OP, which makes me hesitant about giving a "use this" answer, but here goes.
Firstly: why are we using vpath
in our Makefile
?
Because I didn't know what vpath
was, I looked it up. From the GNU Make Manual, section 4.5:
The directory search features of make facilitate this by searching several directories automatically to find a prerequisite...
Similar to the VPATH
variable, but more selective, is the vpath
directive (note lower case), which allows you to specify a search path for a particular class of file names: those that match a particular pattern. Thus you can supply certain search directories for one class of file names and other directories (or none) for other file names.
So, you're using vpath
to find files that are spread over several directories. These files, I'm further presuming, are either source files or are intermediate files created during the build process.
I found several examples of vpath
, which seem indicative of it's usage - this StackOverflow question, this one and finally, Managing Projects with GNU make, 3rd Edition section 2.3.
So that's why you'd be using vpath
. So, moving on:
Secondly, how do you achieve the same thing using cmake
. And this is where further input from the OP would be helpful.
If you have multiple targets that you are building from a directory structure like this:
|- library1/
|-- {C++ Source}
|- Tool/
|-- {C++ Source}
|- Project/
|-- src/
|---- {C++ Source}
You should be using multiple CMakeLists.txt
, one in each of the subdirectories. In library1
, you'd build the library (ADD_LIBRARY( libNAME src1.cxx src2.cxx src3.cxx )
), in Tool
you'd add an executable (ADD_EXECUTABLE( theTOOL src1.cxx src2.cxx )
). Finally, in Project/src/
you'd build your project executable with the ADD_EXECUTABLE
, linking it to libNAME
that you've built in library1
.
In this scenario, you never need to search, because your source is explicitly placed in the CMakeLists.txt
.
If you are not doing something like the above, and your source is just spread over many many directories, something like this:
|-Project/
|--src/
|----maths/
|------ { SOURCE FILES }
|----sound/
|------ { SOURCE FILES }
|----imagegeneration/
|------ { SOURCE FILES }
In this case, you're only building the one thing, and you're just spreading your source out for ease-of-use. In this case, there are several options for you.
You can use the answer posted here to automatically add all files of a type to a target. This is NOT supposed to be done! From the cmake --help-command file
(emphasis mine):
GLOB will generate a list of all files that match the globbing expressions and store it into the variable ... We do not recommend using GLOB to collect a list of source files from your source tree.
[See below for the reason why]
You can use the add_subdirectory
directive to add multiple subdirectories, one for each of your source subdirectory. This is also not ideal. (Some supporting documentation: a link which discusses the use of add_subdirectory
in this manner)
You can use the aux_source_directory
to collect the source files from the specified directory and store in a variable. (Read cmake --help-command aux_source_directory
if you're interested in it). However, this, too, is not recommended.
So why shouldn't you use (1), (2) or (3)?
cmake
is not a replacement for make
or Makefiles
. Rather, cmake
generates a build system
, which you then use to build your project. This is a distinction worth noting. While you could easily add multiple sources to your CMakeLists.txt
automatically, you will cause an ambiguity for cmake
: cmake
will be unable create a build system that is aware of source files to determine what has changed!
This is the issue with all three methods mentioned above. From cmake --help-command aux_source_directory
:
While this seems to work,
there is no way for CMake to generate a build system that knows when a
new source file has been added. Normally the generated build system
knows when it needs to rerun CMake because the CMakeLists.txt file is
modified to add a new source. When the source is just added to the
directory without modifying this file, one would have to manually
rerun CMake to generate a build system incorporating the new file.
Summation: how should you add source files to cmake
?
When using cmake
, you should be explicitly adding source files to each of your CMakeLists.txt
. If you are using multiple directories to separate logical pieces of code, that should be explicitly set in a CMakeLists.txt
, something similar to the following:
set ( MyApplication_SRC_FILES
maths/a.cpp
maths/b.cpp
sound/c.cpp
sound/d.cpp
imagegeneration/e.cpp
imagegeneration/f.cpp
)
ADD_EXECUTABLE ( MyApplication ${MyApplication_SRC_FILES} )
This then allows cmake
to generate a build system which can build your code. There are appropriate methods to add numerous files in directories to the build system, outlined in (1), (2) and (3) above; but they should be treated with caution and not used just because "that's how I did it with my Makefile
". You don't write the build system itself; this is a step back from the Makefile
, and as such should be treated slightly differently.