Using static library in a shared library created with CMake - cmake

I'm using a compiled library that I made, libexp.a. (Was compiled with PIC so its good for this use case).
I want to use it statically in my shared library and I can do that via Mixing static libraries and shared libraries.
So now I'm trying to get that working with CMake, my libexp.a is in the root directory and I do:
find_library(EXP NAMES exp PATHS ${PROJECT_SOURCE_DIR} NO_DEFAULT_PATH)
Then using it in target_link_libraries via ${EXP}, but during link time I still get a linking error of couldn't find -lexp. What is the right way to get this done? Using over 3.6

Related

How is CMake supposed to work for shared libraries?

I am trying to figure out how CMake is supposed to work for shared libraries. I create a shared library like so:
(in /mdp_opt/CMakeLists.txt:)
add_library (mdp_opt SHARED librarycomponent.cpp)
Now, a test executable uses this library:
(/test/CMakeLists.txt:)
add_executable (test test.cpp)
target_link_libraries(test PRIVATE mdp_opt)
If the library is marked STATIC (instead of SHARED as above), I can cmake -> built (under Visual Studio) and successfully run the executable. When it is marked SHARED (as in above), I need to do two things. First thing, is adding:
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
That is fine. However, now it still only works if I copy the file mdp_opt.dll from build/x64-debug/mdp_opt to build/x64-debug/test. But I don’t understand why this is needed?
In the book “professional CMake”, I read:
LINK_LIBRARIES
This target property holds a list of all libraries the target should
link to directly. It is initially empty when the target is created and
it supports generator expressions. An associated interface property
INTERFACE_LINK_LIBRARIES is supported. Each library listed can be one
of the following (emphasis mine):
• A path to a library, usually specified as an absolute path.
• Just the library name without a path, usually also without any
platform-specific file name prefix (e.g. lib) or suffix (e.g. .a, .so,
.dll).
• The name of a CMake library target. CMake will convert this to a
path to the built library when generating the linker command,
including supplying any prefix or suffix to the file name as
appropriate for the platform. Because CMake handles all the various
platform differences and paths on the project’s behalf, using a CMake
target name is generally the preferred method.
I was under the impression that
target_link_libraries(test PRIVATE mdp_opt)
expresses that I intend to link the output associated with the target mdp_opt with the test executable? Also, in my reading of the above book excerpt, my understanding is that the location of the .dll will convert to a path? If the purpose of this conversion is not to somehow tell the executable where to find the shared library, then what is that conversion for?
Basically, can anybody tell me how CMake is supposed to work for shared libraries, and why is works like that? Is a manual post-copy (possibly via CMake instructions) really needed, and the best for this scenario (of intermediate builds while developing)?
On windows you need to export symbols of a shared library or add a linker option that results in symbols being exported; otherwise the .lib file for linking the dll simply isn't generated. This is why you need
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
, use __declspec( dllexport ) or similar.
The other issue is the way windows locates dlls: It basically first searches the directory containing the executable and then continues the search via the PATH environment variable. This can result in issues locating the dll at runtime.
You can avoid this issue by setting the directory to place the runtime artefacts before generating the first one of the targets involved:
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
...
add_library(mdp_opt ...)
...
add_executable(test ...)
Alternatively you could simply change the environment variable visible to the vs debugger:
set_target_properties(test PROPERTIES VS_DEBUGGER_ENVIRONMENT "PATH=$<TARGET_FILE_DIR:mdp_opt>;$ENV{PATH}")
If you're working with CTest, there's also a similar property for tests: ENVIRONMENT
If the purpose of [target_link_libraryes] is not to somehow tell the executable where to find the shared library, then what is that conversion for?
You still need to link a dll, or more precisely the corresponding import library; this is what target_link_libraries does, in addition to adding build system dependencies, transferring some properties (e.g. include directories with PUBLIC visibility), ect.

cmake target_link_libraries - unwanted target

