Creating a shared library with existing static library - cmake

I want to create a shared library with 'sqlite3(SHARED)' and 'glog(STATIC)' installed.
add_library(sqlite3 SHARED IMPORTED)
add_library(glog STATIC IMPORTED)
set_target_properties(sqlite3 PROPERTIES IMPORTED_LOCATION /usr/local/lib/libsqlite3.so)
set_target_properties(glog PROPERTIES IMPORTED_LOCATION /usr/local/lib/libglog.a)
add_library(${MY_LIBRARY} SHARED ${MY_SOURCE})
target_link_libraries(${MY_LIBRARY} sqlite3 glog)
This causes following error
/usr/local/lib/libglog.a: can not be used when making a shared object; recompile with -fPIC
What is wrong in CMakeLists.txt?

Your problem isn't with CMake (though you should never have hardcoded paths... use find_package or find_library), it's that you're trying to do something impossible. As your compiler tells you,
/usr/local/lib/libglog.a: can not be used when making a shared object; recompile with -fPIC
libglog.a was not compiled with position-independent code, so it cannot be used in a shared library, period. There's more information here on SO: How to recompile with -fPIC
You'll need to recompile libglog.a with -fPIC.

Related

Create external module import files [duplicate]

I've a strange problem with CMake.
I'm importing Curl into my project, so I write for you a simplified summary of my CMakeLists.txt file.
ADD_LIBRARY (libcurl SHARED IMPORTED)
SET_PROPERTY(TARGET libcurl PROPERTY IMPORTED_LOCATION
../lib/libcurl.lib)
When I run CMake it generates the project files for MS VC++ (also for Linux). Then into the project file I find a wrong reference to curl library (libcurl-NOTFOUND)!
If I change my code into static import:
ADD_LIBRARY (libcurl STATIC IMPORTED)
SET_PROPERTY(TARGET libcurl PROPERTY IMPORTED_LOCATION
../lib/libcurl.lib)
I find the right reference to ../lib/libcurl.lib.
Do you have any idea why this happens?
Thank you very much!
For a shared library, the IMPORTED_LOCATION must point to the DLL, not the import lib. See the documentation. You might also want to set the IMPORTED_IMPLIB property.
BTW, CMake also has a find package for Curl; perhaps you could use that?

can Cmake pkg-config module say if the library is static or not

I have a program, built with cmake, that (optionally) depends on a library (openwsman), which itself depends on some libraries (libcurl, libssl, libxml-2.0 ...)
pkg_check_modules(winrm openwsman++ openwsman)
IF (${winrm_FOUND})
include_directories(${winrm_INCLUDE_DIRS})
add_definitions(-DHAVE_WINRM=openwsman)
target_sources(launch PRIVATE src/exec_impl_winrm_openwsman.cpp)
target_link_libraries(Tests PRIVATE ${winrm_LIBRARIES})
ENDIF()
If the openwsman library provides shared objects, the link runs fine, and the binary depends on libs the libwsman*.so depends on
But if only static libraries is provided, the linker must have access to libs used by the said static libraries (libcurl, libssl, libcrypto, libxml-2.0)
Is there a way, in cmake, to know the libraries provided by ${winrm_LIBRARIES} are the static ones ?
(BTW: openwsman does NOT provide "static" link options in its .pc file, like libcurl does)

CMake unexpected transitive private dependency in shared library

I have been trying to figure this out for a few days now based on the various existing SO questions & cmake mailing list archives. However, I can't quite put my finger on it.
I want to build a library named libA which will be a shared library that gets consumed by another executable. libA has many internal dependencies (libB, libC, libD, ...) which are built/present either as static libraries or cmake's object libraries. libA is supposed to contain all the code in order to be a self-consistent shared library that an application can link against without the need to propagate the internal dependencies.
libA is being built like this:
add_library(libA-objs OBJECT ${HEADERS_PUBLIC} ${HEADERS_PRIVATE} ${SOURCES_PRIVATE})
target_compile_options(libA-objs
PRIVATE
-o1
-Wall -Wextra -pedantic
-Wl,--whole-archive
)
target_link_libraries(libA-objs
PRIVATE
libB
libC
libD
)
...
# Build static library
add_library(libA-static STATIC)
target_link_libraries(libA-static PUBLIC libA-objs)
# Build shared library
add_library(libA-shared SHARED)
target_link_libraries(libA-shared PUBLIC libA-objs)
I am properly installing libA on the system. I also have everything working to export libA in a way that a consuming application can just use find_package().
The application consuming libA-shared is a shared library itself (a plugin for a 3rd-party application):
find_package(libA REQUIRED)
add_library(myplugin SHARED)
target_link_libraries(myplugin
PRIVATE
libA::libA-shared
)
Upon trying to build, the linker complains about not being able to find/resolve/link libB, libC and libD.
I checked the targets configuration file generated by cmake when installing the exported targets (the scripts that a consuming application pulls in via find_package()) and I see that libA-shared contains references to libB, libC and libD in the INTERFACE_LINK_LIBRARIES as LINK_ONLY.
Given that libA-objs links to the internal dependencies as PRIVATE and given that I am building a shared library (executable!) together with including the whole dependency archives I would have assumed for this to just work.
I do not understand why the internal dependencies show up in the linking commands of a consuming executable as they are marked as PRIVATE within the libA-objs target.
How do I solve this?
I am using CMake 3.15, GCC 9.2 and would like this to also work with clang 8.0.

