I have a project
├── CMakeLists.txt
│ ├── log
│ │ ├── CMakeLists.txt
│ │ ├── include
│ │ │ ├── log.h
│ │ └── src
│ │ ├── log.cpp
│ └── main.cpp
In log.cpp I am usng #include "../include/log.h" and in main.cpp I amd using #include "include/log.h"
I want to use #include "log.h"
I read that target_include_directories can help me.
How can I apply it to my CMakeLists.txt
cmake_minimum_required(VERSION 3.18)
project(Logger)
# specify the C++ standard
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED True)
#include_directories(log/include/) -- I used this, but I want to use target_include_directories
add_library(log_lib log/src/log.cpp)
add_executable(demo main.cpp)
target_link_libraries(demo log_lib)
define the target and then use the name as the first argument for target_include_directories
add_library(log_lib log/src/log.cpp)
target_include_directories(log_lib PUBLIC log/include)
worry about INTERFACE vs PUBLIC vs PRIVATE after you've got it all working and you want to understand it better. (This option transitively affects targets that depend on your library).
The line below helped
target_include_directories(log_lib PUBLIC log/include)
Related
my goal is to create libraries like client and generator and use them in src/main.cpp, but sometimes these libraries depend each other.
In this case: client/User.hpp uses generator/IdGenerator.hpp
Project
│
├── CMakeLists.txt
├── libs
│ ├── CMakeLists.txt
│ ├── client
│ │ ├── CMakeLists.txt
│ │ ├── User.cpp
│ │ └── User.hpp
│ └── generator
│ ├── CMakeLists.txt
│ ├── IdGenerator.cpp
│ ├── IdGenerator.hpp
│ └── Types.hpp
└── src
└── main.cpp
Project/CMakeLists.txt:
cmake_minimum_required (VERSION 3.8)
project(game-project VERSION 0.1.0)
set (CMAKE_CXX_STANDARD 20)
set (CMAKE_CXX_FLAGS "-Wall -Wextra -O0 -std=c++20")
add_executable (game src/main.cpp)
add_subdirectory(libs)
target_link_libraries(game libclient libgenerator)
libs/CMakeLists.txt:
add_subdirectory(generator)
add_subdirectory(client)
libs/client/CMakeLists.txt:
add_library(libclient STATIC
User.cpp
User.hpp
)
include_directories(generator/)
target_link_libraries(libclient libgenerator)
libs/generator/CMakeLists.txt:
add_library(libgenerator STATIC
IdGenerator.cpp
IdGenerator.hpp
Types.hpp
)
C++ files:
main.cpp:
#include <client/User.hpp>
int main(int argc, const char* argv[])
{
User user;
return 0;
}
client/User.hpp:
#pragma once
#include <generator/IdGenerator.hpp>
class User
{
Identifier id = IdGenerator::generateId();
};
When I run make after cmake, I get this error:
In file included from Project/libs/client/User.cpp:1:
Project/libs/client/User.hpp:3:10: fatal error: generator/IdGenerator.hpp: No such file or directory
3 | #include <generator/IdGenerator.hpp>
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Sorry for the verbose summary, I was able to shorten the example this much. What do you think the problem is?
This question might seem like a duplicate of CMake libraries that depend on each other but as you can see I'm already applying the
include_directories(generator/).
I misunderstood what the problem was initially, but now I think this might help.
Try adding to the CMakeLists.txt of your client instead of
include_directories(generator/)
this command
target_include_directories(libclient PUBLIC <Path to your generator file>)
Maybe you need to experiment a little to get the path correct as you might need to either specify it from the root directory or the current one (where this CMakeLists.txt resides), but it might solve your problem.
This is an example of a tuigraphics library I'm working on, what would be the best approach into creating it's public interface accessible via a single header file?
├── CMakeLists.txt
├── include
│ ├── Cell.hpp
│ ├── Grid.hpp
│ ├── math.hpp
│ ├── Node.hpp
│ ├── Renderer.hpp
│ ├── shape
│ │ ├── CircleShape.hpp
│ │ ├── RectangleShape.hpp
│ │ └── Shape.hpp
│ └── types.hpp
└── src
└── Node.cpp
I would like to access the library like so:
#include <tuigraphics.hpp>
int main(void)
{
Node node(CircleShape(10), Vector2(10, 10));
return EXIT_SUCCESS;
}
I have thought about putting a header file tuigraphics.hpp including all header files, but I'm not quite sure about it. I have never built a static library, and i would like some advice on how to proceed. Also here the CMake configuration:
project(libex)
cmake_minimum_required(VERSION 3.16)
add_library(tuigraphics STATIC)
target_include_directories(tuigraphics PRIVATE ./include)
target_sources(tuigraphics PRIVATE src/Node.cpp
include/Node.hpp
include/types.hpp
include/math.hpp
include/Cell.hpp
include/shape/CircleShape.hpp
include/shape/Shape.hpp
include/shape/RectangleShape.hpp
include/Renderer.hpp)
target_include_directories(tuigraphics PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
I feel I don't understand how to set up an "include" directory in a C++ project for header files, and also how to include these headers in the .cpp files.
I'm talking about a project in the context of a ROS package, but I don't think ROS would make the structure of the project any different.
To be specific, this is the structure of the directory I'm talking about:
yuqiong#yuqiong-G7-7588:/media/yuqiong/DATA/sdd_vio$ tree
.
├── CMakeLists.txt
├── CMakeModules
│ └── FindEigen.cmake
├── config
│ ├── camchain-imucam-euroc.yaml
│ ├── camchain-imucam-fla1_11052016.yaml
│ ├── camchain-imucam-snapdragon.yaml
│ ├── custom_rosconsole.conf
│ ├── disp_vo_param.yaml
│ ├── ukf_params.yaml
│ └── vo_param.yaml
├── include
│ └── sdd_vio
│ ├── grid.h
│ ├── pinhole_camera_stereo.h
│ ├── sdd_vio_nodelet.h
│ ├── utils
│ │ ├── calib_utils.h
│ │ ├── math_utils.h
│ │ ├── ros_params_helper.h
│ │ └── timer.hpp
│ ├── visualization.h
│ └── vo_stereo.h
├── launch
│ ├── bag_reader.launch
│ ├── disp_nodelet.launch
│ ├── image_proc_rectify.launch
│ ├── imu.launch
│ ├── vins_node.launch
│ ├── vins_nodelet_euroc.launch
│ ├── vins_nodelet.launch
│ ├── vins_robot.launch
│ └── visualization.launch
├── LICENSE
├── nodelet_plugins.xml
├── package.xml
├── readme.md
├── rviz
│ ├── rviz_config_gs.rviz
│ └── rviz_config.rviz
├── src
│ ├── grid.cpp
│ ├── imu_integration_nodelet.cpp
│ ├── pinhole_camera_stereo.cpp
│ ├── sdd_vio_bag_reader.cpp
│ ├── sdd_vio_node.cpp
│ ├── sdd_vio_nodelet.cpp
│ ├── utils
│ │ ├── calib_utils.cpp
│ │ └── math_utils.cpp
│ ├── visualization.cpp
│ ├── vo_stereo_1.cpp
│ ├── vo_stereo_2.cpp
│ ├── vo_stereo_3.cpp
│ └── vo_stereo_4.cpp
└── statistics
9 directories, 47 files
So we see all the header files in the ./include/sdd_vio folder.
But in the ./src/vo_stereo_1.cpp file, it includes a header file like this:
#include "sdd_vio/vo_stereo.h"
I feel it should use this instead:
#include "../include/sdd_vio/vo_stereo.h"
Why does it omit the ../include part?
Also, it would be good if there are good resources to help me learn about build / CMake / how to figure out the correct include path in general. I've read the official CMake tutorial, some tutorials on how compile + link actually work, but still feel my knowledge is not systematic... Thanks!
Edit
Adding the CMakeLists.txt file below as mentioned in the answer.
cmake_minimum_required(VERSION 2.8.3)
project(sdd_vio)
IF(DEFINED ENV{ARM_ARCHITECTURE})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wall -march=native -mfpu=neon")
#set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -Ofast -fno-signed-zeros -fno-math-errno -funroll-loops -fno-strict-aliasing")
ELSE()
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=native -Wall -std=c++11")
ENDIF()
# set default build type
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
find_package(catkin REQUIRED COMPONENTS
roscpp
image_transport
sensor_msgs
cv_bridge
visualization_msgs
tf
nodelet
rosbag
)
FIND_PACKAGE(OpenCV 3 REQUIRED)
FIND_PACKAGE(Eigen3 REQUIRED)
find_package(Boost REQUIRED COMPONENTS thread)
#find_package(Ceres REQUIRED)
# Check if OpenCV package has been found
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
# Check if Eigen package has been found
message(STATUS "Eigen library status:")
message(STATUS " version: ${EIGEN3_VERSION}")
message(STATUS " libraries: ${EIGEN3_LIBS}")
message(STATUS " include path: ${EIGEN3_INCLUDE_DIRS}")
catkin_package(
LIBRARIES vo_nodelet imu_integration_nodelet
DEPENDS EIGEN3 OpenCV
CATKIN_DEPENDS roscpp image_transport sensor_msgs visualization_msgs tf nodelet
LIBRARIES sdd_vio_nodelet
)
INCLUDE_DIRECTORIES(
include
${EIGEN3_INCLUDE_DIR}
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
add_library(pinhole_camera src/pinhole_camera_stereo.cpp)
target_link_libraries(pinhole_camera ${catkin_LIBRARIES} ${Boost_LIBRARIES} ${OpenCV_LIBS} utils)
add_library(utils src/utils/math_utils.cpp src/utils/calib_utils.cpp)
target_link_libraries(utils ${OpenCV_LIBS} ${catkin_LIBRARIES})
add_library(vo src/vo_stereo_1.cpp src/vo_stereo_2.cpp src/vo_stereo_3.cpp src/vo_stereo_4.cpp src/grid.cpp)
# add_library(vo src/disp_vo_stereo.cpp src/grid.cpp)
target_link_libraries(vo utils pinhole_camera ${catkin_LIBRARIES} ${Boost_LIBRARIES} ${OpenCV_LIBS}) # ${CERES_LIBRARIES}
# for nodelet
add_library(vo_nodelet src/sdd_vio_nodelet.cpp src/visualization.cpp)
add_dependencies(vo_nodelet ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(vo_nodelet vo ${catkin_LIBRARIES} ${Boost_LIBRARIES})
add_library(imu_integration_nodelet src/imu_integration_nodelet.cpp)
add_dependencies(imu_integration_nodelet ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS})
target_link_libraries(imu_integration_nodelet ${catkin_LIBRARIES})
# for node
ADD_EXECUTABLE(sdd_vio_node src/sdd_vio_node.cpp src/visualization.cpp)
TARGET_LINK_LIBRARIES(
sdd_vio_node
pinhole_camera
vo
${OpenCV_LIBS}
${catkin_LIBRARIES}
)
add_executable(sdd_vio_bag_reader src/sdd_vio_bag_reader.cpp)
target_link_libraries(sdd_vio_bag_reader vo_nodelet)
Why does it omit the ../include part?
Your CMakeLists.txt file contains the following lines in it:
INCLUDE_DIRECTORIES(
include
${EIGEN3_INCLUDE_DIR}
${catkin_INCLUDE_DIRS}
${OpenCV_INCLUDE_DIRS}
)
INCLUDE_DIRECTORIES tells the compiler where to look for header files. In this case one of the places is the include directory in your project, hence allows you to omit the ../include part. This is also the better form to use because using an absolute path and then moving the .cpp file that contains the include statement to some sub-folder in the future might break your code.
it would be good if there are good resources to help me learn about build / CMake
There are a couple of good books about Cmake, like Cmake CookBook. But in this case since you are dealing with ROS, I would suggest you start with ROS tutorials, they cover some of the basics of what you wish to know.
RT~ ps: cmake version 3.9.2
My codebase just like this.
suzanwen#n224-004-133:~/repos/C++/ttt:)$ tree -L 2
.
├── build
│ ├── bin
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── cmake_install.cmake
│ ├── lib
│ ├── Makefile
│ ├── test
│ └── thirdparty
├── build.sh
├── CMakeLists.txt
├── Makefile
├── test
│ ├── CMakeLists.txt
│ └── main.cc
└── thirdparty
├── CMakeLists.txt
├── gflags
└── hellolib
10 directories, 9 files
my thirdparty/hellolib/CMakeLists.txt is
PROJECT(hello)
SET(LIBHELLO_SRC hello.cc)
MESSAGE(STATUS "LIBRARY PATH=" ${LIBRARY_OUTPUT_PATH})
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello")
my test/CMakeLists.txt is
INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/thirdparty/hellolib
${PROJECT_SOURCE_DIR}/thirdparty/gflags/include)
IF(LIBRARY_OUTPUT_PATH)
LINK_DIRECTORIES(${LIBRARY_OUTPUT_PATH})
ENDIF(LIBRARY_OUTPUT_PATH)
ADD_EXECUTABLE(main main.cc)
TARGET_LINK_LIBRARIES(main hello)
# TARGET_LINK_LIBRARIES(main hello_static)
when I build my top-level project, an error occurs like this.
/usr/bin/c++ -rdynamic CMakeFiles/main.dir/main.cc.o -o ../bin/main -L/home/suzanwen/repos/C++/ttt/build/lib -Wl,-rpath,/home/suzanwen/repos/C++/ttt/build/lib -lhello
/usr/bin/ld: cannot find -lhello
But when I comment the line # SET_TARGET_PROPERTIES(hello_static PROPERTIES ARCHIVE_OUTPUT_NAME "hello") and TARGET_LINK_LIBRARIES with hello_static, everything goes fine.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target. Could anyone explain it? thanks in advance.
It seems that TARGET_LINK_LIBRARIES cannot find renamed lib target.
Setting ARCHIVE_OUTPUT_NAME property renames not a target, but an output file. So linking with a target still works:
TARGET_LINK_LIBRARIES(main hello_static)
One cannot rename the target once it is created, but it is possible to create ALIAS for a target:
ADD_LIBRARY(hello ALIAS hello_static)
After that it is possible to link with the alias:
TARGET_LINK_LIBRARIES(main hello)
I have a project which uses cmake to build. The project has a number of submodules which build as libraries. The structure looks like this:
src
├── CMakeLists.txt
├── libA
│ ├── CMakeLists.txt
│ ├── include
│ │ └── A
│ │ └── A.h
│ └── src
│ └── A.cpp
│
├── libB
│ ├── CMakeLists.txt
│ ├── include
│ │ └── B
│ │ └── B.h
│ └── src
│ └── B.cpp
│
├── include
│ └── project.h
├── main
│ ├── CMakeLists.txt
│ └── main.cpp
└── other_main
├── CMakeLists.txt
└── main.cpp
Now it turns out that I need to convert module B to be template based rather than a linkable lib; i.e. I want to export just headers from module B.
Currently module B's CMakeLists.txt contains the following:
add_library(B STATIC ${SOURCES})
target_include_directories(B
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
... other include dirs ...
PRIVATE
src)
# B depends on A
target_link_libraries(B A)
export(
TARGETS B
FILE BLibraryConfig.cmake)
What are the minimum changes I need to make to my CMakeLists files (at either module or project scope) to be able to support B as a template library given that B still depends on A and both my main projects make use of A and B?
As another answer says, you could declare B as an interface library. This approach has some limitations, though. For instance, you cannot set custom properties on interface libraries. Also B's headers might not be properly displayed by an IDE, e.g. QtCreator 4.6.1 does not show them in the project tree.
If this is critical for you, there is an alternative. You could have a static library which contains only headers, but you need to manually specify it's linker language.
add_library(B STATIC ${SOURCES})
target_include_directories(B
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
... other include dirs ...
)
# As B does not have any source files, you have to explicitly
# specify the linker language
set_target_properties(B PROPERTIES LINKER_LANGUAGE CXX)
# B depends on A
target_link_libraries(B A)
export(
TARGETS B
FILE BLibraryConfig.cmake)
You can declare B as an interface library to define it as header-only. It will just require slight modifications of target_include_directories and target_link_libraries (define INTERFACE properties instead of public/private)
add_library(B INTERFACE) # no sources
target_include_directories(B INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
# other include dirs ...
)
# B depends on A
target_link_libraries(B INTERFACE A)
export(
TARGETS B
FILE BLibraryConfig.cmake
)