How to add include_directory in simple CMake Project - cmake

I have CMake project whose directory structure is as follows:
├── build
├── CMakeLists.txt
├── src
│   ├── CMakeLists.txt
│   ├── headers
│   │   └── utility.h
│   └── main.cpp
└── tests
├── CMakeLists.txt
├── testfeature_a
│   ├── CMakeLists.txt
│   └── test_me.cpp
└── test_main.cpp
In test_me.cpp I wanted to include utility.h as I wanted to test functions defined there. So I did #include "headers/utility.h" and in testfeature_a CMakeLists.txt I did this:
file(GLOB SRCS *.cpp)
ADD_EXECUTABLE(testfeature_a ${SRCS})
include_directories(src/headers)
TARGET_LINK_LIBRARIES(
testfeature_a
libgtest
libgmock
)
add_test(NAME testfeature_a
COMMAND testfeature_a)
But the make fails with the error message fatal error: headers/utility.h: No such file or directory.
How can I include the headers directory in test_me.cpp

Your path in include_directories() may be incorrect. Here are two things that you could check
The file seems to be the CMakeLists.txt in tests-folder so you need to go up one folder before you can go to src-folder, i.e. include_directories(../src/headers).
You repeat the headers-folder in the #include "headers/utility.h" when you have already specified it in include_directories(src/headers). Either use #include "utility.h" in cpp-file or include_directories(src) in CMakeLists.txt.
Other option is that you don't need to specify the headers-folder in the CMakeLists.txt at all. You can simply use #include "path/to/your/file.h without any other configuration.
For debugging your path in the CMakeLists.txt you can call message-function, e.g. message(${your_path}), so it's printed when executed and you can check if it's correct.
In addition you can use CMake built-in variables such as CMAKE_CURRENT_SOURCE_DIR and CMAKE_SOURCE_DIR, e.g. include_directories(${CMAKE_SOURCE_DIR}/src/headers)

Related

How to properly use CMake to create a complex project with dependencies on custom libraries

