Shared lib with link to static libs internally - c++

I have a shared library called MyLib. I have linked MyLib to a static version of Boost and three other libraries.
MyLib does not expose any feature of those linked libraries. In other words, the public interface headers of MyLib does not mention or include Boost or any other library.
I have built MyLib and got .lib(.a) and .dll(.so) files.
Now, I have MyEXE which is a program that is linked to MyLib. Everything is smooth till now.
If I need some feature of Boost or the other three libraries to be used in MyEXE:
Will it be safe to link MyEXE to Boost or the other libraries? Will I face any ODR problem?
If it is OK to link to them, should I link to the exact same version of Boost and other libraries that were used with MyLIB?
Does the previous scenario seems bad? Should I follow a better scenario? (Distributing the source and keeping the link process to the end developer is not an option for me)

Related

Archiving static dependencies in modern CMake project

I need to package a C++ library that links to some other static libraries, and I'd like to be able to ship the compiled files alone without the need to ship the transitive dependencies as well. To this effect, I'm following this guide regarding modern CMake techniques, and I've specified all the needed dependencies as PRIVATE, as they are not used in my library's exposed API.
The issue is that it seems that, despite having specified the dependencies as PRIVATE, the linker still does not include them in the output library, so if I try to link my library to an executable, the linker will complain about missing symbols (at least using MSVC). Is there a way to solve this?
I've already taken a look at this but I'm not sure how to integrate it in the existing INSTALL targets
Assuming that you are creating a static library:
You receive unresolved symbols because dependencies in static libraries are not resolved during their creation. Only when you link the static lib to an executable or shared library, the linker actually tries to resolve the required symbols (and will fail in your case).
So you need to combine your static libraries to a single one (as you already found out).
You should follow the approach of combining add_custom_command and add_custom_target that is outlined in the answers you linked to (https://stackoverflow.com/a/32888999/1228449).
Then use INSTALL( FILES ....) to add the combined library to your install commands, e.g.:
include(GNUInstallDirs)
INSTALL( FILES ${LIBNAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} )
EDIT:
Alternatively, create a shared library.
ADD_LIBRARY( mylibrary SHARED ...)
Then the required symbols of the privately used static libraries are resolved at link time of your library. Furthermore, only the symbols that your library actually uses, are integrated into your library (whereas the static library will contain everything).

C++ Shared library creation - linking against other shared libraries

I'm creating a C++ shared library which links against some Boost libraries (Boost version 1.55 on my local machine).
I can use my library on my machine, but I can't use it on another system with a different version of Boost (let's say 1.54) because of undefined references.
I am using CMake, here the CMakeLists.txt file:
cmake_minimum_required(VERSION 2.8)
project(my_library)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/lib)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
FILE(GLOB_RECURSE INCLUDE_FILES "include/*.hpp")
FILE(GLOB_RECURSE SOURCE_FILES "src/*.cpp")
add_library(${PROJECT_NAME} SHARED ${INCLUDE_FILES} ${SOURCE_FILES})
target_link_libraries(${PROJECT_NAME} -pthread -lboost_filesystem -lboost_regex -lboost_system)
I'm new to library creation and I'm struggling for days on that issue. I'm wondering if I must create a static library instead with Boost inside. But I would like my library to be the smallest as possible.
EDIT: When I check my lib dependencies I got this for Boost regex:
libboost_regex.so.1.55.0 => /usr/lib/x86_64-linux-gnu/libboost_regex.so.1.55.0 (0x00007fe228a27000)
Is it possible to update this to NOT link against a particular version of Boost?
When you link to a shared library, such as Boost, it is essential that the ABI of the library that is actually loaded in run time is compatible to the one that was used when compiling and linking. Boost does not maintain ABI compatibility between releases. This is why there is a strict dependency on a particular Boost version. There is no way to build an executable or library that will be version-agnostic to the Boost version it uses.
In Linux world it is normal to open source your code so that it can be compiled for each Linux distribution individually. This way, the Boost version used during compilation and run time will be the same - the one that the distro maintainers ship.
If open source model is not suitable for you, you can either do the package building yourself for different Linux distributions or attempt to hide the dependency somehow. One way to do the latter is to build your library as a shared object but link with static libraries of Boost. You must take a great care though to not expose Boost in any of your public interfaces and not export any Boost symbols from your library. This includes type info and consequently Boost exceptions cannot be thrown from your library. Basically, the fact that you're using Boost must be absolutely hidden from your library users. Otherwise there will be difficult to resolve conflicts between your Boost and the Boost that might be used by the user of your library.
Note that for some Boost libraries even static linking is not an option as there may be a requirement to link with shared libraries in some configurations. You should consult with the documentation of each Boost library you use to see if such constraints exist.
You should not create static library, as it just an archive of object files. Also static libraries are not created by compilers, it created using arching tools
ar cr libtemp.a obj/*.o
In contrary Shared libraries are supported by Compilers.
g++ -fPIC -shared *.o -o libtemp.so
And you can use tools like "nm", "ldd" and "objdump" to inspect into your library for symbols.
Read about linker and loaders, it will give a better idea about this topic.
Also standard practice for CMAKE is to use find_package instead of liking directlty.
find_package (Threads)
find_package(Boost,file_system,regex,system)
target_link_libraries (myapp ${CMAKE_THREAD_LIBS_INIT} ${BOOST_LIBS})

Removing linker dependencies

I'm working on a c++ app on linux using g++. My app links in a shared library that exposes a simple API I need. This library internally references a large number of additional shared libs. I've had to find each and every one and add them to my Makefile to get them linked in.
I assume my app has to link to any of the libs the primary lib depends on. Is the only way around this linking requirement, having the primary lib compile in the static libs of all its dependencies? Does this apply to using the plug-in model via dlopen/dlsym?
ty
Is the only way around this linking requirement, having the primary lib compile in the static libs of all its dependencies?
No. The shared library could itself link to the shared libraries it depends on. Most linkers would pick up those libraries as well, and link your executable to those libraries without you mentioning them at the linker stage.
In your case, it sounds like the shared library did not link to the libraries it required. the ldd tool can be useful in this regard.
As an example, say you produce this shared library:
gcc -shared foo.o -o libfoo.so -lm
Now the libfoo.so is linked to the math library (libm). Any application linked to libfoo.so
would be linked to libm as well, i.e. you'd just have to do
gcc -o prog main.o -lfoo
If on the other hand the shared library was not linked to lib, but was produced with only
gcc -shared foo.o -o libfoo.so
You'd have to explicitly link to libm when linking your application:
gcc -o prog main.o -lfoo -lm
When you dlopen() a shared library, the runtime linker will load all the libraries that shared library was also linked against - unless they're already loaded. So - if a library you dlopen() is not linked against libraries it depends on, and your executable are not linked against those libraries either, dlopen() will fail (unless you specify RTLD_LAZY, in which case things fail later on)
I assume my app has to link to any of the libs the primary lib depends on.
It sounds as though either your app is using those symbols directly (not just indirectly through the API shared lib) or that shared lib hasn't been linked properly, so it wasn't linked to the libraries it depends on. If when that shared library was created its dependencies were linked to with -l then it would cause them to be linked to automatically when linking your app to the API lib.
Is the only way around this linking requirement, having the primary lib compile in the static libs of all its dependencies?
That's one way, but not the only way.
Does this apply to using the plug-in model via dlopen/dlsym?
As long as the plugins are correctly linked to the libs they depend on ... No, in that case the linker cannot possibly know what libs you will dlopen at run-time, so can't know what their dependencies will be, so you don't need to name them at link-time. It wouldn't be possible to without knowing in advance all the plugins that might get loaded.
If the plugin libraries weren't properly linked you'd get the same problem when trying to dlopen them.
I assume my app has to link to any of the libs the primary lib depends on. Is the only way around this linking requirement, having the primary lib compile in the static libs of all its dependencies?
Off course. There are no ways around : either static linking, or having libraries (correct versions, if not ABI compatible) in libraries run-time search path.
Does this apply to using the plug-in model via dlopen/dlsym?
No. For that, you need to have shared library in a path from which you want to load it.

Why doesn't Libtool want to link with a static library?

I want to build a shared library that uses ZipArchive using GNU Autotools but I'm having this problem:
Warning: linker path does not have real file for library -lziparch.
I have the capability to make that library automatically link in when
you link to this library. But I can only do this if you have a
shared version of the library, which you do not appear to have
because I did check the linker path looking for a file starting
with libziparch and none of the candidates passed a file format test
using a file magic. Last file checked: /usr/local/ZipArchive/ZipArchive/libziparch.a
The inter-library dependencies that have been dropped here will be
automatically added whenever a program is linked with this library
or is declared to -dlopen it.
If I build a static library or if I use a shared library of ZipArchive it works but the problem is that the makefile that comes with ZipArchive source code only builds a static library.
How can I force Libtool to link with a static library?
Generally, static archives are created with non-pic object files and they cannot be put into shared libraries.
What this message is telling you though, is that when a program links to YOUR library using Libtool, that -lziparch will get added to the link. So you don't need to change anything unless you're building a module for an interpreted language. In that case, you will have to build ZipArchive as a shared library. In addition, this wouldn't work on a platform like MS Windows where shared libraries (DLLs) have to resolve all their symbols at link time.
All that said, if your ziparch static lib is PIC code, you can use the -whole-archive flag when linking it to your library. This would be the least portable solution though.

Linking a dynamic library to a static library that links to other static libraries

In my C++ application I have a static library (libCOMMON.a) that links to boost libraries: system, filsystem, timer and chrono.
I am using CMake and here is how I create and link libCOMMON.a:
ADD_LIBRARY(COMMON ${COMMON_SRCS})
target_link_libraries(COMMON
${BOOST_LIB_DIR}/libboost_filesystem.a
${BOOST_LIB_DIR}/libboost_system.a
${BOOST_LIB_DIR}/libboost_timer.a
${BOOST_LIB_DIR}/libboost_chrono.a
)
I also have plugins for this application that links to libCOMMON.a. The plugins are built as dynamic libraries. Everything compiles ok (using gcc) but when I start the application, the plugins can't be loaded because some symbols in the dynamic libraries related to boost cannot be resolved.
The solution was to link each of the plugins to boost. Is there a better way ?
I thought that if boost libraries are linked statically into libCOMMON.a, it would be enough to link the plugins to libCOMMON.a.
Can someone explain what's happening ?
Thanks
I think the problem is that boost libraries are built as dynamic libraries by default. Even if the ".a" suggests that they are built as static libraries, the lib folder of boost contains a ".so" library with each ".a". Which means that libCOMMON.a is linked dynamically to boost libraries. For this reason, the plugins that statically links to libCOMMON.a has also to dynamically link to boost libraries. A better solution would be to build boost libraries as static libraries.