CMake cannot link executable -ljsoncpp: no such file using github submodules - c++

I am working in a project which uses jsoncpp for parsing and cmake for compilation. I added the jsoncpp official git repository as a submodule to my project with git submodule add REPO_URL external/jsoncpp, so as to keep every dependency together.
When running cmake -B out/build, it works normally. But when I do make, I get the following error:
/usr/bin/ld: cannot find -ljsoncpp: No such file or directory.
The files are organized the following way:
- root
- out/build
- external
- jsoncpp (cloned repo)
- include
foo.h
bar.h
- src
foo.cpp
bar.cpp
main.cpp
CMakeLists.txt
The CMakeLists.txt is like this:
cmake_minimum_required(VERSION 3.22.1)
project(ants)
# ".cpp" files in folder "src" into cmake variable "SOURCE"
file(GLOB SOURCE "src/*.cpp")
# Executable
add_executable(${PROJECT_NAME} ${SOURCE})
# Directory where cmake will look for include files
include_directories(include)
# Tells cmake to compile jsoncpp
add_subdirectory(external/jsoncpp)
# Tells cmake where to look for jsoncpp include files
target_include_directories(${PROJECT_NAME}
PUBLIC external/jsoncpp/include
)
target_link_libraries(${PROJECT_NAME} jsoncpp)

The jsoncppConfig.cmake defines property INTERFACE_INCLUDE_DIRECTORIES for targets jsoncpp_lib and jsoncpp_lib_static.
You need to query the target property and set it manually:
get_target_property(JSON_INC_PATH jsoncpp_lib INTERFACE_INCLUDE_DIRECTORIES)
include_directories(${JSON_INC_PATH})
Linking is done via:
target_link_libraries(${PROJECT_NAME} jsoncpp_lib)
Source.
Try this:
cmake_minimum_required(VERSION 3.22.1)
project(ants)
# ".cpp" files in folder "src" into cmake variable "SOURCE"
file(GLOB SOURCE "src/*.cpp")
# Executable
add_executable(${PROJECT_NAME} ${SOURCE})
# Directory where cmake will look for include files
include_directories(include)
# Tells cmake to compile jsoncpp
add_subdirectory(external/jsoncpp)
get_target_property(JSON_INC_PATH jsoncpp_lib INTERFACE_INCLUDE_DIRECTORIES)
include_directories(${JSON_INC_PATH})
target_link_libraries(${PROJECT_NAME} jsoncpp_lib)

Related

why add_subdirectory() command did not work for my CMakeLists.txt?

I have a simple exercise on cmake with following file tree:
proj01/
include/
functions.h
src/
main.cpp
functions.cpp
CMakeLists.txt
CMakeLists.txt
README
My project CMakeLists.txt is like this:
cmake_minimum_required(VERSION 3.21)
project (test01)
add_subdirectory(src)
set(SOURCES
main.cpp
functions.cpp
)
add_executable(myProgram ${SOURCES})
and when I tried to build, I got error:
# Error!
CMake Error at CMakeLists.txt:18 (add_executable):
Cannot find source file:
main.cpp
CMake Error at CMakeLists.txt:18 (add_executable):
No SOURCES given to target: myProgram
If I change the project CMakeLists.txt by giving the absolute path(relative to the project), it worked!
#add_subdirectory(src)
set(SOURCES
src/main.cpp
src/functions.cpp
)
add_executable(myProgram ${SOURCES})
When there is multiple source files in multiple subdirectories, it would be better to explicitly list all source files including their paths as what is done with my working version of the CMakeLists.txt.
Spent hours to search for command add_subdirectories(), this, this, and this, but no luck.
The closest one would be this question, but there is no solution for that question so far.
What did I miss with my add_subdirectory(src) in this simple specific scenario? Any help is appreciated.
add_subdirectory(src) results in cmake parsing src/CMakeLists.txt creating a new directory src in the build tree for building the part of the project in this cmake file.
It doesn't result in you being able to use shorter paths in the CMakeLists.txt file containing the add_subdirectory command.
If you move the target to src/CMakeLists.txt you could use the shorter paths:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project (test01)
add_subdirectory(src) # add src/CMakeLists.txt to this project
src/CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
set(SOURCES
main.cpp
functions.cpp
)
add_executable(myProgram ${SOURCES})
Personally I'd avoid adding an additional CMakeLists.txt file just to shorten the paths. It's easy to remove the duplication of the src dir, if that's what you're worried about.
set(SOURCES
main.cpp
functions.cpp
)
list(TRANSFORM SOURCES PREPEND "src/")
or
function(subdir_files VAR DIR FILE1)
set(FILES)
foreach(SRC IN ITEMS ${FILE1} ${ARGN})
list(APPEND FILES ${DIR}/${SRC})
endforeach()
set(${VAR} ${FILES} PARENT_SCOPE)
endfunction()
subdir_files(SOURCES src
main.cpp
functions.cpp
)

