Reputation: 2337
I have the following directory structure for my app. The libraries in the external
directory all use fetchcontent
command.
myapp
│
│ CMakeLists.txt
│
├───data
│ data.csv
│
├───external
│ ├───csv-parser
│ │ CMakeLists.txt
│ │
│ ├───eigen
│ │ CMakeLists.txt
│ │
│ └───fmt
│ CMakeLists.txt
│
├───include
│ myapp.h
│
├───out
│ └───build
│
├───src
│ main.cpp
│
└───tests
The CMakeLists.txt
in the csv-parser
folder is as follows.
cmake_minimum_required(VERSION 3.24)
project(libcsvparser VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
include(CMakePrintHelpers)
FetchContent_Declare(csv_parser
GIT_REPOSITORY https://github.com/ben-strasser/fast-cpp-csv-parser.git)
FetchContent_MakeAvailable(csv_parser)
cmake_print_variables(csv_parser_SOURCE_DIR csv_parser_BINARY_DIR)
The CMakeLists.txt
in the fmt
folder is as follows.
cmake_minimum_required(VERSION 3.24)
project(libfmt VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
include(CMakePrintHelpers)
FetchContent_Declare(fmt GIT_REPOSITORY https://github.com/fmtlib/fmt)
FetchContent_MakeAvailable(fmt)
cmake_print_variables(fmt_SOURCE_DIR fmt_BINARY_DIR)
The CMakeLists.txt
in the eigen
folder is as follows.
cmake_minimum_required(VERSION 3.24)
project(libeigen VERSION 1.0.0)
set(CMAKE_CXX_STANDARD 20)
include(FetchContent)
include(CMakePrintHelpers)
FetchContent_Declare(eigen
GIT_REPOSITORY https://gitlab.com/libeigen/eigen.git)
FetchContent_MakeAvailable(eigen)
cmake_print_variables(eigen_SOURCE_DIR eigen_BINARY_DIR)
For all the external libraries, I get the correct ???_SOURCE_DIR
and ???_BINARY_DIR
printed during the build.
The main CMakeLists.txt
is as follows.
cmake_minimum_required(VERSION 3.24)
project(myapp VERSION 1.0.0)
include(FetchContent)
include(CMakePrintHelpers)
cmake_print_variables(CMAKE_CXX_FLAGS)
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(external/csv-parser)
add_subdirectory(external/eigen)
add_subdirectory(external/fmt)
cmake_print_variables(csv_parser_SOURCE_DIR)
cmake_print_variables(eigen_SOURCE_DIR)
cmake_print_variables(fmt_SOURCE_DIR)
add_executable(myapp)
target_sources(myapp PRIVATE src/main.cpp)
target_include_directories(myapp PUBLIC include)
target_include_directories(myapp PUBLIC csv_parser_SOURCE_DIR)
target_include_directories(myapp PUBLIC eigen_SOURCE_DIR)
target_include_directories(myapp PUBLIC fmt_SOURCE_DIR)
I am having trouble accessing the external libraries in the main CMakeLists.txt
and during its build the following commands will print empty as if the add_subdirectory
did not work correctly.:
csv_parser_SOURCE_DIR=""
eigen_SOURCE_DIR=""
fmt_SOURCE_DIR=""
Because of this my Visual Studio does not recognize where the following include files are and I can't build the myapp
target.
#include "Eigen/Dense"
#include "fmt/core.h"
#include <csv.h>
Upvotes: 0
Views: 510
Reputation: 66118
If a subproject follows the target-oriented style ("modern CMake"), then one rarely need to know its source or binary directory: for consume the subproject in the CMakeLists.txt
you could just link with the target(s) created by the subproject.
E.g. in case of Eigen you could write
target_link_libraries(myapp PUBLIC Eigen3::Eigen)
(How to add Eigen library to a cmake c++ project via FetchContent).
If a subproject doesn't follow the target-oriented style, and instead of target_include_directories
uses include_directories
, then you could "fix" that problem by adding missing properties in the same CMakeLists.txt
where FetchContent for that project is called. So the rest of your code could use target_link_libraries
as in the previous case.
E.g. csv-parser contains a single header and doesn't provide CMakeLists.txt
. You may create an IMPORTED target which represents a header-only library:
# in csv-parser/CMakeLists.txt
add_library(csv_parser INTERFACE)
target_include_directories(csv_parser INTERFACE ${csv_parser_SOURCE_DIR})
and link with that target in outer code:
# in top-level CMakeLists.txt
target_link_libraries(app PUBLIC csv_parser)
Upvotes: 1
Reputation: 41
The most simplest way is to set the variable, {project}_SROUCE_DIR, to PARENT_SCOPE.
For example, you can add below code in your CMakeLists.txt of the fmt directory.
set(fmt_SOURCE_DIR ${fmt_SOURCE_DIR} PARENT_SCOPE)
The reason why main CMakeLists could not access that variable is the variable scope related problem.
{project}_SOURCE_DIR variable is valid while configuring {project} subdirectory.
Upvotes: 1