How to link cmake build libs to external code? - c++

I want to use this library c++ library in my code on external directory, which I have build with cmake (I'm new with it), as the compiling tutorial explain. After this, what files (or makefiles) do I'm suppose to add to my directory to do things like this is my code
#include "rpc/server.h"
I saw something about importing static libraries that would have to add a CMakeLists.txt to my directory and compile my main code with something as
g++ -static main.cc -L<librpc.a directory> -lrpc -o main
But getting this:
fatal error: rpc/server.h: No such file or directory compilation terminated.
I have searched the web about these procedures but I'm not having sucess on this. Could someone help

First you need to add the rpc library to the project as an imported library, and subsequently you must specify target properties such as the imported location and the include directories.
add_library(rpc SHARED IMPORTED)
set_target_properties(rcp
PROPERTIES
IMPORTED_LOCATION "${rpc_LIBRARIES}"
INCLUDE_DIRECTORIES "${rpc_INCLUDES}"
)
After you've successfully added the rpc library to the project, just add rpc as a target to your executable.
add_executable(your_test_program main.cpp)
target_link_libraries(your_test_program PRIVATE rpc )

Related

Why linking with imported executable target results in LNK1181: cannot open include file 'xsd.lib'

I'm writing my own find module for a third-party application (xsd from codesynthesis, but I think it's not relevant) and my project needs to use this target in two ways:
include its headers to build my project
execute the xsd executable to generate sources.
Initially I made the xsd target an interface imported library and linking to it with simple target_link_libraries was working as expected (my project built fine). Then I went to add the generate sources option, so I changed the xsd target to an executable, precisely this way:
FindXSD.cmake
if(NOT TARGET xsd)
add_executable(xsd IMPORTED)
target_include_directories(xsd INTERFACE ${_XSD_INCLUDE_DIR})
set_target_properties(xsd PROPERTIES IMPORTED_LOCATION ${_XSD_EXECUTABLE}
add_executable(xsd::xsd ALIAS xsd)
endif()
Then I referenced the target this way in one of the libraries (well, it was already like this before I switched from library to executable):
find_package(XSD EXACT ${XSD_PACKAGE_VERSION} REQUIRED)
target_link_libraries(my_target PUBLIC xsd::xsd)
and the compilation failed as xsd headers were not found. I tried to add this to see if it helps:
get_target_property(XSD_INCLUDES xsd::xsd INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(my_target PUBLIC ${XSD_INCLUDES})
and now the headers are found correctly, but it fails with
LINK : fatal error LNK1181: cannot open include file 'xsd.lib'
Why does it try to include .lib?
Why doesn't target_link_libraries automatically populate the correct include directories?
What is the proper way of handling such dependency?
My motivation to go with an imported executable instead of an imported interface library was so I can use CMake's substitution of xsd's executable path instead of using XSD_EXECUTABLE variable outside of the FindXSD.cmake.

What's the difference between passing a "xxx.a" file and a target to target_link_libraries()?

When I pass a target to target_link_libraries(), it worked fine.
But when I pass a .a file (the "worked fine target" produced), it worked fine while compiling but produced many errors while linking.
I have a project, and the CMakeFiles.txt is like this:
file (sources a.cc b.cc ...)
add_executable(my_project ${sources})
Now I want to produce a static library using the same source files to support another project.
So the CMakeFiles.txt is like this:
file (sources a.cc b.cc ...)
add_library(my_project ${sources})
add_executable(another_project main.cc)
target_link_libraries(another_project my_project)
It works fine, But when I try to link .a file directly like this
target_link_libraries(another_project libmy_project.a)
And it produced lots of "undefined reference to" or "multiple defination to" error when linking the target.
So what exactly happen when pass a target to "target_link_libraries"?
First, if you link the target against a file, you should first ensure this file exists before linking happens, thus you should add target dependencies between the executable and library targets (provided both are part of the same CMake project)
add_dependencies(another_project my_project)
Second, if you link against an arbitrary file (which is not any of the system libraries), you are supposed either provide full path to the file:
target_link_libraries(another_project ${CMAKE_CURRENT_BINARY_DIR}/libmy_project.a)
Or add the folder where the library is located to the current library search directories list:
link_directories(${CMAKE_CURRENT_BINARY_DIR})
target_link_libraries(another_project libmy_project.a)
So what exactly happen when pass a target to "target_link_libraries"?
Simply put, when CMake hits a reference to a library in a form of libName.a, it just adds -lName flag and lets the linker locate the library itself. The linker then fails, because it looks for corresponding archives under LIBRARY_PATH paths only by default.

C++ - Why is a Static Library unusable without source files?

So from what I understand, a static compiled mylib.a file should just be usable as plug-and-play. But I can't use it without the source code, I'm trying to avoid that.
I adapted this tutorial to compile using CMake with the following directory structure:
/
lib
libmy_math.a
main.cpp
my_math.h
my_math.cpp
CMakeLists.txt
The contents of the files are exactly as in the tutorial. The only added file is CMakeLists.txt which basically just runs the library compiling part before building:
CMakeLists.txt
cmake_minimum_required(VERSION 3.21)
project(Test)
### Uncomment this ONCE to compile a libmy_math.a file
# add_library(my_math STATIC my_math.cpp)
add_executable(Test main.cpp)
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
As the CMake file says, uncommenting Line 5 compiles the library, which is then linked to my code when compiling.
I'm trying to package my code so that I don't show my client the source code for the compiled library (my_math), but if I delete the my_math.h and my_math.cpp files, I get a "file not found" error on import:
/Users/Joe/Desktop/Test/main.cpp:1:10: fatal error: 'my_math.h' file not found
#include "my_math.h"
^~~~~~~~~~~
I thought you could compile libraries without needing the source code. What am I missing here?
A static library does not contain each and every definition a header can contain - think of macros, etc. Thus you still need the header. However, you don't need the .cpp anymore to link the library.
Besides the problem stated in Iorro's answer the find_library call here will not work as expected.
find_library(MY_MATH_LIB my_math HINTS ./lib)
target_link_libraries(Test PUBLIC ${MY_MATH_LIB})
What this does is, while running CMake, look for the my_math.a file. However, at that point of the build process, my_math.a has not been built yet. You're just running CMake for the first time, so all you have is source files. Nothing has been compiled yet.
What you want to do instead is link to the library target directly, as CMake already knows about that and can resolve the dependency on its own. So you need to replace the two lines above with:
target_link_libraries(Test PUBLIC my_math)
This now introduces a curious asymmetry in how your test consumes the library (as it is part of the same build) vs. how your clients consume the same library (which are not part of the same build and thus need to do a find_package call before they can use it). Look at CMake's config-file packages for a mechanism that allows you to restore symmetry here, at the cost of a significant amount of boilerplate required in your CMake script.

How to add opendnp3 as a static C++ library

I am currently trying to set up the opendnp3 C++ library as a static library. I've built the solution following their build guide for Windows and have been able to generate several .lib files which I assume to be the static libraries.
In a completely separate folder, I have the following files under the following folder structure:
C:/Development/C++/opendnp3/lib/ # .lib files are contained in this directory
C:/Development/pybexample/
--> CMakeLists.txt
--> src/
--> test.cpp
I have the CMakeLists.txt configured as follows:
cmake_minimum_required(VERSION 2.8)
project(pybexample)
set(SOURCE_FILES src/test.cpp)
add_library(opendnp3 STATIC IMPORTED)
set_target_properties(opendnp3 PROPERTIES IMPORTED_LOCATION C:/Development/C++/opendnp3/lib/opendnp3.lib)
add_executable(pybexample ${SOURCE_FILES})
target_link_libraries(pybexample opendnp3)
Within test.cpp, I am simply calling:
#include <iostream>
#include "opendnp3/LogLevels.h"
using namespace std;
int main(void) {
cout << "Hello world!" << endl;
system("pause");
}
However, when I try to build test.cpp, I receive an error indicating: "Cannot open include file: 'opendnp3/LogLevels.h': No such file or directory". I feel like there must be something pretty basic that I've missed but I'm pretty new to using static libraries and with CMake so I can't seem to figure it out. Would anyone be able to help give some pointers as to why my include is failing?
Turns out this was caused by two problems.
The first problem was that I needed to add a line to my CMakeLists.txt that would add the header files for opendnp3 to my project. This was accomplished by adding include_directories(<path_to_headers>) before the add_executable(pybexample ${SOURCE_FILES}) line.
However, in doing this, it also became clear that there was a second problem: I hadn't built the library properly as it didn't generate any headers with the library. Turns out I had overlooked the instructions to run the INSTALL project. After setting CMAKE_INSTALL_PREFIX and running the INSTALL project, the library and headers were generated and ready for use.

CMake unneeded dependency

I have a project using 3 CMakeLists.txt:
CMakeLists.txt C is my executable and depends on
CMakeLists.txt B which is a static lib and that depends on
CMakeLists.txt A which is also a static lib and depends on an external lib
In CMakeLists.txt C I specify my dependency against B using using target_link_libraries() and I do the same for the dependency of B against A. In CMakeLists.txt A I specify the dependency against the external lib.
I would expect this to work but C actually complains at link-time and I can only get it to work by specifying a dependency in C against the external lib.
Note that the external lib is dynamic (a .so file).
This looks weird to me, no? Anyone understands what is going on?
Thanks,
Antoine.
That should work. I bet there's a bug in the CMakeLists.txt.
View real dependencies
Check it with:
cmake .. --graphviz=deps.dot
xdot deps.dot
It will show a pretty picture of the dependency tree that cmake sees.
If you don't have xdot, export it to a png:
dot -Tpng deps.dot -o deps.png
firefox deps.png
Library not found ?
Another possibility is that the external library can't actually be found. Use find_library rather than just putting the library name:
find_library(FAIL failingmadly)
if (NOT FAIL)
message(FATAL_ERROR "Couldn't find the failingmadly library")
endif()
target_link_libraries(my_lib_a ${FAIL})
Position independent code?
Another possibility when linking static libs with dependencies on shared libs is the PIC complaints. You could add this in cmake before compiling anything:
add_definitions(-fPIC)
Good luck.