I'm building a shared library using cmake. Here are the steps that I take, starting with building a shared library A_shared using an object library A_obj.
add_library(A_obj OBJECT ${A_SRCS})
add_library(A_shared SHARED)
target_link_libraries(A_shared PUBLIC A_obj)
This process works. Now I wish to build another shared library that uses A_shared and its own sources. So I have:
add_library(B_obj OBJECT ${B_SRCS})
target_link_libraries(B_obj PUBLIC A_shared)
add_library(B_shared SHARED)
target_link_libraries(B_shared PUBLIC B_obj)
It seems to me that this should be valid, because I'm building objects B_obj which have dependence on a shared libraries A_shared, and then using these objects to construct shared library B_shared and at the same time transitively passing the dependence on A_shared using the call to target_link_libraries.
However, this results in undefined symbols when building in MSVC. When linking B_shared.dll, I get unresolved external dependencies on global variables that were defined in ${A_SRCS} and used in ${B_srcs}, and not anything else (like functions). Strangely, the object files B_obj compile fine.
If I instead link B_shared to A_obj, it works fine. But this gives me the impression that B_shared will actually contain the object files from A_obj, but all I want it only to link to A_shared.
If I link B_obj to A_obj, nothing changes and I still get unresolved dependencies.
With gcc, B_shared is successfully linked.
Therefore, my question is: am I doing the correct thing in cmake to achieve what I want? I'm wondering what I'm misunderstanding, because I've researched this extensively and I can't find the fault in my process, so I would greatly appreciate any clarification.
This comes from the behaviour of shared libraries on Windows in general: See this question. I have to manually export the symbols. The interaction with the object library wasn't creating issues.
Related
I have a project where I mix between static and shared libs. The shared libs are delivered. Each shared lib is built with its correspondence static lib. A shared lib can depend on other shared libs as well. For example, I have: sharedA, sharedB, sharedC, staticA, staticB and staticC. SharedA is built with staticA inside and similar for other shared. Let's say sharedC, besides its dependency on staticC, also depends on sharedB.
For the static libraries, if they need dependency on another static one, I link against the one's correspondence shared lib. For example:
staticB depends on staticA. Hence, I link staticB against sharedA. The reason for this is to avoid size increase if statically declare staticB's dependency on staticA.
This system has been working. However, problem arises when I build the static libs with hidden visibility. The linker links with no error. But more than one symbols of a specific class might end up in the final symbol map. Therefore, the program can pick up the undesired one, which causes weird behaviour.
I have been reading about cmake object library, and probably switching the static libs to object libs could help in this case. I change the static libs to object, and get undefined symbol errors. I define dependency of an object lib on other, but still could not get rid of all the errors. My questions are:
I am using target_link_libraries(obj2 PUBLIC obj) to declare dependency between 2 object libs. Can this be the reason for undefined symbol error I get? Because according to cmake documentation:
Object Libraries may "link" to other object libraries to get usage requirements, but since they do not have a link step nothing is done with their object files.
Maybe I should switch to target_link_libraries(obj2 $<TARGET_OBJECTS:obj>) so obj2 is built with object files from obj.c? Another thing with this is: obj needs to be a library (created with add_library). In the function where I define all the links, obj is a variable and could not be put after $<TARGET_OBJECTS:. I have been looking around but not able to find anything. Is there a way I can put variable name after $<TARGET_OBJECTS:, or I have to refractor somehow to make this possible?
Any other suggestion on how to do this would be helpful to me
I'm struggling with a linking error.
I have 3 modules:
static library A which defines function ole::compound_document::find_storage(const std::string&);
shared library B which is linked to A and uses the function;
executable C which is linked to B and uses functions from B (but does not call directly functions of library A).
During the linking of the executable C, I receive the following error message:
../../bin/B.so: undefined reference to `ole::compound_document::find_storage(std::string const&)'
The function is defined in library A.
If I run utility nm on shared library B, I receive the following output:
0000000001841c70 T ole::compound_document::find_storage(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
U ole::compound_document::find_storage(std::string const&)
It shows two find_storage functions. One of them is defined another is not defined.
I'm trying to understand how can it happens. So far unsuccessful.
The problem appears under Linux (Ubuntu), compiler: clang-9. On Windows, I can build the libraries and the executable without any problem.
I've tried to create a minimal example, just putting 3 simple modules together with only a few functions. Everything works. The compiler uses only the first definition of the function. I don't understand where the second definition comes from. I suspected some mix of c++ standards but cannot find anything.
Any suggestions will be highly appreciated.
You will need to look for problems in library B's code. std::string, verbatim, is not something that's expected to be an actual type referenced from an exported symbol, since std::string is just an alias for a std::basic_string instance. Narrow this down by looking at symbols of all modules that were linked into library B, and once you identified the module that does, you'll need to figure out why.
Your question does not provide sufficient data to decisively identify the linking problem because, of course, that can only be done by inspecting all the object modules involved in the linking, and inspecting all the source code for the likely violations of the One Definition Rule, or ill-formed code that did not produce a diagnostic, but manifested itself as a link failure.
Therefore, the following answer is meant to be as a general guide to isolating these kinds of linking failure. I don't think this question qualifies to be hammered by the canonical answer.
You have a symbol in the linked shared library that's not getting resolved when linked to an executable, specifically:
ole::compound_document::find_storage(std::string const&)
Just like you ran nm on the shared library, you can use it on every module that went into the shared library, individually. This will find which object module the unresolved reference came from. If you don't find it, it must've come from the static library you linked with, so repeat your search there.
That reference came from one of the object modules that you used to build the shared library. You will find it this way, it's unlikely to pop into existence of its own.
Once you find the relevant module, you're then on your own, by looking at the actual code that was compiled, and figure out what's up. If you can't figure it out: divide and conquer. Take the object module, and split the source file into two files, half of the functions in each one, compile them separately, and then look and see where the unresolved reference comes from.
Finally: before doing all that, try the low hanging fruit: make clean, then recompile everything. This has all the hallmarks of a compiler switch, some of the object modules were compiled by a different compiler. If that static library was provided by a third party vendor as a binary blob, it must've been compiled by a different compiler or a different version of your compiler. C++ does not guarantee binary ABI compatibility.
As mentioned by n. 'pronouns' m.The problem was in inconsistent use of -D_GLIBCXX_USE_CXX11_ABI flag. I used c++14 standard, but some projects were compiled with the flag -D_GLIBCXX_USE_CXX11_ABI=1.
It was not easy to find out, because I use a lot of 3rd party libraries with conan package manager.
I have two C++ modules: A and B, where B links to a set of static libs lib*.a (I use * here to mean a set of lib files) and A links to B.
I have CMakeLists.txt for B:
add_library(B STATIC B.cpp)
target_include_directories(B PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} "/path/to/headers/directory/for/lib*.a")
link_directories("Path/to/directory/contains/lib*.a")
target_link_libraries(B PRIVATE lib*)
and CMakeLists.txt for A:
add_library(A STATIC A.cpp)
target_include_directories(A PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} "/path/to/headers/for/libB.a") # compiler outputs libB.a when target name is B
link_directories("Path/to/directory/contains/libB.a")
target_link_libraries(A PRIVATE B)
Everything works fine, until I try to make A a shared lib, then I got error from the linker saying cannot find -l*. I believe the reason is that when I set A to be shared, the compiler looks for shared lib, which is not available.
The thing I don't understand:
B is already a static lib, why the linker needs lib*?
why compiler looks for shared lib when I set A to be shared? I thought even a shared A can be linked to static libs
I do want to note that in A.cpp, I have #include B.hh at the top, and B.hh further includes the headers for lib*.a, that is why I have target_include_directories(B PUBLIC...)
Your initial setup was already not working, but you did not see the error until switching to a shared library.
The reason for this is that all your target_link_libraries dependencies on A and B were not actually processed at all so long as both were static libraries. This has to do with what a static library is: Just a bunch of object files packed together into a single file. A static library is not linked, hence any build dependencies that concern the linker (such as linking in additional static libraries as dependencies) will not get resolved. The build system will keep track of them, but if they are missing, you will not notice unless you actually pass those libraries to something that is actually being linked - such as an executable or, in your case now, a shared library.
Since it can be a bit embarassing to have invisible unresolved dependencies like this, idiomatic CMake will have you model things differently. You never pull in static dependencies directly, instead you use an approach like the following: At the lowest layer, you have a find_library call that finds any external pre-built dependencies on the system (the lib* in your example). You then wrap that up into an imported target so that you never have to touch the raw library path again. To smoothen things out, you can hide all of this inside a find package script, so that your code only ever sees a find_package call that provides a lib* target and don't worry about the internals.
You then model all of your library interdepencies through target dependencies only. Such an approach has several advantages that make it more robust: If CMake can't find the lib*, it will tell you right away when the find_package call fail, instead of waiting until you're trying to link like it does now. By only specifying target-based dependencies, you ensure that the build is actually consuming the libraries that it was configured with (which is very much not ensured with the link_directories based approach you're having now).
In Linux when I load shared library using dlopen() from executable (or shared library) I expect that undefined symbols in this library will be automatically resolved, of course as long as executable (or shared library) defines these symbols.
For example, I have library A with these header and source files:
#pragma once
int funcA();
#include "A/header.h"
int funcA() {}
also I have library B with this source file:
#include "A/header.h"
void funcB() {
funcA();
}
for library B I specify path to header of library A, but I don't link library A to library B.
In this case, if I load library B from library A by calling dlopen(), then undefined symbol funcA in library B will be resolved, so library B will be able to call funcA.
Is it also true for Windows, or I have to manually find addresses for all symbols I need?
After researching already answered questions on Stack Overflow:
External symbol resolving in a dll
Compile to .dll with some undefined references with MinGW
I realized that if I want to make something similar work on Windows, I have to create some import library for my shared library A.
At first I thought it's needed only for MSVC, but looks like MinGW needs import library too, because it's how things work on Windows. Correct me if I miss something.
For me it's big no-no, so probably I will change a way how I work with shared libraries to explicitly retrieve every symbol I need via additional interface. Fortunately, there are not so many of them.
I want to compile statically pdf2svg so I will be able to use newest version in stable Debian. The ./configure doesn't give --enable-static option so I added manually in Makefile -static option for linker.
Unfortunately the result wasn't quite as I suspected. The linking gave me enormous amounts of undefined reference errors. After some googling I figured out that the problem is caused by wrong order of -lsome_lib. Gcc linker tries to statically link in each library once, when it first sees it - info and Stackoverflow question: Why does the order in which libraries are linked sometimes cause errors in GCC?.
Is there a possibility of making linker make multiple passes through the list of libraries?
Maybe this is what you search for (from gnu ld manpage):
-( archives -)
--start-group archives --end-group
The archives should be a list of archive files. They may be either explicit file names, or -l options.
The specified archives are searched repeatedly until no new undefined references are created. Normally, an archive is searched only once in the order that it is
specified on the command line. If a symbol in that archive is needed to resolve an undefined symbol referred to by an object in an archive that appears later on
the command line, the linker would not be able to resolve that reference. By grouping the archives, they all be searched repeatedly until all possible references
are resolved.
Using this option has a significant performance cost. It is best to use it only when there are unavoidable circular references between two or more archives.
A tick is, whenever possible, to add a static reference to an object of the class (or to the function) that were not linked in another cpp file of the same library (or in another library already used).
I have this situation:
library A with class clsA in clsA.cpp that gives the error
library A with foo.cpp that gives no reference errors
library B that uses class clsA
Application uses both libraries and uses classes/functions from foo.cpp
I get the unresolved reference in Application while using the object in library B that uses the clsA class.
Linking Application with library A and B give me the error. Since i use CodeLite, it's hard to change library order. I simply put a static object in foo.cpp:
#include "clsA.h"
clsA objA;
The linker now see that clsA are referenced in library A (between foo.cpp) and will link correctly in application because foo.cpp were already linked.
But the trick works even if the object were created in a dummy function, never called, so the object would never been allocated:
// foo.cpp
#include "clsA.h"
void dummyf()
{
clsA objA;
}