I'm trying to create a complex project that becomes a single executable file that uses the following libraries: two libraries BHV and HAL that use one interface library.
I have this project structure:
.
├── BHV
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libBHV_Library.so
│   ├── Makefile
│   └── sources
├── HAL
│   ├── check_libraries.cmake
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libHAL_Library.so
│   ├── Makefile
│   └── sources
├── Interface
│   ├── CMakeCache.txt
│   ├── CMakeFiles
│   ├── cmake_install.cmake
│   ├── CMakeLists.txt
│   ├── include
│   ├── libInterface_Library.a
│   ├── Makefile
│   └── sources
├── CMakeCache.txt
├── CMakeFiles
├── cmake_install.cmake
├── CMakeLists.txt
├── main.cpp
├── Makefile
├── README.md
Unfortunately, I can't connect the individual libraries to each other.
In Interface_lib CMakeList.txt I have this:
cmake_minimum_required(VERSION 3.10)
project(Interface_Library)
#requires at least C++17
set(CMAKE_CXX_STANDARD 17)
# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")
# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")
# Add main.cpp to the project
add_library(Interface_Library STATIC ${SOURCES} ${HEADERS})
In HAL_lib CMakeList.txt I have this:
cmake_minimum_required(VERSION 3.10)
project(HAL_Library)
# requires at least C++17
set(CMAKE_CXX_STANDARD 17)
################################### DIR_MANAGMENT #########################################
# Get the parent directory
get_filename_component(PARENT_DIR ${CMAKE_CURRENT_LIST_DIR} DIRECTORY)
#Set the directory of the parent file as the current directory
set(CMAKE_CURRENT_LIST_DIR ${PARENT_DIR})
message("MYPROJECT_DIR directory: ${CMAKE_CURRENT_LIST_DIR}")
################################### HAL_LIB #########################################
# Add all .cpp files from sources folder
file(GLOB SOURCES "sources/*.cpp")
# Add all .h files from include folder
file(GLOB HEADERS "include/*.h")
# Add main.cpp to the project
add_library(HAL_Library SHARED ${SOURCES} ${HEADERS})
################################### INTERFACE_LIB #########################################
target_link_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/Interface)
# Link the Interface_Library into the HAL_Library
target_link_libraries(HAL_Library Interface_Library)
# check if libraries were included
set(TARGET_NAME HAL_Library)
include(check_libraries.cmake)
this is the code i use to check_libraries.cmake (from the internet)
# Get a list of referenced libraries
get_target_property(LINK_LIBS ${TARGET_NAME} LINK_LIBRARIES)
# Print the list of referenced libraries
message("Odkazované knihovny: ${LINK_LIBS}")
# Verify that libraries are available on the system
foreach(LIB ${LINK_LIBS})
execute_process(COMMAND ldd $<TARGET_FILE:${TARGET_NAME}> | grep ${LIB}
RESULT_VARIABLE res
OUTPUT_QUIET ERROR_QUIET)
if(res EQUAL "0")
message("Library ${LIB} was successfully linked with ${TARGET_NAME}")
else()
message(FATAL_ERROR "Error: Library ${LIB} not found.")
endif()
endforeach()
As an output I keep getting the library not found. What am I doing wrong?
And is my approach to project structure correct?
Thank you.
Typically you do:
# ./CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(Interface_Library)
add_subdirectory(HAL)
add_subdirectory(Interface)
# HAL/CMakeListst.txt
file(srcs GLOB sources/*.c include/*.h)
add_library(HAL ${srcs})
target_include_directories(HAL PUBLIC include)
target_link_libraries(HAL PUBLIC Interface)
# Interface/CMakeLists.txt
file(srcs GLOB source/*.c include/*.h)
add_library(Interface ${srcs})
target_include_directories(HAL PUBLIC include)
That's all. Only one project() call, in the root. Note the target_include_directories missing in your code. Note the main root CMakeLists.txt that includes all. I find HEADERS and SOURCES separately confusing, I would also use lowercase everything. No target_link_directories, CMake will find everything. Also, everything is compiled as one big project, not separately.

Library linking not working when CMake single build

using CMake I want to build in each directory A, B, and C.
The project structure is as follows:
.
├── A
│   ├── CMakeLists.txt
│   └── src
│   └── a.cpp
├── B
│   ├── CMakeLists.txt
│   └── src
│   └── b.cpp
├── common
│   ├── CMakeLists.txt
│   ├── include
│   │   ├── common.h
│   └── src
│   └── common.cpp
└── C
├── CMakeLists.txt
└── src
└── c.cpp
Create a library in the Common directory and install the created library.
common/CmakeLists.txt :
set(COMMON_LIB_NAME CommonTemp)
set(SRC_CODE
${CMAKE_CURRENT_SOURCE_DIR}/include/common.h
${CMAKE_CURRENT_SOURCE_DIR}/src/common.cpp
)
add_library (${COMMON_LIB_NAME} SHARED ${SRC_CODE})
install(TARGETS ${COMMON_LIB_NAME} DESTINATION ~/tempDir/lib)
I want to link the generated library to directory A.
a.cpp requires common.h.
A/CMakeLists.txt:
ADD_EXECUTABLE(ServiceA src/a.cpp)
target_include_directories (
ServiceA PUBLIC
include
)
target_sources (
ServiceA PRIVATE
src/a.cpp
)
target_link_libraries(
ServiceA PUBLIC
${COMMON_LIB_NAME} #### Location considered to be a problem
)
install(TARGETS ServiceA DESTINATION ~/tempDir/bin/A)
An error message occurs saying that common.h cannot be included.
My guess is that the ${COMMON_LIB_NAME} variable is defined in CMakeLists.txt in another directory, so it is expected that it cannot be linked.
But even if I put CommonTemp , the value of the variable, it says that common.h cannot be found.
How can I link library links even if I build CMake individually in each directory?
In common/CmakeLists.txt.
You need to include the headers in target_include_directores.
target_include_directories(
${COMMON_LIB_NAME} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
No need to mention it in add_library
In A/CMakeLists.txt. Include path is not correct.
target_include_directories(
ServiceA PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/<path to common>/include
)
For linking the library you have to mention the correct library path otherwise it will fail
target_link_libraries(
ServiceA PUBLIC
${COMMON_LIB_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/<path to tempDir>/lib
)

What does FindPackageHandleStandardArgs do exactly?

I am trying to write a Find Module for a package that I have installed. But I am having trouble understanding the CMake functions.
Here is a snippet of my code.
find_package(PkgConfig)
pkg_check_modules(PC_zcm QUIET zcm)
find_path(zcm_INCLUDE_DIR
NAMES zcm.h
PATHS $ENV{PATH}
)
mark_as_advanced(zcm_FOUND zcm_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(zcm DEFAULT_MSG
REQUIRED_VARS zcm_INCLUDE_DIR
)
find_path() is able to find my zcm_INCLUDE_DIR just fine: /usr/bin/zcm/usr/local/include
But find_package_handle_standard_args() gives
-- Could NOT find zcm (missing: REQUIRED_VARS)
My directory tree looks like this:
└── zcm
├── eventlog.h
├── json
│   ├── json-forwards.h
│   └── json.h
├── message_tracker.hpp
├── tools
│   ├── IndexerPlugin.hpp
│   └── TranscoderPlugin.hpp
├── transport
│   └── generic_serial_transport.h
├── transport.h
├── transport_register.hpp
├── transport_registrar.h
├── url.h
├── util
│   └── Filter.hpp
├── zcm-cpp-impl.hpp
├── zcm-cpp.hpp
├── zcm.h
└── zcm_coretypes.h
My understanding is find_package_handle_standard_args() attempts to find the package at the path, which sounds like it would be straightforward as the path is already determined.
As for REQUIRED_VARS the docs just say "Specify the variables which are required for this package." Which doesn't tell much for a noobie like me.
Description of find_package_handle_standard_args notes about two signatures of given function, one signature accepts DEFAULT_MSG option and another one accepts REQUIRED_VARS option.
You are trying to mix these signatures, and this is wrong.
Proper usage of the first signature:
# Everything after DEFAULT_MSG is treated as required variable.
find_package_handle_standard_args(zcm DEFAULT_MSG
zcm_INCLUDE_DIR
)
Proper usage of the second signature:
# By default, the standard error message is used.
find_package_handle_standard_args(zcm REQUIRED_VARS
zcm_INCLUDE_DIR
)

cmake can't find the depending library

I have a demo project which rely on a logger library, The file structure of the relevant files are listed as below:
.
├── FancyLogger
│   ├── CMakeLists.txt
│   ├── FancyLogger.cpp
│   ├── FancyLogger.h
│   ├── bin
│   │   └── libFancyLogger.a
└── HelloClion
├── CMakeLists.txt
├── helloclion.cpp
I have build a static library named as libFancyLogger.a in the ./FancyLogger/bin directory.
My CMakeFiles of the project HelloClion is listed as below:
cmake_minimum_required(VERSION 3.3)
project(HelloClion)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
get_filename_component(CODE_ROOT ${CMAKE_CURRENT_SOURCE_DIR} DIRECTORY)
set(SOURCE_FILES helloclion.cpp)
add_executable(HelloClion ${SOURCE_FILES})
include_directories(${CODE_ROOT}/FancyLogger)
link_directories(${CODE_ROOT}/FancyLogger/bin)
target_link_libraries(HelloClion FancyLogger)
But the linker complains that library not found for -lFancyLogger, I don't know how to fix this, please help.
I seems to find out why. ;)
In the cmake documentation:https://cmake.org/cmake/help/v3.0/command/link_directories.html
link_directories(directory1 directory2 ...)
Specify the paths in which
the linker should search for libraries. The command will apply only to
targets created after it is called.
The doc says, the command only applys to targets created after it is called. So I just need to move link_directories(${CODE_ROOT}/FancyLogger/bin) to some position in front of the add_executable(HelloClion ${SOURCE_FILES}) command.
Problems solved!

No tests found when using gtest with cmake/ctest

I have a project with the following structure:
linalg
├── build
├── CMakeLists.txt
├── docs
│   └── Doxyfile
├── include
│   └── linalg
│   └── vector3.hpp
├── src
│   ├── CMakeLists.txt
│   └── linalg
│   └── vector3.cpp
└── test
├── CMakeLists.txt
└── linalg
└── test_vector3.cpp
The file test_vector3.cpp is a gtest unit test file which provides two simple tests. The top level CMakeLists.txt simply sets up the includes and adds the src and test subdirectories:
cmake_minimum_required(VERSION 2.8)
project(linalg)
include_directories(include)
add_subdirectory(src)
add_subdirectory(test)
The src/CMakeLists.txt file compiles vector3.cpp into a static library:
cmake_minimum_required(VERSION 2.8)
add_library(linalg linalg/vector3.cpp)
The test/CMakeLists.txt file is based on the example provided in /usr/share/cmake-2.8/Modules/FindGTest.cmake:
cmake_minimum_required(VERSION 2.8)
enable_testing()
find_package(GTest REQUIRED)
include_directories(${GTEST_INCLUDE_DIRS})
add_executable(test_vector3 linalg/test_vector3.cpp)
target_link_libraries(test_vector3 linalg ${GTEST_BOTH_LIBRARIES} pthread)
add_test(test_vector3 test_vector3)
I then run the following:
cd build
cmake ..
make
I get the liblinalg.a library compiled correctly in to build/src and I get the test_vector3 executable compiled correctly in to build/test. I can run the test_vector3 executable and I get the output from googletest saying that all tests have passed, however if I run make test I get no output whatsoever and if I run ctest .. I get a message saying:
Test project /home/ryan/GitHub/linalg/build
No tests were found!!!
Is there something I am missing? Or have I just misunderstood how ctest works with gtest?
The crux of the problem is that enable_testing should be called from your top-level CMakeLists.txt in this case. Adding include(CTest) to your top-level CMakeLists.txt should fix this for you.
This would allow you to remove the enable_testing call in test/CMakeLists.txt, since the CTest submodule calls enable_testing internally.
Just to update this.
cmake in version 3.9 added support for GoogleTest integration with CTest.
So you can now get CTest to scrape all of the test macros in your test executable, not just the whole executable.
Example here:
https://gist.github.com/johnb003/65982fdc7a1274fdb023b0c68664ebe4