CMake add dependencies to internal library in a cousin directory - c++

I have following project structure:
│ CMakeLists.txt
├───lib
│ │ CMakeLists.txt
│ ├───lib_a
│ │ CMakeLists.txt
│ ├───lib_b
│ │ CMakeLists.txt
│ └───lib_c
│ CMakeLists.txt
└───src
│ CMakeLists.txt
└───app
├───controller
| CMakeLists.txt
└───endorser
CMakeLists.txt
The libraries are located in lib directory. lib_b links against lib_a and lib_c links against lib_b. CMake recognizes targets between libraries with no problem. For example having these lines in lib/lib_c/CMakeLists.txt file works perfectly fine:
target_link_libraries(lib_c lib_a lib_b)
However trying to do the same in the src/app/controller fails with following error:
[cmake] CMake Error at src/app/controller/CMakeLists.txt:15 (find_package):
[cmake] By not providing "Findlib_c.cmake" in CMAKE_MODULE_PATH this project has
[cmake] asked CMake to find a package configuration file provided by "lib_c", but
[cmake] CMake did not find one.
[cmake]
[cmake] Could not find a package configuration file provided by "lib_c" with any of
[cmake] the following names:
[cmake]
[cmake] lib_cConfig.cmake
[cmake] lib_c-config.cmake
And this is how I search for lib_c:
# Check for dependencies
find_package(lib_c REQUIRED)
...
# link against it
target_link_libraries(controller lib_c)
How can I export lib_c without having to install it, in such a way that src/app can link against?
Anyway, CMakeLists.txt of non-leaf directories contain only add_subdirectory calls:
# lib/CMakeLists.txt
cmake_minimum_required(VERSION 3.1.0)
add_subdirectory(lib_a)
add_subdirectory(lib_b)
add_subdirectory(lib_c)

Related

CMake add external libraries located within the project folder

Preface: I am on Windows and wish to easily send this project to someone else on a different OS.
My folder structure is:
EigenTest/
libs/
├─ Eigen3/
├─ OpenBLAS C Asm/
src/
├─ main.cpp
My cmake file:
cmake_minimum_required(VERSION 3.22)
project(EigenTest)
set(CMAKE_CXX_STANDARD 20)
add_executable(EigenTest src/main.cpp)
add_library(EigenLib STATIC)
target_include_directories(EigenLib INTERFACE "libs/Eigen3")
target_link_libraries(EigenTest PRIVATE EigenLib)
add_library(OpenBlasLib STATIC)
target_include_directories(OpenBlasLib PRIVATE "libs/OpenBLAS C ASM")
target_link_libraries(EigenTest PRIVATE OpenBlasLib)
For some reason, I get an error that there are no sources when both Eigen3 and OpenBLAS have their own CmakeList.txt and source files in those folders.
Error:
CMake Error at CMakeLists.txt:8 (add_library):
No SOURCES given to target: EigenLib
CMake Error at CMakeLists.txt:14 (add_library):
No SOURCES given to target: OpenBlasLib

CMake Windows find_package Imported target "..." includes non-existent path

I am creating my own package that configures, builds and installs the package without problem including cmake files.
The source files are here:
https://github.com/petrasvestartas/CMAKE/tree/main/install_export
Installation procedure build SHARED libs like this:
cmake -DBUILD_SHARED_LIBS=ON -G "Visual Studio 17 2022" -A x64 .. && cmake --build . --config Release && cmake --install .
I see the files here after installation:
C:\ProgramFiles\
│ sortdemo-config-release.cmake
│ sortdemo-config.cmake
│
├───include
│ ├───print
│ │ print.hpp
│ │
│ └───sort
│ sort.hpp
│
└───lib
my_print_lib.dll
my_print_lib.lib
my_sort_lib.dll
my_sort_lib.lib
Now I want to use this package to another simple project:
https://github.com/petrasvestartas/CMAKE/blob/main/find_package/CMakeLists.txt
But I get an error:
Imported target "my_sort_lib" includes non-existent path -> include/sort files
MY SIMPLE QUESTION:
How to know where CMake searches for the files?
Since I have created the project I could modify the path, but I do not know where the problem is.

CMake Error: Attempt to add link library to target which is not built in this directory (only when policy CMP0079 is set to NEW)

