Linking a library which is compile time linked to another library - c++

I have a binary1 which is compile time linked to another library1.so
To add some functionality I have created library2.so which uses libas_sdk.so.
Functionality in library2.so works only if dlopen(libas_sdk.so) is success, else it returns normally and does other work.
Now library1.so has to use library2.so if required and use the new functionality.
I have tried multiple compile and link options but getting ldd or unresolved symbol errors.
Please suggest.

dlopen() will return success, if the lib is already linked in.
Because library1.so has to use library2.so, you need to link both of them to binary1. (-llibrary1 -llibrary2)
From your question seems, that library2.so links in libas_sdk.so runtime. It happens probably when you call its some init_library2() or some function with some configuration data.
I think the problem is not with your linking, but with your binary1. This initialization of library2 (or library1) is what you do too early, or too late. IMHO your binary1 should be linked with a simple -llibrary1 -llibrary2 .

Related

Linking to a shared library that links to another shared library segfaults on exit

Unfortunately I have been unable to create a minimal example, but here is the situation. I have one library that links to another, like this:
add_library(MainLib MainLib.cpp)
add_library(ChildLib ChildLib.cpp)
target_link_libraries(ChildLib MainLib)
I can do this (not using the ChildLib, but rather compiling ChildLib.cpp into the executable directly):
ADD_EXECUTABLE(TestNoLink TestNoLink.cpp ChildLib.cpp)
TARGET_LINK_LIBRARIES(TestNoLink MainLib)
and everything compiles, links, and runs with no problems.
However, if I do this (now using the ChildLib):
ADD_EXECUTABLE(TestChildLink TestChildLink.cpp)
TARGET_LINK_LIBRARIES(TestChildLink ChildLib) # no need to link to MainLib here because ChildLib already links to MainLib
Everything still compiles and links, and it actually runs fine as well, but after it is finished running, it segfaults.
Is there some concept I should be looking for here to figure out what is causing this?
The problem was apparently that I was linking to a shared AND static version of the same library (a Boost library). Shouldn't the linker notice that and produce an error?

Symbol lookup error at runtime instead of load time

I have an application which uses a class Foo from an .so shared library. I've come across a problem where at runtime it prints
<appname>: symbol lookup error: <appname>: undefined symbol: <mangled_Foo_symbol_name>
Now, it turned out that the unmangled symbol was for the constructor of the class Foo, and the problem was simply that an old version of the library was loaded, which didn't contain Foo yet.
My question isn't about resolving the error (that's obviously to use the correct library), but why it appears at runtime instead of at time of load / startup.
The line of code causing the error just instantiates an object of class Foo, so I'm not using anything like dlopen here, at least not explicitly / to my knowledge.
In contrast, if I remove the whole library from the load search path, I get this error at startup:
<appname>: error while loading shared libraries: libname.so.2: cannot open shared object file: No such file or directory
When the wrong version of gcc / libstdc++ is on the load path, an error also appears at starup:
<appname>: /path/to/gcc-4.8.0/lib64/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by <appname>)
This "fail fast" behavior is much more desirable, I don't want to run my application for quite awhile first, until I finally realize it's using the wrong library.
What causes the load error to appear at runtime and how can I make it appear immediately?
From the man page of ld.so:
ENVIRONMENT
LD_BIND_NOW (libc5; glibc since 2.1.1) If set to a nonempty string, causes the dynamic linker to resolve all symbols at program startup instead of deferring function call resolution to the point when they are first referenced. This is useful when using a debugger.
LD_WARN (ELF only)(glibc since 2.1.3) If set to a nonempty string, warn about unresolved symbols.
I think you can not statically link .so library. If you want to avoid load/run time errors you have to use all static libraries (.a). If you do not have static version of library and source then try to find some statifier. After googling I find few statifiers but do not know how do they work so leaving that part up to you.

maps in shared memory: Boost.Interprocess demo fails due to unmet date_time dependency