Why use add_library({tgt} IMPORTED) versus target_link_libraries( -l {.so | .a})?

What is the purpose of using the statement:
add_library(<tgt> [SHARED|STATIC] IMPORTED)
From what I have found even if you create an imported library target above you still would need to specify the specific location of the actual .so or .a. This would take at least 3 cmake commands to link to an executable and the compiler still would not automatically search through the common include directories on your OS.
Example:
cmake code to link IMPORTED lib
From the CMake documentation I understand there are really 3 ways to link a library that is not built as a target in a subproject of your overall application/library.
CMake target_link_libraries() documentation
Using a CMake package for one of the shipped package scripts.
Using a linker flag:
target_link_libraries(<tgt> [SHARED|STATIC|...] -lncursesw)
Or using the IMPORTED library method (showcased in code at top).
A major difference when using the second method is that it only takes a single line of code and will search through all of your compiler's predefined include directories on you OS. Could anyone help me understand why the add_library() method is used?
Additional Realated SO Posts:
Include directories for IMPORTED libs
CMake imported library behavior
You should use add_library(<tgt> [SHARED|STATIC] IMPORTED) whenever you need to set properties such as dependencies, compile definitions, compile flags etc for <tgt>, and/or by extension, any targets that are linking against <tgt>.
Let's say you have two static libraries; libfoobar.a and libraboof.a, where libfoobar.a requires libraboof.a. Let's also say that these libraries contain some features that are enabled by -DSOME_FEATURE.
add_library(raboof STATIC IMPORTED)
set_target_properties(raboof PROPERTIES
IMPORTED_LOCATION <path-to-libraboof.a>
INTERFACE_COMPILE_DEFINITIONS "SOME_FEATURE"
)
add_library(foobar STATIC IMPORTED)
set_target_properties(foobar PROPERTIES
IMPORTED_LOCATION <path-to-libfoobar.a>
INTERFACE_LINK_LIBRARIES raboof
)
So when you link against libfoobar.a:
add_executable(my_app main.cpp)
target_link_libraries(my_app foobar)
CMake will make sure to link all dependencies in the correct order and will in this case also append -DSOME_FEATURE to the compile flags when you build my_app. Note that since we added libraboof.a as a dependency to libfoobar.a, -DSOME_FEATURE is added to any target that link against libfoobar.a through the transitive property.
If you don't use add_library(<tgt> <SHARED|STATIC> IMPORTED) in a scenario like this, you would have to manage any dependencies and required build options yourself for each target, which is quite error-prone.
This method is also often used in Config-modules for multi-component libraries to manage dependencies between the components.

What are the differences between IMPORTED target and INTERFACE libraries?

As I understand it INTERFACE libraries are like Visual Studio property sheets, so very useful. We can use it to link with static libs and propagate properties.
But IMPORTED targets bother me : I can't see a problem which can be solved with IMPORTED target only.
When you create an imported target, you're telling CMake: I have this { static library | shared library | module library | executable } already built in this location on disk. I want to be able to treat it just like a target built by my own buildsystem, so take note that when I say ImportedTargetName, it should refer to that binary on disk (with the associated import lib if applicable, and so on).
When you create an interface library, you're telling CMake: I have this set of properties (include directories etc.) which clients can use, so if they "link" to my interface library, please propagate these properties to them.
The fundamental difference is that interface libraries are not backed by anything on disk, they're just a set of requirements/properties. You can set the INTERFACE_LINK_LIBRARIES property on an interface library if you really want to, but that's not really what they were designed for. They're to encapsulate client-consumable properties, and make sense primarily for things like header-only libraries in C++.
Also notice that an interface library is a library—there's no such thing as an interface executable, but you can indeed have imported executables. E.g. a package config file for Bison could define an imported target for the Bison executable, and your project could then use it for custom commands:
# In Bison package config file:
add_executable(Bison IMPORTED)
set_property(TARGET Bison PROPERTY IMPORTED_LOCATION ...)
# In your project:
find_package(Bison)
add_custom_command(
OUTPUT parser.c
COMMAND Bison tab.y -o parser.c
DEPENDS tab.y
...
)
(Bison is used just as an example of something you might want to use in custom commands, and the command line is probably not right for it).
It seems like there is a lot of overlap. Say you have a shared library and headers on disk and you want to make it available so that bits of your CMake can do this
target_link_libraries(my_target foo)
and automatically link with it and get the necessary include directories.
You can do it either like this:
find_package(Foo)
add_library(foo SHARED IMPORTED)
set_target_properties(foo PROPERTIES
IMPORTED_LOCATION ${FOO_LIBRARIES} # The DLL, .so or .dylib
INTERFACE_INCLUDE_DIRECTORIES ${FOO_INCLUDE_DIR}
INTERFACE_COMPILE_DEFINITIONS "ENABLE_FOO"
)
Or like this:
add_library(foo INTERFACE)
target_link_libraries(foo INTERFACE ${FOO_LIBRARIES})
target_include_directories(foo INTERFACE ${FOO_INCLUDE_DIR})
target_compile_definitions(foo INTERFACE "-DENABLE_FOO")
They both work and behave identically as far as I can tell. There is even an 'imported interface library' available via add_library(foo INTERFACE IMPORTED) though that didn't seem to work and I have no idea what it is for.
Frankly the docs don't really explain which you should use for libraries, and I'm afraid I don't find Angew's "that's not really what they were designed for" very compelling.
I guess use either. I think the interface library is easier to understand and more consistent with the use of INTERFACE properties from internal libraries.