When I try to build gRPC as a static library everything works fine. Nevertheless, I have link troubles when build it as a shared lib.
option(BUILD_SHARED_LIBS "build shared libraries" ON)
include(FetchContent)
FetchContent_Declare(
grpc
GIT_REPOSITORY https://github.com/grpc/grpc.git
GIT_TAG v1.49.1)
set(FETCHCONTENT_QUIET OFF)
FetchContent_MakeAvailable(grpc)
protoc-3.21.6.0: error while loading shared libraries: libprotocd.so.32: cannot open shared object file: No such file or directory
This error occurs during execution script via add_custom_command inside the grpc
I believe that the error message is pretty clear:
protoc-3.21.6.0: error while loading shared libraries: libprotocd.so.32: cannot open shared object file: No such file or directory
To build the shared library of gRPC you also need the shared libraries for the protocol buffer compiler i.e. protoc. I would start by building the shared libraries of protoc.
If you are sure that you have them then I would check that CMake can correctly find them (by either checking if they are in the standard system paths or by appending the location of the .cmake file using CMAKE_MODULE_PATH)
Hope it helps.
Related
I have a program that depends on an external library (SDL for example). I want CMake to take care of that dependency for me, so I was looking into FetchContent. As far as I understand, this module simply downloads the source code so that information on the external library is available at configure time. For example:
include(FetchContent)
FetchContent_Declare(sdl
GIT_REPOSITORY <...>
)
FetchContent_GetProperties(sdl)
# sdl_POPULATED, sdl_SOURCE_DIR and sdl_BINARY_DIR are ready now
if(NOT sdl_POPULATED)
FetchContent_Populate(sdl)
endif()
At some point, however, I want to build that source code and link it to my main executable. How to do it the "modern CMake way"?
The recommended way to build external libraries from source as part of your build depends on what the external lib provides build-wise.
External lib builds with cmake
If the external lib builds with cmake then you could add the lib to your build via a add_subdirectory(${libname_SOURCE_DIR}) call. That way cmake will build the external lib as a subfolder ("subproject"). The CMakeLists.txt file of the external lib will have some add_library(ext_lib_name ...) statements in it. In order to then use the external lib in your targets (an application or library that depends on the external lib) you can simply call target_link_libraries(your_application <PRIVATE|PUBLIC|INTERFACE> ext_lib_name) https://cmake.org/cmake/help/latest/command/target_link_libraries.html
I had a quick look at this github repo https://github.com/rantoniello/sdl - (let me know if you are referring to another library) and it actually looks like it is building with cmake and that it allows clients to statically or dynamically link against it: https://github.com/rantoniello/sdl/blob/master/CMakeLists.txt#L1688-L1740
So, ideally your applicaiton should be able to do
add_executable(myapp ...)
target_link_libraries(myapp PRIVATE SDL2-static) // Statically link againt SDL2
Due to their CMakeLists.txt file the SDL2-static comes with properties (include directories, linker flags/commands) that will automatically propergate to myapp.
External lib does not build with cmake
If a external lib doesn't build with cmake then one can try to use add_custom_target https://cmake.org/cmake/help/latest/command/add_custom_target.html to build the library. Something along the lines of:
add_custom_target(myExternalTarget COMMAND <invoke the repo's build system>)
You'd then need to set the target properties that are important for clients yourself via the the proper cmake functions set_target_properties, target_include_directories ... A great writeup how to get started with these kinds of things: https://pabloariasal.github.io/2018/02/19/its-time-to-do-cmake-right/
I’m using LibTorch and OpenCV for a program in Cpp. The compilation and building is done on Linux using CMake. The program builds and runs as expected.
I want to use the executable that CMake created on another Linux machine.
The problem is that I don’t want to install either LibTorch nor OpenCV on the other machine. I’d rather supply the user with a single executable if possible.
How can CMake create a single independent executable?
If making just a single file is irrelevant, how can CMake copy all needed libraries to a single directory?
The current CMake file:
cmake_minimum_required(VERSION 2.8)
project(prediction)
list(APPEND CMAKE_PREFIX_PATH “libtorch”) # the folder where libtorch in found
set(CMAKE_BUILD_TYPE Release)
find_package( OpenCV REQUIRED )
find_package( Torch REQUIRED )
if(NOT Torch_FOUND)
message(FATAL_ERROR “Pytorch Not Found!”)
endif(NOT Torch_FOUND)
message(STATUS “Pytorch status:”)
message(STATUS " libraries: ${TORCH_LIBRARIES}")
message(STATUS “OpenCV library status:”)
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
file(GLOB SOURCES ".h" ".cpp") # Link all headers and sources in root dir
include_directories( ${OpenCV_INCLUDE_DIRS} )
add_executable(entrypoint ${SOURCES})
target_link_libraries(entrypoint ${TORCH_LIBRARIES} ${OpenCV_LIBS})
set_property(TARGET entrypoint PROPERTY CXX_STANDARD 14)
####### EDIT
Thanks for the answers.
Following Phesho_T answer bellow, I got the static compilation of LibTorch, but it won't compile with the set() instruction. It throws C10_LIBRARY NOTFOUND.
I think I'll try to use the shared libraries. How can CMake be instructed to copy the releveant shared libraries to the "build" folder, so I can pack everything in a .zip file and send it to the user.
Like another answer said, you need to link the static libs of Torch and OpenCV in your executable.
There are a few pre-requisites for this:
The two libraries need to have static (.a) libraries installed on your system. If they don't, you may have to manually build them. Steps for this differ between different packages.
You need to tell CMake to search for the static libraries ONLY. This is done via the CMAKE_FIND_LIBRARY_SUFFIXES variable. The chances are the default for this is .so;.a, meaning it will find the shared library first.
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
The fact that you're using variables in your target_link_libraries command, instead of imported libraries (the modern CMake way) makes me think that this should be enough - these variables should expand to full paths to the static libraries, which should then be added to your linker command.
Things are a bit more complicated to explain if imported targets were used, but this might be out-of-scope for this question.
Try it out and let us know how you get on.
To create a single executable you need to statically link the dependencies into your executable. Check your libraries to see if they provide static-libs else you need to recompile libtorch or opencv to make static libraries.
Lately, I have been using cmake as a generator for my projects. I have successfully generated many vtk and other application projects. However, I now face a problem when trying to link both dynamic and static precompiled libraries. In particular, I have been given some dynamic precompiled third party dlls along with their respective .lib files. Furthermore, I am trying to link some static precompiled libraries (only .lib files) to my project so as to check the software licences.
Let say that my project is called test_example and I have some precompiled dynamic libraries in libs directory. The structure of my project directory is:
Test_example
-/include
-/libs
-/build
-CMakeLists.txt
The CMakeLists.txt for linking the dynamic libaries has the following content:
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
set (PROJECT_LINK_LIBS dynamic_1.dll dynamic_2.dll )
set (PROJECT_LINK_DIR ${test_example_SOURCE_DIR}/libs/)
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
link_directories(${PROJECT_LINK_DIR})
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${PROJECT_LINK_LIBS})
When I generate the project with this cmake lists, I can successfully use methods from the precompiled dlls. However, I have not found a way to link against my static libraries, as well. Let say I have one static library which is called test_licence.lib. Should I drop it in the libs folder as well and simply refer to it like I do with the dynamic? When I do so and when opening my project solution in Visual Studio, I can see that both dynamic and static libraries have been added to Linker-->Input-->Additional DEpendencies. However, when I am trying to build the project, I have unresolved external dependencies which are methods from the static lib.
Does any of you have any idea what would be the most efficient way to accomplish that? Many thanks in advance!
There is a couple of issues here.
Unlike to what you may be used to from VS, CMake prefers absolute paths for linking, instead of setting a link directory and giving the relative path.
Also, you do not link against .dll files. Dlls are loaded at runtime, not at link time. Many dlls are shipped with import libraries (with a .lib ending), that handle the runtime loading automatically for you. These are the ones you should link against.
Also try not to hardcode libraries in CMake code. The problem here is that if something goes wrong, you end up with a cryptic linker error. You should use find_library instead, which will usually make CMake complain early if something is off.
A cleaner version of your CMake script would be something like
cmake_minimum_required(VERSION 2.8.9)
project (test_example)
# note setting the build type does nothing on a visual studio build
# and should probably be left to the user for other generators
set(CMAKE_BUILD_TYPE Release)
#For the shared libraries:
# this call will succeed if it finds a dynamic_1.lib file
find_library(DYNAMIC_LIB1 dynamic_1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB1)
message(FATAL_ERROR "Library dynamic_1 was not found!")
endif()
find_library(DYNAMIC_LIB2 dynamic_2 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT DYNAMIC_LIB2)
message(FATAL_ERROR "Library dynamic_2 was not found!")
endif()
# for the static libraries:
# basically the same; again this looks for a static_1.lib file
find_library(STATIC_LIB1 static1 HINTS ${test_example_SOURCE_DIR}/libs)
if(NOT STATIC_LIB1)
message(FATAL_ERROR "Library static_1 was not found!")
endif()
set (PROJECT_INCLUDE_DIR ${test_example_SOURCE_DIR}/include/)
include_directories(${PROJECT_INCLUDE_DIR})
add_executable(test_example test_example.cpp)
target_link_libraries(test_example ${DYNAMIC_LIB1} ${DYNAMIC_LIB2} ${STATIC_LIB1})
Double check in Visual Studio that all libraries were added as linker inputs, as expected. If you still get linker errors, it means that something is wrong with your third-party .lib file. Open a new question with the exact linker error that you get.
Here is how we are doing it:
Firstly, use add_library with final arguments STATIC IMPORTED. Then subsequently use set_property to set the IMPORTED_LOCATION property, which is a path to the built library. For example, we pull in gtest like so:
add_library(gtest UNKNOWN IMPORTED)
set_property(TARGET gtest PROPERTY IMPORTED_LOCATION ${binary_dir}/googlemock/gtest/${CMAKE_FIND_LIBRARY_PREFIXES}gtest.a)
Then, gtest is a known library in your build system and you can link with it normally later on by just doing
target_link_libraries(target-name gtest)
See also: Cmake imported libraries documenation
In Ubuntu, I have downloaded a third-party shared library, mylibrary.so, which I have placed in the directory /home/karnivaurus/Libraries. I have also placed the associated header file, myheader.h, in the directory /home/karnivaurus/Headers. I now want to link to this library in my C++ code, using CMake. Here is my CMakeLists.txt file:
cmake_minimum_required(VERSION 2.0.0)
project(DemoProject)
include_directories(/home/karnivaurus/Headers)
add_executable(demo demo.cpp)
target_link_libraries(demo /home/karnivaurus/Libraries/mylibrary)
However, this gives me the error message:
:-1: error: No rule to make target `/home/karnivaurus/Libraries/mylibrary', needed by `demo'. Stop.
What's going on?
While the other answer posted here is valid, it is out-dated. CMake now provides better solutions for using a pre-built external library in your code. In fact, CMake itself even discourages the use of link_directories() in its documentation.
The target_link_libraries() command takes very specific syntax for linking to an external library. A more modern solution is to create an IMPORTED CMake target for your external library:
add_library(MyExternalLib SHARED IMPORTED)
# Provide the full path to the library, so CMake knows where to find it.
set_target_properties(MyExternalLib PROPERTIES IMPORTED_LOCATION /home/karnivaurus/Libraries/mylibrary.so)
You can then use this imported CMake target later on in your code, and link it to your other targets:
target_link_libraries(demo PRIVATE MyExternalLib)
For other ways to use an external third-party library in your CMake code, see the responses here.
You may use a full path to the static library. To link w/ dynamic one, better to use link_directories() like this:
cmake_minimum_required(VERSION 2.0.0)
project(DemoProject)
include_directories(/home/karnivaurus/Headers)
link_directories(/home/karnivaurus/Libraries)
add_executable(demo demo.cpp)
target_link_libraries(demo mylibrary)
and make sure mylibrary has prefix lib and suffix .so in file name (i.e. full name is /home/karnivaurus/Libraries/libmylibrary.so).
To make you project more flexible, you'd better to write a finder module and avoid hardcode paths like /home/karnivaurus/*
The output of my cmake is a static library. I'm creating it as such:
add_library(myMainLib STATIC ${BACKEND_SOURCES})
Problems arise when I try to get myMainLib to link against a third party lib/dll. The dll file will be found at run time, however, I'm trying to import/link against the lib file, with no success. My third party library is SDL2 and SDL2 NET.
I would think this is straight forward and have exhausted all methods I've found online. All fail. A list of what I've tried is below. Please inform me what I'm doing wrong.
Simple method, using target_link_libraries
add_library(myMainLib STATIC ${BACKEND_SOURCES})
target_link_libraries(myMainLib path_to_thirdPartyLib/thirdParty.lib)
According to cmake docs
add_library(myMainLib STATIC ${BACKEND_SOURCES})
add_library(Third_Party SHARED IMPORTED)
set_property(TARGET Third_Party PROPERTY IMPORTED_LOCATION path_to_thirdPartyLib/thirdParty.dll)
set_property(TARGET Third_Party PROPERTY IMPORTED_IMPLIB path_to_thirdPartyLib/thirdParty.lib)
target_link_libraries(myMainLib Third_Party)
Set path to library using link directories
add_library(myMainLib STATIC ${BACKEND_SOURCES})
set(LIB_DIR path_to_thirdPartyLib)
LINK_DIRECTORIES(${LIB_DIR})
target_link_libraries(myMainLib ${LIB_DIR}/thirdParty.lib)
Try finding the library
add_library(myMainLib STATIC ${BACKEND_SOURCES})
find_library(Third_Party thirdParty.lib)
if(Third_Party)
#never gets in here
target_link_libraries(myMainLib ${Third_Party})
endif()
In CMake and several build systems directly linking a static library into another static library is meaningless. You can build a static library and a second one and have your executable project linked against both, but it's not possible to link the first static library with the second library and then link them into the final executable. Although VS allows that, it doesn't make sense for other build systems and thus CMake refrains from it.
Some solutions involve making your static library a shared one or pull the library sources into the executable.
Other details here