I want to create shared map objects that multiple processes can access. The most promising approach I've found is this demo code from Boost.Interprocess, which allocates map objects in a managed shared memory segment. This question will mostly be about the boost problems I'm having, but I'd also be grateful if anyone has non-boost alternative approaches.
I'm completely new to boost: it looks amazing, if huge, and I was encouraged by its claim that "often, there's nothing to build". But in this case that promise is broken in what seems to be a senseless way, and I'm failing to compile the demo because of dependency problems internal to boost.
I'm on Windows, with Visual C++ Express 2010 installed. After saving the demo code as shmap.cpp I do the following:
"%VS100COMNTOOLS%\..\..\VC\vcvarsall.bat"
cl /EHsc /I boost_1_57_0 shmap.cpp
It compiles OK, but then I get this:
LINK : fatal error LNK1104: cannot open file 'libboost_date_time-vc100-mt-s-1_57.lib'
This surprises me on a number of levels. (Q1): I didn't ask for libraries---where and how is boost leading the linker to expect them? (Q2): Why would it be asking for date_time in particular? At no point in the code is anything as functionally specific as a date or time computed, referenced or included. Is this a case of overzealous blanket dependency, and if so is there a way I can weed it out?
Regardless, the obvious first thing to try was to play the game: in the boost_1_57_0 directory I ran bootstrap.bat followed by b2. The Earth turned a good few degrees, boost was built successfully, and I retried with:
cl /EHsc /I boost_1_57_0 shmap.cpp /link /LIBPATH:boost_1_57_0\stage\lib
I still get the same linker error. This is because b2 seems to have built libs with -mt- and with -mt-gd- in their names, but not with the -mt-s- that the linker is looking for. Boost's "Getting Started" webpage tells me what these stand for but doesn't tell me (Q3): how can I change either the type of library that gets built, or the type that the linker expects?
"At no point in the code is anything as functionally specific as a date or time computed, referenced or included."
(Q2): Why would it be asking for date_time in particular?
Apparently the things you used depend on it.
E.g the mutex operations have timed_lock function
(Q1): I didn't add libraries to the project---where and how is boost leading the linker to expect them?
Boost does autolinking by default. This uses MSVC++ specific pragmas to indicate the right flavour of the right link libraries. This is an awesome feature.
You just have to make sure the import libraries are on the library path for your project.
There are ways to disable auto-linking in boost (I think it involves defining BOOST_ALL_NO_LIB)
There might be ways to
disable dependency on boost date_time (dropping features); see the autl-link description in the Getting Started guide
linking to date_Time statically (or make it header-only)
I'd refer to the documentation for this.
Here's what I've learned, in large part thanks to sehe:
Q1: It's magic---specifically, MSVC-specific magic---and it happens because it's necessary.
Q2: It becomes unnecessary---i.e. the demo can be compiled without needing to look for a binary date_time lib---if I add /DBOOST_ALL_NO_LIB to the compile flags. But it's unclear whether that will still be true once I start to use additional IPC functionality like time-dependent mutexing.
Q3: Strings from the "Boost.Build option" column of this table can be passed to b2, so the way to create *-mt-s-*.lib is to say b2 runtime-link=static. This finally lets me compile without the /DBOOST_ALL_NO_LIB flag, and discover that date_time is the only library the demo seems to need.
I also discovered that the dependencies can be tracked with the bcp tool, and (eventually) also how to build bcp in the first place, as follows:
build:
cd boost_1_57_0
bjam tools\bcp
cd ..
report:
boost_1_57_0\dist\bin\bcp.exe --boost=boost_1_57_0 --report --scan shmap.cpp report.html
The result is that the maps-in-shared-memory demo needs 1421 files from boost 1.57.0.

XCode 4.2 static libraries linking issue

