I understand that every subdirectory has to have a CMakeLists.txt, but I don't want to create a library or an executable for each directory.
My folder structure:
/src
/exportedHeaders
/server
main.cpp
Each subfolder has a mix of .h and .cpp files. I don't understand how I can mix all of it up into a single executable, there doesn't seem to be a command for that.
I haven't really used CMake, so there is probably a better way, but as far as I know you can just specify the path to all the source files.
eg:
add_executable (myProgram main.cpp subdir1/foo.cpp subdir2/bla.cpp)
I imagine you could use file globbing to get *.cpp in each subdir, to reduce typing.
See this mailing list message for info about file globbing in CMake.
Related
Consider the following CMakeLists.txt file:
add_subdirectory(execA)
add_subdirectory(libB)
install(TARGETS execA libB
RUNTIME DESTINATION bin
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
I get the following error:
install TARGETS given target "execA" which does not exist in this
directory
execA and libB have their own CMakeList.txt files and are located under project directory, as well as the build directory I'm running cmake (cmake ..):
project
|------ CMakeList.txt (the one with the code)
|----execA
| \- .cpp, .hpp and CMakelist.txt
|----libB
| \- .cpp, .hpp and CMakelist.txt
|---- lib
|---- bin
\---- build (where I´m commanding: $ cmake ..
How do I fix this error?
According to this bugreport, install(TARGETS) command flow accepts only targets created within the same directory.
So you need either move the add_library() call into the top-level directory, or split install(TARGETS) call into per-target ones, and move each of them into the corresponding subdirectory.
Since CMake 3.13 install(TARGETS) can work even with targets created in other directories.
install(TARGETS) can install targets that were created in other directories. When using such cross-directory install rules, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date.
Even though it would help seeing the CMakeLists.txt files contained in the subdirectories, I guess they contain add_executable and/or add_library statements to create your stuff.
Also, because of your example, I guess you are using the same name of your directories for your targets.
That said, you should know that symbols defined in a CMakeLists.txt file in a subdirectory are not visible by default within the context of the CMakeLists.txt file in the parent directory. Because of that, you should rather move your install statements within the CMakeLists.txt files within your subdirectories.
This should solve the problem, if my thoughts were right. Otherwise, I strongly suggest you to post in your question also the content of the other files above mentioned.
Anyway, the error is quite clear.
The file that contains the install statement for the target named X does not contain a target creation statement (add_executable and the others) that gives birth to that target, so it goes on saying that that target does not exist in that directory.
This still seems to be a pain point in CMake 3.11.
In our codebase, we have many targets defined in subdirectories and need to create an assortment of installers with different configurations and (potentially overlapping) combinations of targets.
Here's my solution:
Before calling add_subdirectory in your root CMakeLists.txt file, create a GLOBAL property with the names of the target(s) you want to include in your installer.
Wrap target creation functions (add_executable, etc.) in your own custom functions. Within those functions check if the target is present in the global property, and invoke install accordingly.
That approach allows you to centralize installer configuration.
Also: To support creation of multiple installers, we populate our global list along with other installer properties in separate .cmake files. When we invoke cmake, we pass the name of the installer configuration CMake file as a command-line argument. Our root CMakeLists.txt file simply calls include with that file.
If I do FILE (GLOB "*.cpp") where does it look? What is the working directory of the search? Is it the current source directory? This doesn't seem to be documented anywhere (although it is for FILE (COPY).
The FILE(GLOB globbing expression) accepts paths in the globbing expression to. Thus you can include any path into the expression. The following example finds all files with extension dat in subfolder testdata:
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/testdata/*.dat")
Note: The usage of predefined path variables like CMAKE_CURRENT_SOURCE_DIR avoids any thinking about relative paths and made CMakeLists.txt more reusable and platform independent.
Bad:
file(GLOB generatedSources "../build-arm/autocode/*.c")
Good:
file(GLOB generatedSources "${PROJECT_BINARY_DIR}/autocode/*.c")
You can also specify a RELATIVE path. I'm not sure when the RELATIVE option was added, but it appears to be available from at least v3.0.2.
The search occurs in the current source directory, i.e. the directory of your CMakeLists.txt.
As a side remark regarding what you want to achieve with this, I would emphasize the following:
Note: We do not recommend using GLOB to collect a list of source files
from your source tree. If no CMakeLists.txt file changes when a source
is added or removed then the generated build system cannot know when
to ask CMake to regenerate.
i like to structure my code in multiple subdirs but i dont want to create a new cmakelist.txt in each new subdir.
my folder structure is something like this:
project
>cmakelist.txt
>build
>src
>main.cpp
>multiple_subdirs_or_(c|h)pp_files_with_more_subdirs_or_(c|h)pp_files
my cmakelist.txt looks like this:
...
file(GLOB_RECURSE cpps RELATIVE ${CMAKE_CURRENT_LIST_DIR} "src/*.cpp")
file(GLOB_RECURSE hpps RELATIVE ${CMAKE_CURRENT_LIST_DIR} "src/*.hpp")
#remove files with main
list(REMOVE_ITEM cpps "src/test.cpp")
#bins
add_executable(test src/test.cpp src/test.cpp ${hpps} ${cpps})
#same problem if this is used instead of the other add_executable
add_library(foo OBJECT ${cpps} ${hpps})
add_executable(test src/test.cpp $<TARGET_OBJECTS:foo>)
the problem with my file:
source files created after the execution of cmake are not compiled and the build fails if they are used.
as predicted by http://www.cmake.org/cmake/help/v3.0/command/file.html in section GLOB:
We do not recommend using GLOB to collect a list of source files from
your source tree. If no CMakeLists.txt file changes when a source is
added or removed then the generated build system cannot know when to
ask CMake to regenerate.
the question: is it possible to use a single cmakelist.txt for a project with multiple sub directories? (without the problems of file(GLOB ...) )
You have two totally unrelated things here.
First, can you use only a single CMakeLists.txt file for your whole project? Yes, of course you can (although I'd personally not go this way after a project has reached a certain size), and you're already doing this.
Second, the problem with GLOB. You already quoted the part of the documentation where it states what problems the use of GLOB has. This cannot really be avoided at the moment if you want to continue using GLOB, as this is part of the cmake design where they distinguish between what is done during configure and build time. The alternative is to list all files manually. Whether you do this in a single CMakeLists.txt file in your projects main directory, or in multiple files across your subdirectories does not matter.
To answer your question: yes, it is possible to handle a project with multiple sub-directories and one CMakeLists.txt. I have two considerations for you to take into account:
I strongly recommend you not using file(GLOB ...) for sources.
You have to list the files manually. For example (src/ is the source-subdirectory):
set(cpps src/file1.cpp src/file2.cpp src/file3.cpp)
I have a CMakeLists.txt file for a library. It's pretty basic:
set(LIB_FILES source/first.cpp)
add_library(first ${LIB_FILES})
I put the files in a list because I will eventually be adding more source files to the library. The problem is that all of the files will be in the source directory. And I don't want to constantly have to repeat that.
I also don't want to use the GLOB pattern matching solution, because I want to have to edit the CMakeLists.txt file when I add a new file. That way, my build will re-build the build solution, and new files will correctly appear (as I understand it. I'm still new with CMake).
I tried adding a CMakeLists.txt file into the source directory itself, just to build the LIB_FILES list. That didn't work out very well. Variables in CMake are file scoped. And even when I broke scoping (with PARENT_SCOPE), I still had to prefix each file with the directory. So that gained nothing.
I don't want to put the actual library definition in the source directory, as that will generate all the build files in the source directory. And I don't want that. Also, I will need to include headers that aren't in or under the source directory.
My directory structure looks like this:
libroot (where the project build files should go)
\-source (where the source code is)
\-include (where the headers that the user of the library includes go)
So how do I tell CMake that all of the source files come from the source directory, so that I don't have to constantly spell it out?
You could move the add_library call to your source/CMakeLists.txt also:
set(LIB_FILES first.cpp)
add_library(first ${LIB_FILES})
Then just use add_subdirectory in your top-level CMakeLists.txt:
add_subdirectory(source)
you could use a simple macro for that
macro(AddSrc dst_var basepath_var)
foreach(file ${ARGN})
list(APPEND ${dst_var} ${basepath_var}/${file})
endforeach()
endmacro()
set(MY_SRCFILES "")
AddSrc(MY_SRCFILES path/to/source
foo.cpp
bar.cpp
whatever.cpp
)
I have this variable set in the root CMakeLists.txt
set(${LIBNAME}_srcs
File1.cpp
File2.cpp
File3.cpp
File4.cpp
File5.cpp
)
add_subdirectory(A)
and I want to add the variable as a source for the executable in the subdirectory A
add_executable(${TEST}}
What is the cleanest way to do this? without having to create a new variable with ../ on all the source files? Or is there a macro I can use?
You can insert the absolute path to each of the values in ${LIBNAME}_srcs by doing something like:
foreach(${LIBNAME}_src ${${LIBNAME}_srcs})
list(APPEND abs_${LIBNAME}_srcs ${CMAKE_SOURCE_DIR}/${${LIBNAME}_src})
endforeach()
add_executable(${TEST} ${abs_${LIBNAME}_srcs})
Jumping to conclusions here, it looks like what you're doing may be a bit unusual.
Normally the add_executable call would be made in the same place where the list of source files is gathered - usually in the same directory.
Going by the fact that you've named your sources variable ${LIBNAME}_srcs, I'd guess that you're already creating a library from these sources. If so, it'd be better to just link that library in your test subdirectory rather than recompiling all the library's sources into the executable.
Something like:
add_executable(${TEST} test_main.cpp)
target_link_libraries(${TEST} ${LIBNAME})
When I add sources, I do something like this:
set(${LIBNAME}_srcs
${SRC}/File1.cpp
${SRC}/File2.cpp
${SRC}/File3.cpp
${SRC}/File4.cpp
${SRC}/File5.cpp
)
Where ${SRC} is the absolute path to the source directory found using ${CMAKE_SOURCE_DIR}.
Then, you can simply use add_executable(${TEST} ${LIBNAME}_srcs) in your subdirectory. CMake will automatically import the scope of parent directories into child directories.