Reputation: 2430
I need help with writing good CMakeLists.txt
files for C++
projects.
This is the structure of my projects:
MainProj
| ProjLib/
| | include/
| | | proj_lib.h
| | src/
| | | proj_lib.cc
| | CMakeLists.txt
| ProjExec/
| | include/
| | | proj_exec.h
| | src/
| | | proj_exec.cc
| | CMakeLists.txt
| CMakeLists.txt
MainProj
CMakeLists.txt
:
cmake_minimum_required(VERSION 2.8)
project(MainProj CXX)
# enable C and C++ language
enable_language(C CXX)
# Add sub-directories
add_subdirectory(ProjLib)
add_subdirectory(ProjExec)
ProjLib
CMakeLists.txt
:
set (PROJLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set (PROJLIB_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set(PROJLIB_SRCS
${CMAKE_CURRENT_SOURCE_DIR}/src/proj_lib.cc
)
include_directories("${PROJLIB_SOURCE_DIR}")
include_directories("${PROJLIB_INCLUDE_DIR}")
add_library(ProjLib SHARED ${PROJLIB_SRCS} ${PROJLIB_INCLUDE_DIR})
target_include_directories (ProjLib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
ProjExec
CMakeLists.txt
:
set (PROJEXEC_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
set (PROJEXEC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
set(PROJEXEC_SRCS
${PROJEXEC_SOURCE_DIR}/proj_exec.cc
)
include_directories("${PROJEXEC_SOURCE_DIR}")
include_directories("${PROJEXEC_INCLUDE_DIR}")
add_executable(ProjExec ${PROJEXEC_SRCS})
target_link_libraries (ProjExec LINK_PUBLIC ProjLib)
proj_exec.cc
:
#include "proj_lib.h"
...
And it doesn't found proj_lib.h
in proj_exec.cc
file.
Do I need some additional entries in some cmake
?
Upvotes: 17
Views: 16914
Reputation: 11
When you are setting the properties of a target, a key point is to comprehend the command of target_include_directories
and its keywords of PRIVATE
, INTERFACE
, and PUBLIC
.
PRIVATE
indicates that the include directory is only needed by the target.
INTERFACE
indicates that the include directory is needed when other targets would like to link this target, and cmake
will deal with it automatically.
PUBLIC
means both this target and other targets which depend on it have to compass this directory into its search path.
All of this is determined by your code.
Upvotes: 1
Reputation: 795
Your cmake project template looks fine and self-contained. First, I'm going to assume GAITPARAMS_SRCS
was supposed to be PROJEXEC_SRCS
which is currently pointing at proj_exec.cc contains a main() method. (If you're going to manage a SRCS list, be careful not to add source files at the top of the list, add_executable expects the main function to be in the first entry)
Secondly, the problem is in your ProjLib/CMakeLists.txt
. Try replacing your target_include_directories
call with this:
target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})
This will propagate the include directory information to the ProjExec when the target_link_libraries
command is applied. If you don't wan't to do that, I guess you can access via #include <include/ProjLib.h>
but that's just confusing. My recommendation is to add another folder in the include folder (named exactly the same with the cmake folder) and add your headers in it. Like this:
MainProj
| ProjLib/
| | include/
| | | ProjLib/
| | | | proj_lib.h
| | src/
| | | proj_lib.cc
| | CMakeLists.txt
This lets you include your headers with a foldername (Not to mention preventing name collision.). Like this:
#include <ProjLib/proj_lib.h>
And to configure your CMakeLists.txt files to match the pattern.
Upvotes: 2
Reputation: 76795
You need to make use of the CMake targets and their properties:
MainProj/CMakeLists.txt:
cmake_minimum_required(VERSION 2.8)
project(MainProj)
# Add sub-directories
add_subdirectory(ProjLib)
add_subdirectory(ProjExec)
ProjLib/CMakeLists.txt
add_library(ProjLib SHARED src/proj_lib.cc)
target_include_directories(ProjLib PUBLIC ${CMAKE_CURRENT_LIST_DIR}/include)
ProjExec/CMakeLists.txt
add_executable(ProjExec src/proj_exec.cc)
target_include_directories(ProjExec PRIVATE ${CMAKE_CURRENT_LIST_DIR}/include)
target_link_libraries(ProjExec ProjLib)
target_link_libraries
makes sure that when building a target, its dependencies' PUBLIC and INTERFACE include directories will be used appropriately.
Upvotes: 32
Reputation: 20326
All of the following are valid, but the best option is explained in rubenvb's answer.
You have at least 3 options:
1) Add the following line in ProjExec/CMakeLists.txt:
target_include_directories (ProjExec PUBLIC ${CMAKE_SOURCE_DIR}/ProjLib/include)
2) You can extend the visibility of the variable PROJLIB_INCLUDE_DIR
, by adding the CACHE INTERNAL
keywords
set(PROJLIB_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include CACHE INTERNAL "")
and then use it in ProjExec/CMakeLists.txt:
target_include_directories (ProjExec PUBLIC ${PROJLIB_INCLUDE_DIR})
See How to set the global variable in a function for cmake?
Of course ProjLib must come first in the add_subdirectory
sequence in the main CMakeLists.txt file.
3) I couldn't test this one. If you in ProjLib's CMakeLists.txt use this line:
target_include_directories (ProjLib PUBLIC ${PROJLIB_INCLUDE_DIR})
Then in ProjExec's CMakeLists.txt you can extract the property INTERFACE_INCLUDE_DIRECTORIES
, and use it:
get_target_property(ProjLib PROJLIB_INCLUDE_DIR INTERFACE_INCLUDE_DIRECTORIES) #Do not use anymore CACHE INTERNAL (Point 2)
target_include_directories (ProjExec PUBLIC ${PROJLIB_INCLUDE_DIR}) #or PRIVATE
These 2 lines can be compacted in one, using cmake-generator-expressions (untested):
target_include_directories (ProjExec PUBLIC $<TARGET_PROPERTY:ProjLib,INTERFACE_INCLUDE_DIRECTORIES>) #or PRIVATE
See also target_include_directories and get_target_property.
include_directories
or target_include_directories
, not both.include_directories("${PROJLIB_SOURCE_DIR}")
and include_directories("${PROJEXEC_SOURCE_DIR}")
Upvotes: 0