I want to link the component "fsm" into my executable (main.cpp). "fsm" is dependent on "taskmap". So I was trying to figure out how to configure cmake to recognise my libraries the correct way, but the configuration always fails with the following errors:
Errors (yielded while configuring):
[cmake] CMake Error at components/taskmap/CMakeLists.txt:9 (target_link_libraries):
[cmake] Attempt to add link library "taskmap" to target "sample_project" which is
[cmake] not built in this directory.
[cmake]
[cmake] This is allowed only when policy CMP0079 is set to NEW.
[cmake] Call Stack (most recent call first):
[cmake] CMakeLists.txt:8 (include)
[cmake]
[cmake]
[cmake] CMake Error at components/fsm/CMakeLists.txt:8 (target_link_libraries):
[cmake] Attempt to add link library "fsm" to target "sample_project" which is not
[cmake] built in this directory.
[cmake]
[cmake] This is allowed only when policy CMP0079 is set to NEW.
[cmake] Call Stack (most recent call first):
[cmake] CMakeLists.txt:9 (include)
My directory structure:
project
├───CMakeLists.txt
├───components
│ ├───fsm
│ │ ├───fsm.cpp
│ │ ├───CMakeLists.txt
│ │ └───include
│ │ └───fsm.hpp
│ └───taskmap
│ ├───CMakeLists.txt
│ └───include
│ └───taskmap.hpp
└───main
├───main.cpp
└───CMakeLists.txt
CMakeLists.txt (toplevel):
cmake_minimum_required(VERSION 3.0.0)
project(sample_project VERSION 0.1.0)
include(CTest)
enable_testing()
add_subdirectory(main)
include(components/taskmap/CMakeLists.txt)
include(components/fsm/CMakeLists.txt)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
main/CMakeLists.txt:
add_executable(sample_project main.cpp)
components/fsm/CMakeLists.txt:
add_library(
fsm
fsm.cpp
include/fsm.h
)
target_include_directories(fsm PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(sample_project PRIVATE fsm)
components/taskmap/CMakeLists.txt:
add_library(
taskmap
include/taskmap.h
)
set_target_properties(taskmap PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(taskmap PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_link_libraries(sample_project PRIVATE taskmap)
I can't really make a lot out of this error and have done some research:
CMake: Attempted to add link library to target which is not built in this directory
This person tried to target_link_libraries() in the toplevel CMakeLists.txt, even though the executables are added in a subordered CMakeLists.txt. Apparently target_link_libraries() needs to be called from the CMakeLists.txt where the target is specified (except if the directory scope remains the same, see below).
Alternative to calling target_link_libraries in subdirectory
This person attempted to use target_link_libraries() with the "link to"-target not specified in the same directory as the newly created target (because a new subdirectory scope was entered). I think this is somewhat related to my problem, so I switched to use include() directives instead of add_subdirectory(), but the error stays the same.
So nothing helped so far. Any clues on what I'm doing wrong?

Generate grpc files for a library target in CMAKE

In the following project structure(from my previous question):
root/
├─ CMakeLists.txt
├─ protocol/
│ ├─ msg.proto
│ ├─ myrpc.proto
│ ├─ CMakeLists.txt
├─ app/
│ ├─ main.cpp
│ ├─ CMakeLists.txt
I could generate the protobuf files and add them as dependency into the app target. Now I am trying to generate grpc files inside the same library.
Something is not right with the grpc generation function, which is based on this answer and blog post;as the following error message is printed:
-- Configuring done
-- Generating done
-- Build files have been written to: /media/davids91/Work/rafko/src/main/cxx/build
[ 1%] Running grpc protocol buffer compiler on /usr/local/bin/grpc_cpp_plugin
/usr/local/bin/grpc_cpp_plugin: File does not reside within any path specified using --proto_path (or -I). You must specify a --proto_path which encompasses this file. Note that the proto_path must be an exact prefix of the .proto file names -- protoc is too dumb to figure out when two paths (e.g. absolute and relative) are equivalent (it's harder than you think).
make[2]: * [protocol/CMakeFiles/protocol.dir/build.make:138: /media/usr/local/bin/grpc_cpp_plugin.grpc.pb.h] Error 1
make[1]: * [CMakeFiles/Makefile2:276: protocol/CMakeFiles/protocol.dir/all] Error 2
make: * [Makefile:103: all] Error 2
I can see that the install folder looks correct, as that is where the grpc library was installed from source.
root CMakeLists.txt:
cmake_minimum_required(VERSION 3.18.4)
project(
root
VERSION 0.1
LANGUAGES CXX
)
add_subdirectory(protocol)
add_subdirectory(app)
protocol CMakeLists.txt:
add_library(protocol)
target_include_directories(protocol
PUBLIC
.
${CMAKE_CURRENT_BINARY_DIR}
${Protobuf_INCLUDE_DIRS}
)
find_package(Protobuf REQUIRED)
find_package(gRPC CONFIG REQUIRED)
target_link_libraries(protocol ${Protobuf_LIBRARIES})
get_target_property(grpc_cpp_plugin_location gRPC::grpc_cpp_plugin LOCATION)
protobuf_generate( TARGET protocol LANGUAGE CPP PROTOS msg.proto )
protobuf_generate(
TARGET
protocol
LANGUAGE
grpc
PROTOS
myrpc.proto
PLUGIN
"protoc-gen-grpc=${grpc_cpp_plugin_location}"
)
app CMakeLists.txt:
add_library(app)
target_link_libraries(app PUBLIC protocol)
target_include_directories(app PUBLIC .)
target_sources(app
PRIVATE
main.cpp
)
What might be missing from this solution to generate out the grpc files based on the plugins?
After some experimenting and closely looking at the example here I figured it out!
I updated protocol CMakeLists.txt:
changed
find_package(Protobuf REQUIRED)
to
find_package(Protobuf CONFIG REQUIRED)
I figure it tells CMake that the proto files are being procesed at configuration time, but any deeper explanation is welcome!

Build open62541 library as external library with CMake

I would like to include open62541 library to my existing C++ project in Visual Studio using CMake. open62541 itself uses CMake as build tool. Project structure:
MyOPC
│ CMakeLists.txt
│ MyOPC.cpp
│ MyOPC.h
├───.vs
└───open62541
│ CMakeLists.txt
├───arch
│ │ CMakeLists.txt
├───deps
├───doc
├───examples
├───include
├───plugins
├───src
├───tests
└───tools
I would like to build open62541 togehter with my project so it will produce open62541.h file. How this could be done using CMake?
You can simply add the subdirectory of open62541 to your main CMake and before that set the corresponding CMake options. Then also add the open62541 targets to your own target and add the amalgamated source file.
E.g. to enable amalgamation:
set(UA_ENABLE_AMALGAMATION ON CACHE BOOL "" FORCE)
set(UA_LOGLEVEL 300)
add_subdirectory(open62541)
add_dependencies(${PROJECT_NAME} open62541 open62541-amalgamation-source open62541-amalgamation-header)
set (${PROJECT_NAME}_SRCS ${${PROJECT_NAME}_SRCS} "${PROJECT_BINARY_DIR}/open62541/open62541.c")
Make sure that you add the _SRCS to your own target sources.
Something similar is done here:
https://github.com/Pro/open62541-arduino
Thanks #Stefan Profanter for putting me on right direction. This is current working CMakeLists.txt:
# CMakeList.txt : Top-level CMake project file, do global configuration
# and include sub-projects here.
#
cmake_minimum_required (VERSION 3.8)
project ("MyOPC")
add_executable (${PROJECT_NAME} "MyOPC.cpp" "MyOPC.h")
# -----------------------------------
# open62541 specific settings - BEGIN
# -----------------------------------
set(UA_ENABLE_AMALGAMATION ON CACHE BOOL "" FORCE)
set(UA_LOGLEVEL 300)
add_subdirectory ("open62541")
set_source_files_properties("${PROJECT_BINARY_DIR}/open62541/open62541.c" PROPERTIES GENERATED TRUE)
set(${PROJECT_NAME}_SRCS ${${PROJECT_NAME}_SRCS} "${PROJECT_BINARY_DIR}/open62541/open62541.c")
include_directories("${PROJECT_BINARY_DIR}/open62541/")
# -----------------------------------
# open62541 specific settings - END
# -----------------------------------
add_dependencies(${PROJECT_NAME} open62541 open62541-amalgamation-source open62541-amalgamation-header)
target_link_libraries(${PROJECT_NAME} open62541)
Reference in header file MyOPC.h:
#include "open62541.h"