I have Core static library, a few Component static libraries that relays on the Core one, and then there is an App that links against both Core and Component libraries. My App can link both against Core and Component as long as Component don't uses classes from Core (App uses classes from Core).
I got the following error in both armv6 and armv7 versions. So my problem is not the very popular linking issue that everyone has.
ld: symbol(s) not found for architecture armv6
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I added reference to Core in Component and even added it in "Link Binary With Libraries" which shouldn't be necessary for static lib.
Since I start having this issue I start doubting my design... It probably makes more sense in dynamically linking environment but still it should be doable in static one, especially since this already works under Windows with MSVC compilers.
Edit:
I made some progress! Although I still don't know where to go with it.
Here is my setup:
Core has a class cResourceManager that has a templated method GetResource<T>(int id)
Core also has class cResource
Component has class cMesh that inherits cResource
Here are some tests:
If I try from App to call rm->GetResource<cMesh>(...) I get the linking error
If I try from App to construct cMesh I get linking the linking error
If I try from App to call static method that will return new instance of cMesh I get the linking error
If I comment out the construction of cMesh but leave other member cMesh function calls the App links fine. I can even call delete mesh.
I have never seen anything like it!
If you remove the cMesh constructor, then you are then using the default (no argument, no body) cMesh constructor that is given to you. It almost sounds like there's a build error or missing code as a result of some code in your cMesh constructor and so the library isn't actually getting generated, and perhaps Xcode isn't reporting the error. Xcode is no good at reporting linker errors.
I would suggest looking at what symbols the linker says are missing and double-check that they are actually defined in your code. My guess is that you're using one of those symbols in your cMesh constructor. A lot of times with virtual base classes, you may forget to define and implement a method or two in a child class. Could be a result of missing a method based on your template, or your template isn't #included correctly. This could compile fine but result in linker errors like you're seeing.
If Xcode isn't showing you the full linker error, show the Log Navigator (Command ⌘+7), double-click the last "Build " entry, select the error, and then press the button on the far-right of the row that appears when selected. The symbols should be listed there. If not, it's time for xcodebuild in the Terminal.
If it's not that case, I'd be interested in seeing the results of whether or not the library is being built for the appropriate architecture, or maybe this can spur some progress:
In the Xcode Organizer Shift ⇧+Command ⌘+2, click Projects and find the path to the DerivedData for your project.
In the Terminal, navigate to that directory (cd ~/Library/Developer/Xcode/DerivedData/proj-<random value>/)
Remove (or move aside) the Build directory (rm -r Build)
In Xcode, try to build with the cMesh constructor present.
Find the Library product file (cd Build/Products/<scheme>-iphoneos)
Your compiled static libraries (<libname>.a) should be in this directory. If they're not there, they didn't build (unless you put your products elsewhere). If your libraries are there, let's confirm that they actually are getting built for the appropriate architecture. Run otool -vh <library>.a. You should see something like:
$ otool -vh libtesting.a
Archive : libtesting.a
libtesting.a(testing.o):
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC ARM V7 0x00 OBJECT 3 1928 SUBSECTIONS_VIA_SYMBOLS
As you can see, my test library was built for ARMv7.
Make sure you are linking them in the correct order.
If Component depends on symbols in Core, then Component needs to be first in the link order, so the linker knows which symbols to look for in Core.
In MSVC the order doesn't matter, but in most other compiler suites it does.
I don't think Clang generates code for armv6, if you're targeting devices that old you still need to use GCC.

Linker issues in C++ / ObjC

I'm porting a sizeable codebase to iOS. The simplified version of my scenario is as follows:
I have a C++ library, built from the command line. I can run code from it from the iOS simulator, so I believe it's correctly built.
I have the skeleton iOS application created by Xcode
I want to add logging to the C++ library. I have a trace() method which takes fmt, .... I compile that .cpp using -x Objective-c++, the code is as follows:
void trace (const char* sFmt, ...)
{
va_list args;
va_start(args, sFmt);
NSString* sFmt2 = [ NSString stringWithUTF8String: sFmt ];
NSLogv(sFmt2, args);
va_end(args);
}
The library compiles just fine. However, when I try to link the app, I get a linker error:
".objc_class_name_NSString", referenced from: literal-pointer#__OBJC#__cls_refs#NSString in lib.a(trace.o)
This is strange because I can use NSString and NSLog from a .mm file in the project itself. The Foundation framework is linked. Moreover, just to test, instead of calling NSString from my library I added a helper foobar() to the .mm in the project, which does this
void foobar (const char* sFmt)
{
NSLog([NSString stringWithUTF8String:sFmt]);
}
When this is called from the library function above, it works!
Everything I read about this kind of error involves a "just updated my SDK" scenario, which is not my case. I started doing iOS stuff literally two days ago, I haven't changed the default project settings, etc.
My guess is that name mangling is failing at some point, because I know NSString is indeed linked, but it seems the name refrenced by the library is different to the linked one.
Any ideas?
Your linker output indicates that your command-line-built library is lib.a, which indicates to me that it's a static library. I'd guess that, not being a dylib, it doesn't know how to use the dyloader to find missing symbols at runtime. Relatedly, I suspect that the iOS project will link in these System libraries dynamically (even though non-OS developers can't create dynamic frameworks), whereas your static C++ library will expect those symbols to be resolved at link time.
I suspect that any of these three things would resolve the issue: (in descending order of attractiveness)
statically link against the right libraries when building the C++ library
make the C++ library a dylib instead of a static library (so it will expect to find missing symbols at runtime using the dyloader)
link your whole app statically (so the NSString class symbols are present at app link time) (This is a bad idea, if it's even possible at all, but would likely solve the problem.)
Hope this helps!
I was able to fix this by using libtool instead of ld, passing it -framework Foundation, and passing -fobjc-abi-version=2 to gcc.