How can I include headers from find_package() function in CMake? - c++

I have a CMake project in C++ and I have been struggling how to setup the CMakeLists.txt files properly. In the external folder there are some dependencies located, which are added to the root CMakelists.txt by the add_subdirectory command. It is important to mention that Project_B needs Project_A. Here is the simplified version of the folder structure:
$ tree
.
├── external
│ ├── Project_A
| ├──include
| ├── project_A.h
│ ├── projectA_0.cpp
│ └── CMakeLists.txt
|
| ├── Project_B
| ├──include
| ├── project_B.h
│ ├── projectB_0.cpp
│ └── CMakeLists.txt
|
├── root_0.cpp
├── root_1.cpp
└── CMakeLists.txt
Here is the simplified root CMakeLists.txt
# root CMakeLists.txt
cmake_minimum_required(VERSION 3.19)
project(foo)
add_subdirectory(external/Project_A)
add_subdirectory(external/Project_B)
add_executable(${PROJECT_NAME} root_0.cpp
root_1.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC
external/Project_A/include
external/Project_B/include)
target_link_libraries(${PROJECT_NAME} PUBLIC
project_a
project_b)
Here is the CMakeLists.txt of Project_A, which is also a dependency for Project_B. I decided to create a config.cmake file for this project and import it by Project_B.
# Project_A CMakeLists.txt
cmake_minimum_required(VERSION 3.19)
project(project_a)
target_include_directories(${PROJECT_NAME} PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
add_library(${PROJECT_NAME} STATIC projectA_0.cpp)
export(TARGETS ${PROJECT_NAME}
NAMESPACE project_a::
FILE ${CMAKE_SOURCE_DIR}/project_a_Config.cmake )
and here is the CMakeLists.txt of Project_B.The project_a_Config.cmake is loaded with the help of find_package() function. The path of the include dir from A is written in the project_a_Config.cmake. However, I can not make those headers included properly. Should I use a *.cmake.in file?
# Project_B CMakeLists.txt
cmake_minimum_required(VERSION 3.19)
project(project_b)
add_library(${PROJECT_NAME} STATIC projectB_0.cpp)
find_package(project_a CONFIG REQUIRED HINTS ../)
target_include_directories(${PROJECT_NAME} PUBLIC
include
project_a::project_a )
target_link_libraries(${PROJECT_NAME} PUBLIC
project_a )
If there are any further problems with the structure or the used functions, just let me know! Thank you!

Related

CMake header files can't be found (fatal error: file not found)

I'm working on a CMake project but Im getting this error and I don't understand why. Im using VS Code on MacOS and I'm using Clang as the compiler.
Here is the structure of my folder project:
tree
.
├─ app
│ ├── CMakeLists.txt
│ └── src
│ └── main.cpp
├─ CMakeLists.txt
├─ build
└─ engine
├── CMakeLists.txt
├── external
├── include
│ └── project_engine
│ └── engine.h
└── src
└── engine.cpp
The root CMakeLists.txt is
cmake_minimum_required(VERSION 3.5)
project(vulkanEngine_developement_env VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
add_subdirectory(app)
add_subdirectory(engine)
The CMakeLists.txt in the app folder:
cmake_minimum_required(VERSION 3.5)
project(vulkanEngine VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
add_executable(${PROJECT_NAME} src/main.cpp)
target_link_libraries(${PROJECT_NAME} vulkanEngine_engine)
target_include_directories(${PROJECT_NAME} PRIVATE vulkanEngine_engine)
and the one in engine is:
cmake_minimum_required(VERSION 3.5)
project(vulkanEngine_engine VERSION 0.0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 20)
add_library(${PROJECT_NAME} src/engine.cpp)
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
PRIVATE
)
target_link_libraries(${PROJECT_NAME}
PUBLIC
PRIVATE
)
Whenever I try to include the header file in both cpp files I get the error "file not found", I tried using both
#include <project_engine/engine.h>
and
#include "project_engine/engine.h"
I also tried linking the path to the header in the vs code include path setting but it didn't work, I added include_directories to the engine CMake file but that didn't work either.

Importing header files and linking .a file in CMake

Trying to put Skia in my CMake project. How do I tell CMake to link my executable against libskia.a and use the header files inside ext/skia so that I can include them like so?
#include <skia/subdirectory/headerfile.h>
My project structure is currently the following:
.
├── CMakeLists.txt
├── CMakeLists.txt.user
├── ext
│   ├── libskia.a
│   └── skia
│   └── <subdirectories>
│      └── <header files>.h
└── src
└── main.cpp
and my CMakeLists.txt:
cmake_minimum_required(VERSION 3.5)
project(project LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
add_executable(project src/main.cpp)
In your primary CMakeLists.txt file you would simply add the following:
target_link_libraries(project skia)
If CMake cannot find the library, you can either do:
target_link_libraries(project /full/path/to/libskia.a)
or:
link_directories(/path/to/libraries)
target_link_libraries(project skia)

Creating and using a static library with CMake

I am trying to first create a static library and then link it to an executable using CMake. My project file structure looks like this:
├── CMakeLists.txt
├── build
├── lib
│   ├── CMakeLists.txt
│   ├── build
│   ├── include
│   │   └── Point.hpp
│   └── src
│   └── Point.cpp
└── mainApp.cpp
I first build the library like so.
cmake_minimum_required(VERSION 2.8.9)
project(CAST3)
set(CMAKE_BUILD_TYPE Release)
include_directories(include)
file(GLOB SOURCES "src/*.cpp")
add_library(CAST3 STATIC ${SOURCES})
However, when i try to link the library to my executable I get an error.
This is my executable
#include"Point.hpp"
int main(int argc, char *argv[]){
Point p = Point(1,2,3);
return 0;
}
This is my CMake file to link the library to the executable.
cmake_minimum_required(VERSION 2.8.9)
project (CAST3)
set ( PROJECT_LINK_LIBS libCAST3.a )
link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest ${PROJECT_LINK_LIBS} )
When I run that I get the this error
/mainApp.cpp:1:9: fatal error: 'Point.hpp' file not found
#include"Point.hpp"
^~~~~~~~~~~
1 error generated.
make[2]: *** [CMakeFiles/libtest.dir/mainApp.cpp.o] Error 1
make[1]: *** [CMakeFiles/libtest.dir/all] Error 2
make: *** [all] Error 2
What am I missing?
What am I missing?
You are missing target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) inside lib/CMakeLists.txt.
You are missing add_subdirectory(lib) from root CMakeLists.txt.
The set ( PROJECT_LINK_LIBS libCAST3.a ) and target_link_libraries(libtest ${PROJECT_LINK_LIBS} ) and link_directories( ${CMAKE_CURRENT_SOURCE_DIR}/lib/build) could be removed. Then you are missing just target_link_libraries(libtest PUBLIC CAST3). Cmake will automatically find the proper .a file and propagate include paths with target_link_libraries.
So your lib/CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
include_directories(include)
file(GLOB sources src/*.cpp) # upper case variable names reserved for exported variables by convention
add_library(CAST3 ${sources}) # STATIC by default
target_include_directories(CAST3 PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
And root CMakeLists.txt could look like this:
cmake_minimum_required(VERSION 3.0) # I would advise to update
project(CAST3)
add_subdirectory(lib)
add_executable(libtest mainApp.cpp)
target_link_libraries(libtest CAST3)

verifying my understanding of a CMakeLists.txt file

I successfully played trial-and-error with a CMakeLists.txt file, and now everything builds. However, I want to make sure my understanding is correct about how it's working.
I have a project with the following structure:
./
├── bin
├── CMakeLists.txt
├── include
│   └── sql-writer
│   ├── credentials.h
│   ├── database.h
│   ├── datetime.h
│   ├── market_bar.h
│   └── writer.h
├── README.md
├── src
│   ├── CMakeLists.txt
│   ├── database.cpp
│   ├── main.cpp
│   └── writer.cpp
└── test
├── CMakeLists.txt
├── test-main.cpp
├── test_sym_table_pairs
└── writer_tests.cpp
This builds an executable, a static library, and a test executable. The problem was src/CMakeLists.txt:
set(HEADER_DIR ${sql-writer_SOURCE_DIR}/include/sql-writer)
add_executable(sql-writer-demo main.cpp ${HEADER_DIR})
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) #!
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
file(GLOB HEADERS ${HEADER_DIR}/*.h)
add_library(sql-writer-lib ${HEADERS} ${SOURCES})
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
the first line's set command just defines HEADER_DIR. This is easy.
target_include_directories(sql-writer-demo PUBLIC ${HEADER_DIR}) must be included after the first add_execuable because otherwise header files will need to be included with relative paths. Is that right? Why does it come after? I've heard cmake treats include directories as "separate" from "sources" (cmake sources not .cpp files). What does that mean?
target_link_libraries(sql-writer-demo sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_executable(sql-writer-demo main.cpp ${HEADER_DIR}) as well, and it tells how to link to other libraries.
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp) is not recomended before only because the directory/file structure could change, and then this wouldn't work anymore
target_link_libraries(sql-writer-lib mysqlcppconn ${Boost_LIBRARIES}) needs to come after add_library(sql-writer-lib ${HEADERS} ${SOURCES}) because the compulation of my library sql-writer-lib needs to use other libs, and this is where we tell cmake to look out for those.
You typically don't include headers into add_executable and add_library, but only implementation files:
add_executable(sql-writer-demo main.cpp)
add_library(sql-writer-lib ${SOURCES})
add_executable and add_library create a target, target_include_directories specifies include directories for this target. The documentation is pretty clear:
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an IMPORTED target.
If you use target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR}) with PUBLIC specifier, you don't need to use target_include_directories to specify include directories for targets that link against that library, because the dependency will be propagated automatically. The same applies to target_link_libraries.
So, src/CMakeLists.txt
file(GLOB SOURCES ${sql-writer_SOURCE_DIR}/src/*.cpp)
add_library(sql-writer-lib ${SOURCES})
target_link_libraries(sql-writer-lib PUBLIC mysqlcppconn ${Boost_LIBRARIES})
target_include_directories(sql-writer-lib PUBLIC ${HEADER_DIR})
add_executable(sql-writer-demo main.cpp)
target_link_libraries(sql-writer-demo sql-writer-lib)
should work. Whether you want to use PUBLIC on mysqlcppconn ${Boost_LIBRARIES} depends on the structure of your project. I specified it as an example only.

CMake + Qt + GTest files linking

I have a simple CMake + Qt + GTest project:
.
├── CMakeLists.txt
├── src
│   ├── CMakeLists.txt
│   ├── main.cpp
│   └── utils
│   ├── calculator.cpp
│   └── calculator.h
└── tests
├── calculator_test.cpp
└── CMakeLists.txt
Root CMakeFiles.txt
cmake_minimum_required(VERSION 3.5)
project(random_project)
# Place binaries and libraries according to GNU standards.
include(GNUInstallDirs)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_LIBDIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR})
# Add source folder.
add_subdirectory(src)
# Add GTest.
include(cmake/googletest.cmake)
fetch_googletest(
${PROJECT_SOURCE_DIR}/cmake
${PROJECT_BINARY_DIR}/googletest
)
enable_testing()
# Add tests folder.
add_subdirectory(tests)
And I want to reach calculator.h in calculator_test.cpp which uses GTest:
#include <gtest/gtest.h>
#include "utils/calculator.h" // <- Want to reach this in that path format.
TEST(example, add)
{
EXPECT_EQ(8, Calculator::sum(3, 5));
}
I have tried to link but then test is not found and the path is releative:
tests/CMakeFiles.txt
# Find the Qt libraries.
find_package(Qt5Widgets REQUIRED)
# Qt5 libraries.
set(QT5_LIBRARIES
Qt5::Widgets)
# Source files.
set(SOURCE_FILES
calculator_test.cpp
../src/utils/calculator.cpp
../src/utils/calculator.h
../src/main.cpp) # If I link like this, test is not found.
# Tell CMake to create the executable.
add_executable(unit_tests ${SOURCE_FILES})
# Use the Widgets module from Qt5.
target_link_libraries(unit_tests ${QT5_LIBRARIES} gtest_main)
# Add tests.
add_test(
NAME unit_tests
COMMAND ${CMAKE_BINARY_DIR}/${CMAKE_INSTALL_BINDIR}/unit_tests
)
How to link calculator.h in calculator_test.cpp test with CMakeLists.txt?
My Qt project with CMake project file cannot resolve the path to
"someHeader.h". What can I do to fix it?
You can specify the include path:
include_directories("${PROJECT_SOURCE_DIR}/relativePathToHeader")
and likely the path needed:
include_directories("${PROJECT_SOURCE_DIR}/src/utils") or maybe
include_directories("${PROJECT_SOURCE_DIR}/utils") depending on where the source directory actually is.
You need to re-run CMake, of course.