Move duplicated CmakeLists.txt functionality to a common file - cmake

I have multiple projects that have identical/duplicated code in their respective CMakeLists.txt. At the very least I need a place to store string definitions that I can pull into the CMakeLists.txt files. What's the best way to do this? My directory structure
common_defs/
src_files
hdr_files
CMakeLists.Txt - file that has common defs
independent_dir1/
src_files
hdr_files
CMakeLists.Txt --> Imports/Includes from ../common_defs/CMakeLists.txt
independent_dir2/
src_files
hdr_files
CMakeLists.Txt --> Imports/Includes from ../common_defs/CMakeLists.txt
independent_dir1 and independent_dir2 will be built independently from each other. Building in common_defs should not trigger builds in the independent_dirs

Create a file in common_defs/common_defs.cmake with common strings and definitions, than add to your CMakeLists.txt:
// add path common_defs to include search path
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/../common_defs")
// include module from file common.cmake searched in search path
include(common_defs)

Related

How can we refer external cmake file from main CMakeLists.txt file?

Let's say I have some protobuf related cmake code as a library that resides inside CMakeLists.pro file and I need to include this library as a external file configuration. How to do that ?
I think this question is asking how to make cmake modules. IE you have helper code and would like to make it easily available.
A normal top level project has a top level cmake folder. Here is an example of what that would look like.
cmake
tests
src
.gitignore
CMakeLists.txt
README.md
Inside the cmake folder say you have a cmake module called foo.cmake
(It's important to make the file end with .cmake file extension)
Anyway this is what your foo.cmake may look like
# Include guards need at least cmake 3.10
include_guard() # Good practice to use an include_guard()
function(bar)
...
endfunction()
Now in your main cmakelists how do you call this function? Simple.
cmake_minimum_required(VERSION 3.18)
# Add the cmake folder to the cmake module path, this makes it easier to include files
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/")
# Include foo.cmake
include(foo)
# Call the bar function you defined in foo.cmake
bar()
And that's how you can refer to external cmake file from the main CMakeLists.txt

Adding extra source files to ALL CMake targets?

How can I add several source files to ALL CMake add_executable()s (aka. targets)?
I am just writing something like an automated CMake script, so I have no prior knowledge of any target names (or variables) defined in normal projects.
I know everything about the source files that I want to add.
My script will be include()ed to CMakeLists.txt in other normal projects.
Is there an elegant way to do this besides iterating through BUILDSYSTEM_TARGETS and target_sources() for each target?
I have seen solutions that add sources files to some specific target:
Can one add further source files to an executable once defined?
To elaborate on what I want to do, check this:
# my_script.cmake
some_magic_function_that_adds_sources_to_all_targets(
abs_path_to_file1.cpp
abs_path_to_file2.cpp
)
# CMakeLists.txt (of some other projects)
cmake_minimum_required(VERSION 3.7)
project(project_name)
include(abs_path_to_my_script.cmake) # can be anywhere in this file
add_executable(exe1
exe1.cpp)
add_executable(exe2
exe2.cpp)
add_executable(i_dont_know_exec_name
i_dont_know.cpp
how_many_files.cpp
are_here.cpp)
As a result, the CMakeLists.txt will be functionally equivalent to:
# CMakeLists.txt (of some other projects)
cmake_minimum_required(VERSION 3.7)
project(project_name)
add_executable(exe1
exe1.cpp
abs_path_to_file1.cpp
abs_path_to_file2.cpp
)
add_executable(exe2
exe2.cpp
abs_path_to_file1.cpp
abs_path_to_file2.cpp
)
add_executable(i_dont_know_exec_name
i_dont_know.cpp
how_many_files.cpp
are_here.cpp
abs_path_to_file1.cpp
abs_path_to_file2.cpp
)

cmake use one cmakelist.txt for a project with subdirectories

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)

Changing cmake directories

I'm writing a cmake file for a project which has the following structure
project/ (root)
libraries/ (contains (precompiled) libraries
src/
code/ (contains a set of fortran files)
My CMakeLists.txt file is currently in project/ and effectively is just
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (sc1 sc1.f90)
target_link_libraries(sc1 ${PROJ_LIBRARY})
This creates my binary in the same folder as the source code, when I actually want it in the level above (i.e. in the src folder - this structure will be changed so we have a bin folder eventually), but haven't worked out how to do it.
Some answers on SO say you have to have a CMakeLists.txt file in every folder - is this correct? Is it possible to set an environment variable or use a CMake variable (e.g. http://cmake.org/cmake/help/v2.8.8/cmake.html#command:set). It's also not very clear from some answers whether the solutions they have posted are C++ specific (as that is what language CMake most often seems to be used for).
Edit
I found out that I can change it to the behaviour I want by modifying it slightly:
cmake_minimum_required(VERSION 2.6)
enable_language(Fortran)
project(project1)
set(projsrc src/code)
set(libdir lib/)
find_library(PROJ_LIBRARY pr10 PATHS ${libdir})
add_executable (src/sc1 ${projsrc}/sc1.f90)
target_link_libraries(src/sc1 ${PROJ_LIBRARY})
However, this doesn't explain why my behaviour is different to how it should be, according to arrowdodger below. I'm also still trying to work out how to display the values of environment variables; I've tried the following with no luck:
message(${RUNTIME_OUTPUT_DIRECTORY})
message($ENV{RUNTIME_OUTPUT_DIRECTORY})
message(${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
message($ENV{CMAKE_RUNTIME_OUTPUT_DIRECTORY})
By default, binaries will appear in respective subdirectory of your build dir. By respective i mean the directory that contains CMakeLists.txt with add_executable() call.
For example, if you have following CMakeLists.txt
add_executable(tgt1 src1.f90)
add_executable(tgt2 subdir/src2.f90)
in the root folder, you will get both binaries in ${CMAKE_BINARY_DIR}. So if you wish tgt2 to be in ${CMAKE_BINARY_DIR}/subdir, you need to add CMakeLists.txt there and call add_executable(tgt2 src2.f90) from there.
You can change this behavior:
CMAKE_LIBRARY_OUTPUT_DIRECTORY, CMAKE_RUNTIME_OUTPUT_DIRECTORY and others.
You can also set respective target properties.

Cmake - How to build a project separated in different subfolders

I am trying to build a big project with CMake but I struggle on how to write the CMakeList.txt file.
My project is separated in different folders each containing a set of .hpp and .cpp files more or less related together as follows:
root
- memory
-- Memory.cpp
-- Memory.hpp
-- MemoryManager.hpp
-- MemoryManager.cpp
-- CMakeLists.txt
- tools
-- Array.cpp
-- Array.hpp
-- CMakeLists.txt
- main.cpp
- CMakeLists.txt
I would like to build all the files together to an executable. I don't want to build libraries in each subfolder as I don't see any good reason to do it.
I would like also to avoid putting a single big list of all source files in the ADD_EXECUTABLE command of the CMakeLists.txt file located at the root of the project.
Do you have any idea of how to set this up correctly ?
Cheers,
M.
You can use the GLOB function, such as:
file (GLOB _my_sources RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
memory/*.cpp tools/*.cpp main.cpp)
add_executable (myprogbin ${_my_sources})
set_target_properties (myprogbin PROPERTIES OUTPUT_NAME myprog)
See http://cmake.org/cmake/help/cmake-2-8-docs.html#command:file for reference