CMakeLists include Header File from subdirectories

I am trying to work with CMake for the first time and am struggling to link header files into my main. My cmake directory looks like this:
Project
| CmakeLists.txt
| src
|| CMakeLists.txt
|| Main.cpp
| Libs
|| CMakeLists.txt
|| headers
|||obstacle_detection.hpp
||source
|||obstacle_detection.cpp
|build
||"build files"
I would like to link the files in the headers folder to main, but what I currently have does not appear to work. The following runs the CMake command correctly but fails to compile with the make command, being unable to find the given header file. My CMakeLists files are as follows:
Project:
cmake_minimum_required(VERSION 3.17)
project(Sensivision)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
find_package(OpenCV REQUIRED)
find_package(realsense2 REQUIRED)
find_library(darknet REQUIRED)
add_subdirectory(libs)
add_subdirectory(src)
target_link_libraries(${PROJECT_NAME} obstacle_detection)
Libs:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
src:
add_executable(${PROJECT_NAME} main.cpp)
target_link_libraries(${PROJECT_NAME} ${OpenCV_LIBS})
target_link_libraries(${PROJECT_NAME} ${realsense2_LIBRARY})
My include in main.cpp is
include <obstacle_detection.hpp>
I have also tried
include <headers/obstacle_detection.hpp>
and
include <obstacle_detection>
Each gives the error:
obstacle_detection.hpp: no such file or directory
What am I doing incorrectly to link the header to the main?
You haven't added any include directories to the obstacle_detection library. By listing the header file in the add_library call, this may allow the header to be displayed in an IDE, but it doesn't do anything for compilation. You should use target_include_directories to add the headers directory as an include directory for the obstacle_detection library. Otherwise, it, and other consuming targets, will have no knowledge of the headers in that directory.
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
# Add this line.
target_include_directories(obstacle_detection PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/headers)
# Not sure this line is necessary, as it doesn't appear you actually link anything...
target_link_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
You haven't shown the CMake code in the src directory, but be sure to link the obstacle_detection library target to the main target, e.g.:
target_link_libraries(MyExeTarget PRIVATE obstacle_detection)
In addition, because this header file is local, it is best if you use quotes to include the header:
#include "obstacle_detection.hpp"
You can use target_include_directories to add folder where your headers are located and #include <header.hpp> where needed.
Ex:
libs cmake:
add_library(
obstacle_detection
headers/obstacle_detection.hpp
sources/obstacle_detection.cpp
)
target_include_directories(obstacle_detection PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}")
cpp:
#include <headers/obstacle_detection.hpp>

CMake import local shared library and how to include it in a header

