How to properly link to libraries in CMake (using Boehm GC)? - c++

I've been trying to figure this out for a while, but can't seem to get it working. I've already checked a bunch of posts.
I have a static library libRuntime.a, generated like so:
cmake_minimum_required(VERSION 3.15)
project(Runtime)
set(CMAKE_CXX_STANDARD 17)
add_library(Runtime library.cpp)
find_library(GC gc)
message(${GC})
target_link_libraries(Runtime PUBLIC ${GC})
library.cpp uses Boehm GC, which is why I'm also linking it with my Runtime target.
Now, I want to call functions from my libRuntime.a, so I have the following other CMake project:
cmake_minimum_required(VERSION 3.15)
project(test)
set(CMAKE_CXX_STANDARD 17)
add_executable(test main.cpp)
find_library(TESTLIB Runtime lib)
message(${TESTLIB})
target_link_libraries(test ${TESTLIB})
I have pasted library.h into the project, and also pasted libRuntime.a into a directory called lib, so the definitions are known and the library is found. Calling functions from my Runtime library now gives me:
/path.../Scheme-Compiler/Runtime/library.cpp:12: undefined reference to `GC_init'
/usr/bin/ld: ../lib/libRuntime.a(library.cpp.o): in function `alloc_atom':
Thanks in advance

Because you use a separate CMake invocation to create the executable, the properties of the Runtime CMake target from your first project are not known. Specifically, CMake will not know any of the Runtime library's dependencies (i.e. GC), so you have to list them explicitly when linking Runtime to your executable:
cmake_minimum_required(VERSION 3.15)
project(test)
set(CMAKE_CXX_STANDARD 17)
add_executable(test main.cpp)
find_library(TESTLIB Runtime lib)
message(${TESTLIB})
# Find GC library.
find_library(GC gc)
# Link GC here, along with the Runtime library.
target_link_libraries(test PRIVATE ${GC} ${TESTLIB})

Related

pybind11 and another libs in one project [duplicate]

I want to be able to call my C++ code as a python package. To do this I am using pybind11 with CMakelists (following this example https://github.com/pybind/cmake_example). My problem is that I have to include GSL libraries in the compilation of the code, and these need an explicit linker -lgsl .
If I were just to compile and run the C++ without wrapping it with python, the following Cmakelists.txt file does the job
cmake_minimum_required(VERSION 3.0)
set(CMAKE_BUILD_TYPE Debug)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
project(myProject)
add_executable(
myexecutable
main.cpp
function1.cpp
)
find_package(GSL REQUIRED)
target_link_libraries(myexecutable GSL::gsl GSL::gslcblas)
but when using pybind11 the template I found doesn't allow the add_executable therefore target_link_libraries doesn't work.
I have trie this
project(myProject)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED YES) # See below (1)
# Set source directory
set(SOURCE_DIR "project")
# Tell CMake that headers are also in SOURCE_DIR
include_directories(${SOURCE_DIR})
set(SOURCES "${SOURCE_DIR}/functions.cpp")
# Generate Python module
add_subdirectory(lib/pybind11)
pybind11_add_module(namr ${SOURCES} "${SOURCE_DIR}/bindings.cpp")
FIND_PACKAGE(GSL REQUIRED)
target_link_libraries(GSL::gsl GSL::gslcblas)
but this produces errors in the building.
Any idea ?
Function pybind11_add_module creates a library target, which can be used for link added module with other libraries:
pybind11_add_module(namr ${SOURCES} "${SOURCE_DIR}/bindings.cpp")
target_link_libraries(namr PUBLIC GSL::gsl GSL::gslcblas)
This is explicitely stated in documentation:
This function behaves very much like CMake’s builtin add_library (in fact, it’s a wrapper function around that command). It will add a library target called <name> to be built from the listed source files. In addition, it will take care of all the Python-specific compiler and linker flags as well as the OS- and Python-version-specific file extension. The produced target <name> can be further manipulated with regular CMake commands.

Undefined Reference in self-built shared library with cmake

