I can't figure out why my binary does not link with certain libraries in the GNUMake file I wrote. I have:
LDLIBRARIES += -L/ms/dist/msjava/PROJ/sunjdk/1.6.0_31/.exec/amd64.linux.2.4.glibc.2.3/jre/lib/amd64/
LDLIBRARIES += -L/ms/dist/msjava/PROJ/sunjdk/1.6.0_31/.exec/amd64.linux.2.4.glibc.2.3/jre/lib/amd64/sever
LDLIBRARIES += -L/ms/dist/msjava/PROJ/sunjdk/1.6.0_31/.exec/amd64.linux.2.4.glibc.2.3/jre/lib/amd64/xawt
LDLIBRARIES += -lmlib_image -lfontmanager -lawt -lmawt
LDLIBRARIES += -ljvm -lverify -lzip -ljava`
The binary I get when I run the ldd command on it I don't see the files above being linked properly even though they are in the path specified above /ms/dist/msjava/PROJ/sunjdk/1.6.0_31/.exec/amd64.linux.2.4.glibc.2.3/jre/lib/amd64/
The ldd command on the resulting binary gives me:
libmlib_image.so => not found
libfontmanager.so => not found
libawt.so => not found
libjvm.so => not found
libverify.so =t found
libzip.so =t found
libjava.so => not found
There are a few problems with your Makefile. The first one is that you repeat yourself (a lot). In programming, this is generally considered a bad practice.
You can fix this with e.g.
JRELIB = /ms/dist/msjava/PROJ/sunjdk/1.6.0_31/.exec/amd64.linux.2.4.glibc.2.3/jre/lib/amd64
LDLIBRARIES += -L${JRELIB} -L${JRELIB}/server -L${JRELIB}/xawt
The second problem is that you don't understand the difference between static linking and runtime linking.
When you run make, you perform static (build-time) link, which succeeds.
When you run ldd, you perform runtime link (which fails to find required libraries).
To make runtime link succeed, you need to tell runtime linker where the libraries are to be found (the -L... flag tells only the static linker where to find the libraries). You do that with -Wl,-rpath=... flag:
LDLIBRARIES += -Wl,-rpath=${JRELIB}:${JRELIB}/server:${JRELIB}/xawt
Related
I'm trying to gather all the dependencies needed by some .so file. I use the Recursive ldd script, but that doesn't really matter for the manner of sake.
I want to put all the .so files in one directory, say it's in
/home/user/project/lib
I'm having a weird experience: Say there's a file libmat.so which I want to gather all its dependencies. So I ran
/home/user/project/lib$ ldd libmat.so
...
libmwboost_system.so.1.65.1 => /home/user/project/lib/libmwboost_system.so.1.65.1
libmwboost_filesystem.so.1.65.1 => /home/user/project/lib/libmwboost_filesystem.so.1.65.1
...
So we see that ldd recognized the libmwboost_system.so.1.65.1 file in the current directory.
Turns out that libmwboost_filesystem.so.1.65.1.so also depends on libmwboost_system.so.1.65.1,
But when I run:
/home/user/project/lib$ ldd libmwboost_filesystem.so.1.65.1
...
libmwboost_system.so.1.65.1 => not found
...
How come ldd can find it when I run in on libmat.so and can't when I run it on libmwboost_filesystem.so.1.65.1 ?
I would be glad if someone could provide an explanation in the context of the linking process. As far as I know, when you link a file against a library, you use the following flags:
~$ gcc my_program.c -Lpath/to/solib/for/static/linker -lnameoflib -wl,-rpath=path/to/solib/for/dynamic/linker
This -Wl,-rpath flag embeds in the executable the path of the library that the dynamic linker will search for at run time. In the case of a shared library that depends on other libraries - does it work the same?
Ok so that's how it works:
When linking a binary - whether it's an executable or another shared library - against a shared library, the static linker embeds in the binary the names of the libraries we linked against. Those libraries will be loaded by the dynmaic linker - ld.so - once the program is run by the user.
Now the question is where the dynamic linker will search for these libraries at runtime. Briefly, according to the man page of ld.so, when the dynamic linker first inspects the binary to resolve its dependencies, it goes through the strings of the dependencies. If a string contains a slash "/" then the string is interpreted as a path. This can happen if the library name was specified with a slash at link time, like this:
~$ gcc prog.c ../path/to/library.so
In this case, the string embeded in the executable will be: ../path/to/library.so and the dynamic linker will search it relatively to the location of the binary.
If not, it will search for the library in a list of locations (the whole list is specified in the man page). The first location is the directories specified in the DT_RUNPATH section attribute of the binary. This can be set at link time using the -Wl,-rpath flag:
~$ gcc prog.c -Lpath/of/lib/ -lmylib -Wl,-rpath=path/of/lib
In this case, the path/of/lib will be searched for the library by the dynamic library.
You can inspect this attribute using readelf:
~$ readelf -d binary | grep RUNPATH
In my case, the libmat.so library contained a RUNPATH attribute set to $ORIGIN, meaning that libraries will be searched in the same location of the binary library. Whereas, the libmwboost_filesystem.so.1.65.1 didn't have this attribute set, that is why ldd didn't find the library.
ldd is just using ld.so to try and load the libraries, and shows where it found them, according to the search path specified in the ld.so man page.
System spec: Ubuntu 16.04, QtCreator 3.5.1 based on Qt5.5.1
In a C project I'm using dlopen and friends to load a shared library. The library uses some machinery from the main application.
Now, if I compile manually from terminal, everything works just fine. When I use QtCreator to build the project, calls from the library to the main application fail with the following error:
/Programming/C/emme_1/emme_1: symbol lookup error: /Programming/C/emme_1/modtest/test.so: undefined symbol: pop. Here pop is a function in the main application which is named emme_1. Please note that the error happens only if the library's function calls another function inside the main application. If the library's function is empty and is called from the application, it works.
This is my very simple .pro file:
QMAKE_CFLAGS += -DTRACE_ASM
QMAKE_CFLAGS += -rdynamic
QMAKE_CFLAGS += -ldl
LIBS += /usr/lib/x86_64-linux-gnu/libdl.so
I believe it contains all it's needed for the requested functionality, but maybe I'm missing something.
I believe it contains all it's needed for the requested functionality, but maybe I'm missing something.
You must be missing something since the setup doesn't work.
Note that -rdynamic and -ldl are linker flags, not compile flags. You'll want to move them to QMAKE_LFLAGS.
You can look at the final link command, and verify that -rdynamic is not in it. Once you manage to get it there, things will work again.
I am linking few libs in one by using command
lib.exe /out:X.lib X.lib other1.lib other2.lib
The result lib becomes much bigger then it was.
When I am linking the result X.lib to my exe everything works perfect till I remove other1.lib or other2.lib from the file system.
I have 2 questions:
Why my result lib becomes SO big if still the original other1.lib and other2.lib are used.
How can I let linker to use data from the result X.lib and not from original libs?
Update:
this behavior is relevant just for boost libs in my case
I am using certain GNU tools, i.e. the GNU C++ Compiler (g++) and the GNU Linker (ld) to create a shared library (.so) file as well as a binary executable file.
The binary executable file makes use of the dlopen function to dynamically load the shared library file at runtime. In addition to this, the shared library file
needs to invoke a particular class method (called ToolboxManager::registerToolbox) which is defined within the binary executable. This is accommodated by forcing the binary
executable to export the class method, which in turn is accomplished at link time by linking the binary executable with the following command line options ;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
where the file ${top_srcdir}/dynamic_symbol_table.txt contains the following content ;
{
extern "C++"
{
"ToolboxManager::registerToolbox*";
};
};
Note the use of the asterisk (*) in the file to force the linker to export all symbols that begin with ToolboxManager::registerToolbox.
When I run the GNU nm utility (nm -C -g ./a.out) on the resulting binary executable, it displays the following information about the afore-mentioned class method ;
08053da0 T ToolboxManager::registerToolbox
(
std::string&,
std::string&,
std::map
<
std::string,
Factory_DSPB_Base*,
std::less
<
std::string
>,
std::allocator
<
std::pair
<
std::string const,
Factory_DSPB_Base*
>
>
>&
)
or, if the nm utility is invoked as above, but this time without the use of the -C command line switch ;
08053da0 T _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
So far, this looks fine. The "T" in front of the definition of the class method ToolboxManager::registerToolbox, denotes that the method resides within the Text/Code section of the file.
Similarly, if I run the nm utility (nm -C -g ./toolbox.so) on the shared library file, it displays the following information about the same afore-mentioned class
method ;
U ToolboxManager::registerToolbox
(
std::string&,
std::string&,
std::map
<
std::string,
Factory_DSPB_Base*,
std::less
<
std::string
>,
std::allocator
<
std::pair
<
std::string const,
Factory_DSPB_Base*
>
>
>&
)
This also looks fine. The "U" in front of the definition of the class method ToolboxManager::registerToolbox, denotes that the method is undefined in the shared library file.
However, a problem occurs when I run the binary exectable from the command line and this problem results in the following error message being displayed ;
./toolbox.so: undefined symbol: _ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
The mangled class method name which appears in this runtime message is shown below, as the first of the two lines. For comparison purposes, the mangled class method name from above (and which was generated using the the nm -g command) is shown below as the second of the two lines ;
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
_ZN14ToolboxManager15registerToolboxERSsS0_RSt3mapISsP17Factory_DSPB_BaseSt4lessISsESaISt4pairIKSsS3_EEE
As can be seen, the two mangled names are identical. Therefore, I cannot understand why the undefined symbol cannot be resolved at runtime.
I then re-linked the binary executable, however this time I replaced the following linker command ;
-Wl,--dynamic-list=${top_srcdir}/dynamic_symbol_table.txt
with the this one ;
-Wl,--export-dynamic
The --export-dynamic linker option instructs the GNU Linker to add all the symbols to the dynamic symbol table.
If then ran the binary executable again. This time it executed
correctly and the call to the dlopen function did not result in an undefined symbol error. This has me utterly perplexed, as it looks as though the symbol is being exported
correctly in the initial version of the binary executable. Is anyone able to see the problem here? Any assistance would be immensely appreciated.
Thanks in advance.
I have managed to solve this problem. I have found that if I remove the quotation marks from the following line ;
"ToolboxManager::registerToolbox*"
within the file ${top_srcdir}/dynamic_symbol_table.txt and then re-link the binary executable, then it works. That is, the dlopen function will not fail anymore.
I can't help but wonder if it would have been more appropriate to ask this question on the GNU binutils mailing list than here on this web-site.
I'm trying to get SCons to make a shared library. One of the items going into the .so is a .a static lib.
I have a line like:
env_2.SharedLibrary('libstuff.so', \
Split("""stuff.cxx mylib/libMine.a""")
And upon running it, I get this error:
scons: *** Source file: mylib/libMine.a \
is static and is not compatible with shared target: libstuff.so
However, I know that a shared library can be made from the .a via a command like:
g++ -m32 -shared -o libstuff.so stuff.o mylib/libMine.a
Any ideas on getting this to work or any workarounds would be greatly appreciated.
Related question: How do I get scons to put an additional string -shared on the LINK command line for the Program() call? If I could do this, I think it would meet my needs.
Try to set env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME']=1 in your SConstruct.
This problem is not specific to scons. To build a shared library, you'll need objects that are compiled with position independent code (-fPIC). Your best bet is to make the shared library out of the source files compiled with the right options.
In SCons, you can define a list of targets that's used to build both libMine.a and libShared.so.
Update: for your second question, the SharedLibrary builder might do what you need:
SharedLibrary('foo', ['f1.c', 'f2.c', 'f3.c'])
If not, LINKFLAGS sets the flags passed to a link command.
I've the same problem under cygwin. I passed '-fPIC' options to gcc when building the objects and got the following warning:
warning: -fPIC ignored for target (all code is position independent)
I also passed '-shared' to the link command. And I finally got the error
"***.lib is static and is not compatible with shared target: myso.dll"
It seems scons doesn't allow to create so directly from obj or lib files, and one can either create the so from a list of sources files (using SharedLibrary()) or source file + 'LIBS' option like dummytaurus says. I'm curious about that.
env_2.SharedLibrary('libstuff.so', Split("""stuff.cxx"""), LIBS='libMine.a', LIBPATH='mylib')
This should work.
The problem is in the function SharedFlagChecker (Default.py), which checks only for an internal "shared" flag. The SCons documentation leads you to believe that it keeps the distinction between shared objects and static objects via the suffix (SHOBJSUFFIX), but not so. The fix is easy. In the file scons-local.../SCons/Default.py find the SharedFlagCheckerand edit:
def SharedFlagChecker(source, target, env):
same = env.subst('$STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME')
if same == '0' or same == '' or same == 'False':
for src in source:
try:
shared = src.attributes.shared
except AttributeError:
# Replace this line: shared = None
shared = env.Dictionary()['SHOBJSUFFIX'] == src.suffix
if not shared:
raise SCons.Errors.UserError("Source file: ...")
Now objects made via the SharedObject builder will be linkable in a shared library.
The solution to resolve this issue have been used a 'SharedObject' as the following:
ASN1CObjectFile = envCProcesses.SharedObject(target = "OTCMsg.os",
source = "OTCMsg.c",
CFLAGS = envCProcesses["CFLAGS"] + ["-Wno-unused"])
and:
OTCLibSharedLibrary = envCProcesses.SharedLibrary(env["OTC_LIBPATH"] + "/libOTCLib" + env["SHLIBSUFFIX"],
ASN1CObjectFile +
[ASN1AllocatorSource,
"OTCLib.c"],
LIBPREFIX = "")
Best regards,