I'm stuck to import a shared library in another project with CMake.
my-utils-lib
My lib files are generated in my-utils-lib project:
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(my-utils-lib VERSION 1.0.0 DESCRIPTION "Utils for C++.")
set(CMAKE_CXX_STANDARD 14)
add_library(
my-utils-lib SHARED
./src/string_utils/find_matches.cpp
./src/string_utils/split.cpp
./src/string_utils/format.cpp
./src/vector_utils/print_vector.cpp
)
set_target_properties(
my-utils-lib PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION 1
)
target_include_directories(my-utils-lib PRIVATE src)
include(GNUInstallDirs)
install(
TARGETS my-utils-lib
DESTINATION ${CMAKE_INSTALL_LIBDIR}
EXPORT my-utils-lib
)
configure_file(my-utils-lib.pc.in my-utils-lib.pc #ONLY)
install(
FILES ${CMAKE_BINARY_DIR}/my-utils-lib.pc
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig
)
I run mkdir build && cd ./build/ && cmake .. && sudo make install to generate and install my library files.
Finally, my-utils-lib project tree looks like this:
CMakeLists.txt
my-utils-lib.pc.in
src/
|_main.cpp
|_main.h
|_string_utils/
|_find_matches.cpp
|_find_matches.h
|_format.cpp
|_format.h
|_split.cpp
|_split.h
|_vector_utils/
|_print_vector.cpp
|_print_vector.h
my-project
In another project, I'd like to import "split.h" in one of my local headers without having to enter the full path to the actual file. Something like:
#include "my-utils-lib/string_utils/split.h"
I tried many solution so far, none of them is working. My last attempt is:
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(longer_sub_sequence)
set(CMAKE_CXX_STANDARD 14)
find_package(Qt5Widgets REQUIRED)
find_library(my-utils-lib libmy-utils-lib.1.0.0.dylib)
add_library(my-utils-lib SHARED IMPORTED)
add_executable(
longer_sub_sequence
main.cpp
visualization/draw_matrix.cpp
visualization/draw_matrix.h
)
target_link_libraries(longer_sub_sequence my-utils-lib Qt5::Widgets)
CMake autobuild runs fine (I am using CLion as an IDE) but I can't find how to import any code from my library.
I checked in /usr/local/lib (where CMake generated my lib files), and found the correct lib files :
find . -maxdepth 1 -name "*my-utils-lib*" -print
./libmy-utils-lib.1.0.0.dylib
./libmy-utils-lib.1.dylib
./libmy-utils-lib.dylib
What am I missing here ?
You are missing to install the library header.
You should add an install command for header just like you did with the library binary.
Moreover you should consider using comparison signs (< and >) instead of double quote for include directive :
#include <my-utils-lib/string_utils/split.h>
One last remark, you are generating and installing a .pc file which is used by pkg-config only and you're not using it.

CMake with protobuf file in subdirectory

I have seen a lot of similar questions and answers, but until now it seems not so obvious to get it working. I am quite new to CMake and until now everything was easy except the integration with protocol buffers.
I have a project with subdirectories, where each subdirectory has its own CMakeLists.txt
One of the subdirectory contains a .proto file. If the PROTOBUF_GENERATE_CPP macro is executed it generates the sources and the headers files. This macro is invoked from the CMakeLists.txt in the subdirectory containing the .proto file.
It seems however the make file is not invoked because no sources are added to the target. I can not add the sources to the target, because the files do not exist, they exist after generation, so this results in an error when CMake runs.
Setting the file properties to generated seems also not to help. In general, before the build process starts the macro should have been run to generated the source files.
How to do this, any working examples ?
Example:
./src/externals/protodef (from other repository, only contains .proto files)
./src/generated (supposed for the generated c and header files by protoc)
CMakeLists-1 (project root)
cmake_minimum_required (VERSION 2.6)
PROJECT (prototest)
ADD_SUBDIRECTORY("${PROJECT_SOURCE_DIR}/src/externals/protodef")
ADD_SUBDIRECTORY("${PROJECT_SOURCE_DIR}/src")
SET_SOURCE_FILES_PROPERTIES(${PROTO_SOURCES} ${PROTO_HEADERS} PROPERTIES GENERATED TRUE)
ADD_EXECUTABLE(prototest ${PROTO_SOURCES} ${SOURCE} )
TARGET_LINK_LIBRARIES(prototest ${EXTERNAL_LIBS} )
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
CMakeLists-2 (src)
SET(SOURCE ${SOURCE}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
PARENT_SCOPE
)
CMakeLists-3 (src/externals/protodef)
SET(PROTOBUF_PATH "D:/protobuf-3.0.0/" )
SET(CMAKE_PREFIX_PATH ${CMAKE_PREFIX_PATH} "${PROTOBUF_PATH}")
# Changing PROTO_SRCS and PROTO_HDRS does not work for setting the location
# of the generated files.
# Those variable are ignored by CMake for compiling the proto files.
# Using a dedicated CMakeLists.txt and settng CURRENT_BINARY dir is a
# workaround to get them where we want.
SET(GENERATED_DIR ${PROJECT_SOURCE_DIR}/src/generated )
SET(CMAKE_CURRENT_BINARY_DIR ${GENERATED_DIR} )
INCLUDE(FindProtobuf)
FIND_PACKAGE(Protobuf REQUIRED)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS${CMAKE_CURRENT_SOURCE_DIR}/test1.proto)
SET( EXTERNAL_LIBS ${PROTOBUF_PATH}/lib/libprotobuf.a PARENT_SCOPE)
# Propagate sources to the parant project
SET(PROTO_SOURCES ${PROTO_SRCS}
PARENT_SCOPE
)
SET(PROTO_HEADERS ${PROTO_HDRS}
PARENT_SCOPE
)
First generate the protobuf files, then add them to a CMake target.
CMakeLists (src) :
# Generate h/cpp proto files (./src/externals/protodef) into ./src/generated folder
PROTOBUF_GENERATE_CPP(...)
# Process subdir
ADD_SUBDIRECTORY(generated)
It seems that PROTOBUF_GENERATE_CPP can only be used in the same subdirectory. A possible workaround is to invoke protoc directly instead :
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/externals/protodef PROTOMODEL_PATH)
FILE(TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/generated PROTOBINDING_PATH)
FILE(GLOB DATAMODEL_PROTOS "${CMAKE_CURRENT_SOURCE_DIR}/externals/protodef/*.proto")
FOREACH(proto ${DATAMODEL_PROTOS})
FILE(TO_NATIVE_PATH ${proto} proto_native)
EXECUTE_PROCESS(COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${PROTOMODEL_PATH} --cpp_out=${PROTOBINDING_PATH} ${proto_native}
RESULT_VARIABLE rv)
# Optional, but that can show the user if something have gone wrong with the proto generation
IF(${rv})
MESSAGE("Generation of data model returned ${rv} for proto ${proto_native}")
ENDIF()
ENDFOREACH(proto)
CMakeLists (src/generated) :
## List generated sources files
FILE(GLOB HDRS "*.h")
FILE(GLOB SRCS "*.cc")
ADD_LIBRARY(protoBinding ${HDRS} ${SRCS})
# ${PROTOBUF_LIBRARIES} should be defined by FIND_PACKAGE(Protobuf REQUIRED)
TARGET_LINK_LIBRARIES(protoBinding ${PROTOBUF_LIBRARIES})
This way CMake will first generate the header/source files, and only then add the generated files to a CMake target.
You can then use protoBinding target to link the generated files to an other target (e.g at the end of src's CMakeLists.txt) :
ADD_LIBRARY(myModel ${myFiles})
TARGET_LINK_LIBRARIES(myModel protoBinding)

How to properly use file GLOB?

I'm trying to use GLOB_RECURSE to specify my sources and headers files. Currently, my CMakeLists.txt for a static library is:
project(LinearSystemLib)
file(GLOB_RECURSE ${PROJECT_NAME}_headers ${PROJECT_SOURCE_DIR}/*.h)
file(GLOB_RECURSE ${PROJECT_NAME}_sources ${PROJECT_SOURCE_DIR}/*.cpp)
add_library(
${PROJECT_NAME} STATIC ${${PROJECT_NAME}_headers}
${${PROJECT_NAME}_sources}
)
install(
TARGETS ${PROJECT_NAME}
LIBRARY DESTINATION libs
ARCHIVE DESTINATION archives
)
The library directory looks like this:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
When I run command cmake .. -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug (in the build directory) everything goes ok. Yet, command make it displays the following:
/home/felipe/Documents/Dados/SINMEC/Eclipse/LinearSystemLib/source/LinearSystemLib.cpp:1:29: fatal error: LinearSystemLib.h: No such file or directory
Is my CMakeLists wrong? I don't want to set specify the sources and headers files by name. I'm not finding information about glob_recurse easily.
I can make it work by listing the sources and headers files by name. However, it MUST be done with the glob_recurse or with glob.
I solved my problem, here's what LinearSystemLib directory looks like:
LinearSystemLib
CMakeLists.txt
source
LinearSystemLib.cpp
include
LinearSystemLib.h
The CMakeLists.txt contains:
project(LinearSystemLib)
#INCLUDE DIRECTORIES
include_directories(${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include)
#SEARCH FOR .CPP AND .H FILES
file(GLOB ${PROJECT_NAME}_headers ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/include/*.h)
file(GLOB ${PROJECT_NAME}_sources ${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/*.cpp)
#ADD LIBRARY
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_sources})
#DEFINE OUTPUT LOCATION
install(
TARGETS ${PROJECT_NAME}
ARCHIVE DESTINATION static_libs
)
You don't actually NEED to add the .h/.hpp files using GLOB. I did it because otherwise, Visual Studio (or CodeBlocks) wouldn't create a "Header Files" folder on the project menu.
I wasn't properly specifying the path where GLOB would find the files.
${CMAKE_SOURCE_DIR}/${PROJECT_NAME}/source/
You need to add
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_SOURCE_DIR})
so the correct -I argument is added to your compilation step. Use make VERBOSE=1 to see exactly what commands make is executing.