I am currently trying to utilize a self-built shared library. The Library FooBar utilizes the "Foo" Library to do some costly calculations. "Foo" however needs "Bar", the licensing library. It has been successfully cross-compiled when using the following CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(FooBar LANGUAGES CXX)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(THREADS_PREFER_PTHREAD_FLAG ON)
find_package(Threads REQUIRED)
find_library(Curl
NAMES curl)
find_library(Foo
NAMES foo)
find_library(Bar
NAMES bar)
file(GLOB OBJECT_FILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/resources/*.o)
file(GLOB SOURCE_FILES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/*.cpp)
add_library(FooBar SHARED ${SOURCE_FILES} ${OBJECT_FILES})
target_link_libraries(FooBar PRIVATE Threads::Threads)
target_link_libraries(FooBar PRIVATE -L${Foo} -L${Bar} -L${Curl})
The compilation is successful without any errors but when I want to include it in the executable, "FooBar" does give me an undefined reference to an function in "Bar", the licensing library. I already checked the "Bar"-library, it contains the used function!
CMakeLists.txt of the executable:
cmake_minimum_required(VERSION 3.12)
project(FooBarExe)
add_subdirectory(FooBar)
add_executable(FooBarExe ${FooBarExe_SRC} ${FooBarExe_INC}) # FooBarExe is just the placeholder for its original name!
target_link_libraries(FooBarExe PRIVATE FooBar)
Error message:
"FooBarExe/FooBar/FooBar.so: undefined reference to 'function'
collect2: error: ld returned 1 exit status"
Does anyone have another idea to solve this issue? I already reordered the libraries in target_link_libraries, compiled it as a static library, included and linked both libraries to FooBarExe via set_target_properties and INTERFACE_LINK_LIBRARIES without any success...
Edit:
I tried the following suggested solutions:
Removing "-L" when adding Library
Added a Check after the find_library(Bar ...)
There was an interface change in the "Bar" Library, which went unnoticed by me. Had to replace the header file and the library. Found the change by looking deeper into the library, using the nm -gDC xxxx.so command.
Thank you all for your help, the error was done by me...

How to build static library with bundled dependencies - CMake

I am currently using CMake to create a static library which utilizes a few of the static libraries from OpenCV 4 ( core imgcodecs video highgui imgproc ). My intention is to be able to bundle all of the required OpenCV static libraries into my own library so that I can distribute it as one library. Additionally, I want for the user of my library to not have to install OpenCV 4 on their system (but do not mind if the user has to do simple installs using apt-get install). I know there are tools for bundling static libraries (such as using ar for linux).
However, where I really am having the issue is with all the dependencies of OpenCV (such as libjpeg, libpng, etc). I don't necessarily mind if these libraries are bundled with mine or linked dynamically as they are relatively easy to install (can be installed with sudo apt-get install, whereas opencv4 needs to be built from source).
What is the best way to go about doing this?
This is my current CMakeLists.txt
It is currently working, but that is because I am using find_package(OpenCV REQUIRED) (which defeats the purpose of what I am trying to do). When I remove that line, the linker complains about not being able to find the OpenCV dependencies.
cmake_minimum_required(VERSION 2.8)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
list(APPEND LINKER_LIBS opencv_core opencv_highgui opencv_video opencv_imgcodecs libmxnet.so libncnn.a nlohmann_json::nlohmann_json)
file(GLOB SRC${CMAKE_CURRENT_LIST_DIR}/src/*.cpp${CMAKE_CURRENT_LIST_DIR}/main.cpp)
add_library(myproject ${SRC})
target_link_libraries(myproject ${LINKER_LIBS} ${OpenMP_CXX_FLAGS})
To elaborate on my question. I build my project which generates libmyproject.a. I then take this library and will eventually extract the symbols from the OpenCV libs (libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a) and add them to my lib (for the time being, I have not yet done this step, which is why in the below example I am linking libopencv_*). I then use my library in a new project, for which the CMakeLists.txt is shown below:
cmake_minimum_required(VERSION 2.8)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
include_directories(${CMAKE_CURRENT_LIST_DIR}/include)
link_directories(${CMAKE_CURRENT_LIST_DIR}/lib)
find_package(OpenMP REQUIRED)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver myproject libncnn.a ${OpenMP_CXX_FLAGS} libmxnet.so libopencv_core.a libopencv_highgui.a libopencv_imgcodecs.a libopencv_video.a)
Building this generates the following errors:
Linking CXX executable myproject-driver
/usr/bin/ld: /home/nchafni/Cyrus/myproject/lib/libopencv_imgcodecs.a(grfmt_jpeg.cpp.o): undefined reference to symbol 'jpeg_default_qtables##LIBJPEG_8.0'
//usr/lib/x86_64-linux-gnu/libjpeg.so.8: error adding symbols: DSO missing from command line
collect2: error: ld returned 1 exit status
How can I fix this. Is there some CMake command which will link all these dependencies for me? Do I need to manually track down each dependency of those libopencv_* libs and link those manually? Once again, this is assuming that the person using libmyproject.a can't use find_package(OpenCV REQUIRED) as it won't be defined as they have not installed OpenCV on their machine.
First of all, don't use the super old and outdated version 2.8 of CMake. CMake 3.x is so much more powerful and pretty straightforward to use.
Some tips for modern CMake.
Don't use file(GLOB), see here why that is.
Don't use directory wide instructions, rather use target instructions, e.g. target_include_directories vs. include_directories.
Don't use string variables like ${<PACKAGE_NAME>_LIBRARIES}, rather use targets, e.g. <Package_NAME>::lib
When using targets instead of string variables, all the properties (including LINK_INTERFACE) of that target will be populated to the library/executable when calling target_link_libraries, so no more include_directories,link_directories, etc.
myproject
cmake_minimum_required(VERSION 3.14)
project(myproject)
set(CMAKE_CXX_STANDARD 14)
find_package(OpenMP REQUIRED)
find_package(OpenCV REQUIRED)
set(JSON_BuildTests OFF CACHE INTERNAL "")
add_subdirectory(nlohmann_json)
set(SOURCES ...) # list all the source files here
add_library(myproject ${SOURCES})
target_include_directories(myproject PUBLIC # give it a scope
${CMAKE_CURRENT_LIST_DIR}/include
)
target_link_libraries(myproject PUBLIC # give it a scope
opencv_core # using the target, you will get all LINK_LIBRARIES
opencv_highgui
opencv_video
opencv_imgcodecs
libmxnet.so # where is this coming from?
libncnn.a # where is this coming from?
nlohmann_json::nlohmann_json
OpenMP::OpenMP_CXX ## linking against a target, CXX_FLAGS will be populated automatically
)
myprojec-driver
cmake_minimum_required(VERSION 3.14)
project(myproject-driver)
set(CMAKE_CXX_STANDARD 14)
add_executable(myproject-driver main.cpp)
target_link_libraries(myproject-driver PUBLIC # give it a scope
myproject # gets all dependencies through the LINK_INTERFACE
)

CMake - Can't link shared library (subdirectory)

I am using CLion and mingw-w64.
My executable's CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(test_exe)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "D:\\test")
add_subdirectory(test_lib)
include_directories(test_lib/include;test_lib/deps/include)
link_directories(test_lib/deps/lib)
add_executable(test_exe main.cpp)
target_link_libraries(test_exe test_lib)
test_lib's CMakeLists.txt:
cmake_minimum_required(VERSION 3.12)
project(test_lib)
set(CMAKE_CXX_STANDARD 17)
include_directories(include;deps/include)
link_directories(deps/lib)
file(GLOB_RECURSE LIB_SOURCES "include/*.*" "src/*.*")
add_library(test_lib SHARED ${LIB_SOURCES})
target_link_libraries(test_lib libfreetype.a libpugixml.dll.a)
The problem is that when I add library with add_library(test_lib SHARED ${LIB_SOURCES}) I get undefined reference errors but when I add the library with add_library(test_lib ${LIB_SOURCES}) it works perfectly.
An empty project links as expected (both SHARED and STATIC) but I wonder why this one is not working? Because of the libraries I link in the test_lib's CMakeLists.txt?
When you build a static library, there is no linking taking place. It doesn't check that you have all required libraries.
When you do the same for shared librarie,s then on some platforms (like Windows, or on Linux with -X defs, I think), you need to solve all references.
And you have a shared library.

linking to self created dll fails

using CLION i did create a very basic "C++ Library" containing only one function. Library Type is "shared".
in Library.h there is only a
void hello();
function declaration.
Library.cpp contains the definition
void hello(){std::cout << "hello";}
When i compile it, i get 2 files: libLibrary.dll and libLibrary.dll.a.
Here comes my problem. When i create a new Project named Test (an executable), i can include the Library.h file with no problems. But it wont compile due to an "undefined reference to `hello()'" which is no surprise, because i did not link to the created DLL-File. I added "target_link_libraries" to the CMakeLists.txt and copied both DLL-Files to the same directory where the executable is to be build.
The CMakeLists file looks as follow:
cmake_minimum_required(VERSION 3.12)
project(Test)
set(CMAKE_CXX_STANDARD 17)
add_executable(Test main.cpp)
target_link_libraries(Test Library)
its always the same error-message:
C:/PROGRA~2/MINGW-~1/bin/../lib/gcc/i686-w64-mingw32/8.1.0/../../../../i686/w64-mingw32/bin/ld.exe: cannot find -lLibrary
I did also try
target_link_libraries(Test libLibrary)
target_link_libraries(Test -libLibrary)
target_link_libraries(Test -Library)
target_link_libraries(Test libLibrary.dll)
target_link_libraries(Test Library.dll)
target_link_libraries(Test -libLibrary.dll)
...to no avail.
What did i miss?
i could finally link against the .dll-File by specifying the concrete location of the .dll-file, as #drescherjm suggested. Here linking to the .dll-File was successful with the command
target_link_libraries(Test ${CMAKE_BINARY_DIR}/libLibrary.dll)