I have a problem with cmake target_link_libraries.
I have 3 libs. The first is static compiled, the second one (shared lib) link to it and the third one is an executable which use the second lib.
My problem is that my first lib is automatically added to the third lib and leads into a "object already defined" problem.
Is it possible to hide away the first lib from the third one?
I use cmake 3.4.x
Compiler: msvc 2010 x64
Thanks in advance
Tonka
Your third "lib" isn't a library, but an application. You need to add this using add_executable, not add_library.
If your shared library links in a static library, and then you want to link an application to both the static library and that shared library, you get two copies of the static library. Never link static libraries you plan to use elsewhere into a shared library, for this reason. Either make the first shared as well (the name implies that's what you want, as it is exactly what you are describing), or a workaround for this design problem could be to not explicitly link the application to the static library.
I've solved it. I can link to a library private, so f.e.
target_link_libraries(MyLib2 PRIVATE MyLib1)
will hide MyLib1 from everybody linking to MyLib2

Linking Shared library (which has dependency on other shared library) in CMake

I am trying to build an executable which links to a shared library (named 'caffe'). The shared library is dependent on another shared library (named 'cblas'). When I try to link to caffe in my CMake file it shows the following error:
libcblas.so.3, needed by libcaffe.so, not found (try using -rpath or
-rpath-link)
I am using the following statements in my CMakeLists.txt:
link_directories(${BINARIES}/lib)
add_library(CAFFE_LIBRARY SHARED IMPORTED)
set_target_properties(CAFFE_LIBRARY PROPERTIES IMPORTED_LOCATION ${BINARIES}/lib/libcaffe.so)
target_link_libraries(${PROJECT_NAME} CAFFE_LIBRARY)
Both 'cblas' and 'caffe' libraries are present in ${BINARIES}/lib folder.
Do I need to add cblas.so to target_link_libraries also? Also, i am not building caffe.so so building it via CMake and keeping it as a dependency is not an option
Is there any other feasible solution for the same problem where dependency tree of shared library needs to be resolved while linking?
Browsing through the library's GitHub tree, it seems to me that it provides a package config file. Therefore, if you have installed it in the normal way, you should be able to find it as a package, instead of defining the imported target yourself:
find_package(Caffe)
include_directories(${Caffe_INCLUDE_DIRS})
add_definitions(${Caffe_DEFINITIONS}) # ex. -DCPU_ONLY
add_executable(caffeinated_application main.cpp)
target_link_libraries(caffeinated_application ${Caffe_LIBRARIES})
The example above comes from the Caffe documentation on the topic.

How to make CMake find real static libraries instead of dynamic wrappers?

I use find_package to include external library into my CMake project. Because I wanted to add support for static linking, I set set(BUILD_SHARED_LIBS FALSE). However, I still get libraries like libglew32.dll.a which are just wrappers that make dynamic linking easier. Instead, I want CMake to find libglew32.a which exists in the same directory. This is the module to find GLEW I use.
You can always link to an exact library using the filename. Here are the flags you would use
-l:[filename]
For cmake
target_link_libraries(target :libglew32.a)
Doing this on linux will use all static libraries
set(CMAKE_FIND_LIBRARY_SUFFIXES .a ${CMAKE_FIND_LIBRARY_SUFFIXES})
if you are building external libraries, usually i just include them in my target
target_link_libraries(myprogram
${LIBROCKET_LIBS_DIRS}/libRocketCore.a
${LIBROCKET_LIBS_DIRS}/libRocketControls.a)

CMake: add static library to shared lib

I would like to create shared library with cmake, but also I need to link it to third party static libraries.
For example if it should include my own file1.o, file2.o, then statically linked libfoo.la and then be written down to disk as .so file which dynamically linked to libbar.so
Is it even possible?
It is possible to link static library to shared library. On most Unixes, you will need
to add -fPIC flag or its equivalent for producing position-independent code when you build static library. On Windows, there is no PIC, i.e linking static to shared just works out of the box.