CMake inherit static library dependency - cmake

I have a library that gets build and depends on other libraries:
add_library(library1 STATIC main.c)
target_link_libraries(library1 m;pthread)
If I want to now use the just declared library1 in other library I would expect that libm and libpthread to be passed in the linker to build library2
add_library(library2 STATIC main2.c)
target_link_libraries(library2 library1) # I would expect m and pthread to be linked to library2 but don't
add_executable(binary library2)
Is the normal behavior pass libm and libpthread to the compiler to build binary?
Thanks

Related

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.

Add only headers of an imported module to a library in CMake

In CMake there are imported modules that are used to simply add external modules to local targets. For example if we want to use boost::filesystem library in our project we could have a CMakeLists.txt like this:
project(foo CXX)
find_packge(Boost REQUIRED COMPONENTS filesystem)
add_executable(foo main.cpp)
target_link_libraries(foo Boost::filesystem)
With above configuration CMake will add proper compiler options and include directories among required libraries to building process of the foo.
Now we have to build a library instead of an executable and we don't want to link boost::filesystem libraries to our library. We want only compiler options and include directories to be added to our target. Could we use imported modules concepts here? I mean that if we could use Boost::filesystem syntax for adding those options to our target?
project(foo CXX)
find_packge(Boost REQUIRED COMPONENTS filesystem)
add_library(foo STATIC foo.cpp)
# what should be wrote here to only add headers and configs to foo not the libs?
Turning my comments into an answer
add_library(STATIC) won't link the target_link_libraries() dependencies into itself.
In short, if two static libraries would include e.g. Boost::filesystem and then you link both of those libraries into an executable (where the external symbols get actually resolved) you would get duplicate symbol errors.
So CMake by default, does not add linker options like --whole-archive for gcc or LinkLibraryDependencies for VC.
target_link_libraries(foo Boost::filesystem) should work, it just describes the dependency resolved later when building a executable or shared library.
References
ld linker question: the --whole-archive option
CMake issue #9732: Cmake does not disable Link Libray Dependencies in the project settings

Statically compile library into binary?

I'm trying to fight a really obscure compilation-time bug with linking in a CMake project.
The project builds its own spin of Lua with the following CMake file:
set(LUA_SRC
"lua-5.1/src/lapi.c"
...brevity
)
set(LUA_HPP
"lua-5.1/src/lapi.h"
...brevity
)
source_group("" FILES ${LUA_SRC})
source_group("" FILES ${LUA_HPP})
add_library("lua-5.1" ${LUA_SRC} ${LUA_HPP})
set_property(TARGET "lua-5.1" PROPERTY FOLDER "External Libraries")
# include_directories(src)
if(MSVC)
sm_add_compile_definition("lua-5.1" _CRT_SECURE_NO_WARNINGS)
endif(MSVC)
disable_project_warnings("lua-5.1")
Lua is referenced in the main CMakeLists file for compiling the resultant binary:
list(APPEND SMDATA_LINK_LIB
"lua-5.1"
...brevity
)
...brevity
target_link_libraries("${SM_EXE_NAME}" ${SMDATA_LINK_LIB})
There are a few other libraries which it does link to which I'm okay with (like libpng, libjpeg, etc.), but I'd like Lua to be statically compiled into the final binary so that it has no dependencies on any system Lua.
How can I modify the CMakeLists to statically compile the Lua library into my binary?
Usually you can just tell CMake to compile the library statically:
add_library("lua-5.1" ${LUA_SRC} ${LUA_HPP})
becomes
add_library("lua-5.1" STATIC ${LUA_SRC} ${LUA_HPP})

Building shared libraries with cmake with option -Wl,--no-undefined

I'm trying to create a ndk library using android-cmake.
My target here is a shared library and build fails because of option
-Wl,--no-undefined
As the targets refers symbols from another library.
Is there a way to the missing library to the command
add_library(foo SHARED ${sources})
I was able to build by changing cmake variable
set (CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L<path to library> -lfoo")