we have a tree shaped directory structure in our project like:
project_dir/public_include
public_include has dir1, dir2 and dir3
now, I want to include directories based on an option
if(option A)
include_directories(project_dir/public_include/dir1)
else
include_directories(project_dir/public_include/dir3
project_dir/public_include/dir2)
endif()
The header files are independent.
It is not working!!! Am I missing something???
How about options ? Try using option(option_A "include dir 1" ON) at the top of your CMakeLists.txt. It will set option_A=ON by default and your if statement should work.
Related
As in Google C++ Style Guide is mentioned all of a project's header files should be listed as descendants of the project's source directory without use of UNIX directory shortcuts . (the current directory) or .. (the parent directory). How can I do that in my project that is shortly described below.
My project directory hierarchy is like this:
GraphicsEngine
header_files.h
source_files.cc
CMakeLists.txt (1)
Light
CMakeLists.txt (2)
header_files.h
source_files.cc
Camera
CMakeLists.txt (3)
header_files.h
source_files.cc
Core
CMakeLists.txt (4)
header_files.h
source_files.cc
These are contents of CMakeLists.txt files:
CMakeLists.txt (1)
add_library(GraphicsEngineLib source_files.cc)
target_link_libraries(GraphicsEngineLib LightLib CameraLib CoreLib)
add_subdirectory(Light)
add_subdirectory(Camera)
add_subdirectory(Core)
CMakeLists.txt (2)
add_library(LightLib source_files.cc)
CMakeLists.txt (3)
add_library(CameraLib source_files.cc)
CMakeLists.txt (4)
add_library(CoreLib source_files.cc)
Now when for example I want to include header files from Camera folder in to files in Core folder, I have to use ../Camera/header_file.h but I want to use GraphicsEngine/Camera/header_file.h. How can I do this?
What I have done in the past is to set this in the top level CMakeLists.txt (which should be in your GraphicsEngine directory):
SET(PROJECT_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/..")
INCLUDE_DIRECTORIES(
${PROJECT_ROOT}
)
where according to this, CMAKE_CURRENT_SOURCE_DIR is
this is the directory where the currently processed CMakeLists.txt is located in
Note that by defining Project_Root in this way, your GraphicsEngine project can also #include headers from sister projects to GraphicsEngine.
Hope this helps.
I have a CMake project that looks like this:
project/
CMakeLists.txt
subprojectA/
CMakeLists.txt
include/
headerA.hpp
src/
libraryA.cpp
subprojectB/
CMakeLists.txt
src/
mainB.cpp
The "library" subproject, A, is compiled as a static library, becoming libsubprojectA.a. The "main" project, B, is compiled as a binary and depends on the library. mainB.cpp includes a reference to headerA.hpp.
Here is subprojectA/CMakeLists.txt:
project(SubProjectA)
include_directories(include)
add_library(subprojectA STATIC src/libraryA.cpp)
set(${PROJECT_NAME}_INCLUDE_DIRS
${PROJECT_SOURCE_DIR}/include
CACHE INTERNAL "${PROJECT_NAME}: Include Directories" FORCE)
And here is subprojectB/CMakeLists.txt:
project(SubProjectB)
include_directories(${SubProjectA_INCLUDE_DIRS})
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
The main Project CMakeLists.txt looks like:
project(Project)
add_subdirectory(subprojectB)
add_subdirectory(subprojectA)
Note that subprojectB, the main project, is listed before subprojectA.
Here's the problem. When I first run "cmake" on this project, ${SubProjectA_INCLUDE_DIRS} is not set within SubProjectB.
What I think is happening is that the CMakeLists for SubProjectB loads first, when ${SubProjectA_INCLUDE_DIRS} has not yet been set. It sets its own include path to an empty string as a result. However, even though libsubprojectA.a gets built successfully before mainBinary, the include path was already set empty beforehand. As a result, I get this error when trying to make mainBinary:
subprojectB/src/mainB.cpp:1:23: fatal error: headerA.hpp: No such file or directory
#include "headerA.hpp"
^
It's a workaround to put subprojectA before subprojectB in the main Project CMakeLists in the declarative world of CMake. What I really want is to know the proper way to indicate to CMake that the include_directories(${SubProjectA_INCLUDE_DIRS}) line depends on the definitions that exist inside SubProjectA's CMakeLists. Is there a better way to do this?
If you want to express that include directory subprojectA/include is an interface of the library subprojectA, attach this property to the target with target_include_directories command:
subprojectA/CMakeLists.txt:
project(SubProjectA)
add_library(subprojectA STATIC src/libraryA.cpp)
# PUBLIC adds both:
# 1) include directories for compile library and
# 2) include directories for library's interface
target_include_directories(subprojectA PUBLIC include)
So any executable(or other library) which linked with subprojectA will have this include directory automatically:
subprojectB/CMakeLists.txt:
project(SubProjectB)
add_executable(mainBinary src/mainB.cpp)
target_link_libraries(mainBinary subprojectA)
Of course, for use last command properly you need to process directory with library before one with executable:
CMakeLists.txt:
project(Project)
add_subdirectory(subprojectA)
add_subdirectory(subprojectB)
Till date I still do not really understand what the 'best practice' is for doing this for a CMake project with many subdirectories.
Say I have a project hierarchy as such and each subdirectory has source files in it...
--CMake Project Source dir
|-- SubD1
|-- SubSubD1
|-- SubD2
What I would usually do is to do add_subdirectory(SubD1) and respectively for D2 in the CMakeLists.txt of the root directory and recursively for the subdirectory in the CMakeLists.txt of the SubD1 directory, while declaring variables in each subdirectory and making them visible in the root directory with PARENT_SCOPE.
That means if a file Source2.cpp exists in `SubSubD1', I'd simply do
set(SUBSUBD1_SOURCES Source2.cpp PARENT_SCOPE)
and expect to be able to use SUBSUBD1_SOURCE in my SubD1 directory.
Subsequently, say Source.cpp exists in SubD1, I would do
set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} Source.cpp PARENT_SCOPE)
so that all sources would be visible in root dir.
The problem is of course that the file paths aren't kept when the variables arrive at the root directory. What I'm currently doing is for all source files that I set, I include a ${CMAKE_CURRENT_LIST_DIR}, making it
set(SUBSUBD1_SOURCES ${CMAKE_CURRENT_LIST_DIR}/Source2.cpp PARENT_SCOPE)
and
set(SUBD1_SOURCES ${SUBSUBD1_SOURCES} ${CMAKE_CURRENT_LIST_DIR}/Source.cpp PARENT_SCOPE)
In this case, I could then say, do add_executable(myProg SUBSUBD1_SOURCES) in the root directory of my CMake project.
Are there any better ways of doing this then having to always include a CMake variable in front of all source files?
There is a fourth way if you're using newer versions of CMake.
Take a look at target_sources() command of CMake.
It seems like you are declaring your target in your CMakeLists.txt
add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
add_subdirectory(subd1)
add_subdirectory(subd2)
Instead of propagating your Source files up to the root you can depend on the target you have defined in the root CMakeLists.txt. That means subd1/CMakeLists.txt may look like:
target_sources(my_target PRIVATE "subd1/Source.cpp" "subd1/Source2.cpp")
[EDIT]
As stated in the comments you must give the relative path of the source-files to target_sources(). I use target_sources() because I do not want the explicit source file listing to pollute the targets CMakeLists.txt. Another use case is that target_sources() can be invoked with the PUBLIC or INTERFACE keyword to propagate source files to depending targets. Well I never used target_sources() that way.
[/EDIT]
If you're using IDEs like Visual Studio that support folders you make want to also declare a source_group() in the CMakeLists.txt that contains your target. So the root CMakeLists.txt may look like:
add_executable(my_target "subd1/CMakeLists.txt" "subd2/CMakeLists.txt")
add_subdirectory(subd1)
add_subdirectory(subd2)
...
source_group(subd1 REGULAR_EXPRESSION "subd1/*")
source_group(subd2 REGULAR_EXPRESSION "subd2/*")
I'm using this approach because it leads to much cleaner CMakeLists.txt files, its lesser work and I think the introduction of not needed variables only raises the complexity of your CMakeLists.txt files.
CMakeLists.txt as target sources
I currently use the CMakeLists.txt of the sub folders as source files of the target because otherwise CMake will complain that the add_executable command has no source files given.
There are 3 ways I have used before. I normally prefer the 1st way, but have already used all 3 depending on the use case:
1. You directly name the sources in your root CMakeLists.txt file
set(
SUBD1_SOURCES
"SubD1/SubSubD1/Source2.cpp"
"SubD1/Source.cpp"
)
set(
SUBD2_SOURCES
"SubD2/Source3.cpp"
)
add_executable(myProg ${SUBD1_SOURCES} ${SUBD2_SOURCES})
2. You use OBJECT intermediate libraries to collect/group your sources
SubD1/SubSubD1/CMakeLists.txt:
add_library(SubSubD1Objs OBJECT Source2.cpp)
SubD1/CMakeLists.txt:
add_subdirectory(SubSubD1)
add_library(SubD1Objs OBJECT Source.cpp)
CMakeLists.txt:
add_executable(myProg $<TARGET_OBJECTS:SubSubD1Objs> $<TARGET_OBJECTS:SubD1Objs>)
3. You write your own function() to collect the data (and do the prefixing)
CMakeLists.txt:
function(my_collect_sources)
foreach(_source IN ITEMS ${ARGN})
if (IS_ABSOLUTE "${_source}")
set(source_abs "${_source}")
else()
get_filename_component(_source_abs "${_source}" ABSOLUTE)
endif()
set_property(GLOBAL APPEND PROPERTY GlobalSourceList "${_source_abs}")
endforeach()
endfunction(my_collect_sources)
add_subdirectory(SubD1)
#add_subdirectory(SubD2)
get_property(MY_SOURCES GLOBAL PROPERTY GlobalSourceList)
add_executable(myProg ${MY_SOURCES})
SubD1/CMakeLists.txt:
add_subdirectory(SubSubD1)
my_collect_sources(Source.cpp)
SubD1/SubSubD1/CMakeLists.txt:
my_collect_sources(Source2.cpp)
In your case there's no need to use add_subdirectory since you have only one target which is created in the root CMakeLists.txt. You can simply write this:
add_executable(myProg
SubD1/Source.cpp
SubD1/SubSubD1/Source2.cpp)
Use add_subdirectory for subdirectories creating their own targets so there's no information to pass upwards.
I have a folder net like:
main
headers
cls1.hpp cls2.hpp ...
sources
cls1.cpp cls2.cpp ...
resources
r1.hpp r2.hpp ...
I have tried more cmake methods to link the files, like
set(SRC ${SRC})
in parent dir and
set(SRC ${SRC} ${CMAKE_CURRENT_SOURCE_DIR}/cls1.cpp PARENT_SCOPE)
in subdir
OR
file(GLOB_RECURSE SRC_FILES ${PROJECT_SOURCE_DIR}/*.cpp)
file(GLOB_RECURSE HDR_FILES ${PROJECT_SOURCE_DIR}/*.hpp)
to get the .cpp and .hpp files, but when I do
#include "resources/r1.hpp"
I get error like "resources/r1.hpp" No such a file or directory
Can anyone help me pleas? How can I do linking between files in folders in my case?
To solve this specific problem, in your main CMakeLists.txt add this line before adding subfolders:
include_directories(".")
This will allow the compiler to see the file located in resources/r1.hpp starting from the root path.
However, I suggest you take a look to some CMake projects examples, because it doesn't seem you are doing things in the standard way (e.g. usually a good way is to add a sub directory that creates its own library, that then you link to your main executable)
I am trying to set up a cmake system for a pretty big project and I got stuck at the stage of passing a unique define to the C++ compiler for all the files in each of the sub-directories in the project. What I did was:
On the top level directory in CMakeLists.txt:
set_property(
DIRECTORY
APPEND PROPERTY COMPILE_DEFINITIONS LOG_FAPP_PKG=CORE
)
and then
add_subdirectory(Modules)
and in the Modules subdirectory in CMakeListst.txt:
add_subdirectory(ModuleConfigurationProvider)
set_property(
DIRECTORY ModuleConfigurationProvider
APPEND PROPERTY COMPILE_DEFINITIONS LOG_FAPP_MODULE=CONFPROVIDER
)
but what I get in the Makefile is just the first level (ie: the LOG_FAPP_PKG) being defined and the second level (the LOG_FAPP_MODULE) is totally ignored.
I also have tried to put in CMakeLists.txt in the ModuleConfigurationProvider directory the
set_property(
DIRECTORY
APPEND PROPERTY COMPILE_DEFINITIONS LOG_FAPP_MODULE=CONFIGPROVIDER
)
or even the
add_definitions(-DLOG_FAPP_MODULE=CONFIGPROVIDER)
but still not working. I had printed out the defines for the current directory and they show up correctly in the directory but it seems they don't propagate to the generated makefiles.
Any idea what I'm doing wrongly?