cmake link against dll/lib - c++

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

Related

Linking both third party precompiled dynamic and static libaries in Windows

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

creating a static library and linking using Cmake

I have a application which need to use two libraries (pugixml and lua) and need to be an multi-platform build capable. I am trying to use Cmake for this. Since I have three different solution (two for creating static libraries and one solution which actually uses that libraries). So far what I do is run Cmake for those two libraries and copy those static libraries manually to the lib folder into application and run cmake again.
I need to reduce the three step and make it as a single step so that I can handle the multi-platform build in a single shot.
I need to know, should we need to create a dynamic link library or shared library or static library for these kind of operation?
And need help on how to do it. I tried creating the source folder of pugixml and copy the cpp/hpp/h file and wrote a cmakelists file like
set(HEADERS pugixml.hpp pugiconfig.hpp)
set(SOURCES ${HEADERS} pugixml.cpp)
add_library(pugixmlLib STATIC ${SOURCES})
target_link_libraries(pugixmlLib pugixml)
On the solution I could see my application project and pugixml project, but on my application project linker property I could find pugixml library.

how to add library source in cmake

i can't seem to find in google/stackoverflow how do i add a library to my project using the library sources so that in make time it will compile the library and then my project and then link between them.
the library i'm trying to add is curlpp
as of now I've tried the following:
add_library(curlpp STATIC IMPORTED ./curlpp)
target_link_libraries(myExec curlpp)
link_directories(./curlpp/src/)
include_directories(./curlpp/includes)
but it has no effect
You first need to add the subdirectory to actually build the library, then you can add the actual library for linking.
If the library is not a CMake project you might need to add a simple CmakeLists.txt file in the library, that executes the actual configuration and building.
You might also use custom commands from the top-level CMakeLists.txt file to configure/build the library.
Basing off on Some programmer dude's response the following commands allowed me to statically link with curlpp:
add_subdirectory(./vendor/curlpp)
set_property(TARGET curlpp PROPERTY IMPORTED_LOCATION ./vendor/curlpp/libcurlpp.a)
target_link_libraries(my_target curlpp)

"No rule to make target" error in cmake when linking to shared library

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/*

Linking a static library to a shared library in cmake

I have been working on a fun project (a game engine) for awhile now and figured i could make it more portable and easy to compile across platforms if I use cmake. Right now i have it set up like so, with a main executable and then a bunch of shared libraries that the executable is linked to. I've found all the material needed to produce the libraries and the executable, and linking those to the executable, but what of linking a dependency like a static library or another shared library to one of the libraries i produce? Here is a visual
Sentiment (name of project)
-Root (all the interfaces and components of the engine. main.cpp is here
-Sentiment_OGL4Renderer (the files for the Renderer library)
-Sentiment_SFMLGui (the files for the Gui library)
-Sentiment_TestGame (the code for a game)
now i want all of these, the executable and the shared libraries built and put into the bin folder in the top level directory. What i found suggested online for a setup like this was to make cmakelists.txt files in each folder, and then one in the root, for each project. What i have thus far is this.
#Sentiment
cmake_minimum_required(VERSION 2.6)
project(Sentiment)
set(RENDERER Sentiment_OGL4Renderer)
set(GUI Sentiment_SFMLGui)
set(GAME Test_Game)
add_definitions(-DBUILD_DLL)
list( APPEND CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS} -g -ftest-coverage -fprofile-arcs")
set(EXECUTABLE_OUTPUT_PATH "${Sentiment_SOURCE_DIR}/bin")
set(LIBRARY_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}")
link_directories("${LIBRARY_OUTPUT_PATH}")
add_subdirectory("${RENDERER}")
add_subdirectory("${GUI}")
add_subdirectory("${GAME}")
add_subdirectory(Root)
in root
project(Sentiment_exe)
link_directories("${Sentiment_SOURCE_DIR}/bin")
AUX_SOURCE_DIRECTORY(. new_source_list)
add_executable("${CMAKE_PROJECT_NAME}" ${new_source_list})
target_link_libraries("${CMAKE_PROJECT_NAME}" "${LIBRARY_OUTPUT_PATH}/${RENDERER}" "${LIBRARY_OUPUT_PATH}/${GUI}" "${LIBRARY_OUTPUT_PATH}/${GAME}" "${ADDITIONAL_DEPENDENCIES}")
in Sentiment_OGL4Renderer
project(Sentiment_OGL4-3Renderer)
include_directories(${Sentiment_SOURCE_DIR})
add_definitions(-DGLEW_STATIC)
add_library(Sentiment_OGL4-3Renderer SHARED Sentiment_OGL4Renderer.cpp GL/glew.cpp)
in Sentiment_SFMLGui
project(Sentiment_SFMLGui)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_SFMLGui SHARED Sentiment_SFMLGui.cpp)
in Sentiment_TestGame
project(Sentiment_Game)
include_directories(${Sentiment_SOURCE_DIR})
add_library(Sentiment_Game SHARED Game.cpp)
As you can tell there are a lot of third party libraries, and i tried various methods of linking, like with target_link_libraries, and i cannot for the life of me figure how to link an external library to the ones i've made. First off, the renderer uses GLEW but it needs no external dependency so ignore that. Then it needs OpenGL32.lib and Gdi32.lib from the windows sdk (only for windows). As for SFML, i've got the DLL's in the bin folder which need to be linked, (can easily get the .so's when working in linux and can distribute with the final product if I ever choose to do so). I need these all linked as dependencies to the libraries i create, but nothing seems to work. The project is all c++ and I am currently using mingw32 to compile it. I'm brand new to cmake so please be gentle if it is really simple.
To link external libraries, best practice is to use or create FindModule for given external library.
CMake comes with numerous modules that aid in finding various well-known libraries and packages.
The list of standard modules is in the official documentation
In case there is no standard module for your external library, you should write your own.
The OpenGL library has standard module FindOpenGL:
find_package (OpenGL)
if (OPENGL_FOUND)
include_directories(${OPENGL_INCLUDE_DIR})
target_link_libraries (Sentiment_OGL4-3Renderer ${OPENGL_gl_LIBRARY})
endif (OPENGL_FOUND)