c++, netbeans, --whole-archive - c++

I am using netbeans on redhat. I have a suite of related projects:
stand alone .a utility library
stand alone project specific .a library
executable that depends on the two .a libs and a couple third
party shared and static libs
a .so module that depends on the two .a libs and a couple third
party shared and static libs
My goal is that the executable and the module will be easily copied onto target machines here to do the necessary tasks without having to make sure that the associated local and third party libs are installed as well.
The executable builds and seems to work fine. The .so module builds fine but the application that loads it finds undefind references to various things. I have found advice that says to surround the list of needed libraries with
g++ ... -Wl,--whole-archive -llib1 -llib2 ... -Wl,--no-whole-archive
I just discovered that you add this in netbeans by going to {project} > Properties > Linker > Libraries; editing the list of libraries; and then, Add Option to add the strings. Then you use the Up/Down buttons to position the whole-archive options where you want them. Cool!
The result of this however is:
g++ -o dist/Debug/GNU_1-Linux-x86/myLocalSharedObjectModule.so build/Debug/GNU_1-Linux-x86/myLocalSharedObjectModule.o -L/usr/local/myLibTestDestination -Wl,--whole-archive -lpam -lpcre -lsqlite3 /usr/lib64/mysql/libmysqlclient.a -lmyLib-1 -lmyLib-2 -Wl,--no-whole-archive -shared -fPIC
/usr/lib64/mysql/libmysqlclient.a(mysys_dtrace.o):(.SUNW_dof+0x0): multiple definition of `__SUNW_dof'
/usr/lib64/mysql/libmysqlclient.a(clientlib_dtrace.o):(.SUNW_dof+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `__SUNW_dof' changed from 4050 in /usr/lib64/mysql/libmysqlclient.a(clientlib_dtrace.o) to 4274 in /usr/lib64/mysql/libmysqlclient.a(mysys_dtrace.o)
/usr/lib64/mysql/libmysqlclient.a(mysys_ssl_dtrace.o):(.SUNW_dof+0x0): multiple definition of `__SUNW_dof'
/usr/lib64/mysql/libmysqlclient.a(clientlib_dtrace.o):(.SUNW_dof+0x0): first defined here
/usr/bin/ld: Warning: size of symbol `__SUNW_dof' changed from 4274 in /usr/lib64/mysql/libmysqlclient.a(clientlib_dtrace.o) to 3490 in /usr/lib64/mysql/libmysqlclient.a(mysys_ssl_dtrace.o)
collect2: ld returned 1 exit status
I'm not sure what to do about this. Is it actually possible to link static (mysql and my libs) and shared (sqlite3, pcre, ...) objects into a shared object?

Related

Using --whole-archive linker option with CMake and libraries with other library dependencies

I've got a project that used to be a giant set of source files that all got compiled and then linked as one executable. As a first step in making the project more modular, I am breaking up the build into several smaller chunks and making them static libraries. There's a hierarchy, so Exe1 will link against static libs Lib2A and Lib2B. Lib2A will depend on static Lib3A, lib3B, lib3C, etc. The numbers here show their layer in the hierarchy.
The problem is that I need to use --whole-archive when linking or else some symbols from the underlying libraries are not found.
When I add the below for the linking of Exe1:
target_link_libraries(Exe1 -Wl,--whole-archive Lib2A Lib2B -Wl,--no-whole-archive)
I end up with an actual link stage command like:
g++ -o Exe1 -Wl,--whole-archive libLib2A.a libLib2B.a -Wl,--no-whole-archive libLib3A.a libLib3B.a libLib3C.a
Inevitably, symbols from some of the layer 3 static libraries get lost and I get missing symbol errors.
I expected that because Lib2A has Lib3* libraries as dependencies, that they would also be "inside" the --whole-archive part of the linker command, but they show up outside.
I've tried many different combinations (e.g. putting the --whole-archive stuff at lower layers), but haven't come across an approach that works using CMake. What am I doing wrong?
Thanks
For 3.12 and newer versions of CMake, I would use object libraries.
The workaround I found for versions earlier than that was to create an intermediate static library that used some property magic to place all linkage dependencies inside the --whole-archive section. For me, the top-level static library was called 'source'. It contained actually nothing itself, but had linkage dependencies on a bunch of other static libraries. I created 'source-combined' as follows:
add_library(source-combined STATIC "")
set_target_properties(source-combined PROPERTIES LINKER_LANGUAGE CXX)
target_link_libraries(source-combined PUBLIC
-Wl,--whole-archive
$<TARGET_PROPERTY:source,INTERFACE_LINK_LIBRARIES>
-Wl,--no-whole-archive
)
Now when I create an executable or a shared library by linking against this souce-combined library, I get the --whole-archive and --no-whole-archive as bookends around the entire set of static libraries that were the link dependencies of 'source'. It took forever to stumble across this technique, so I'm sharing it.
The following worked for me. Consider two libraries:
my_platform
my_clib
We want the whole archive of my_clib, and my_platform links to it.
add_library(my_platform INTERFACE) # this could also be a regular library
add_library(my_clib STATIC)
target_sources(my_clib
PRIVATE
gcc_newlib_nano.c
gcc_newlib_nano_cpp.cc
)
# Link my_clib and any other libs
target_link_libraries(my_platform
INTERFACE
my_clib
)
# Ensure the whole archive is linked
target_link_options(my_platform
INTERFACE
-Wl,--whole-archive ${CMAKE_CURRENT_BINARY_DIR}/libmy_clib.a -Wl,--no-whole-archive
)
As an alternative to the above answer, I needed to get something quick and dirty to see if the effort to add whole archive target flags (or convert the code base to object libraries...) was the right solution. By following the CMake Source Code for the default link command, I modified my project's command to:
set(CMAKE_CXX_LINK_EXECUTABLE "<CMAKE_CXX_COMPILER> <FLAGS> <CMAKE_CXX_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> -Wl,--start-group -Wl,--whole-archive <LINK_LIBRARIES> -Wl,--no-whole-archive -Wl,--end-group")
It worked a treat! While not the greatest solution, it will at least get some results quickly.
If you need to use the linker option --whole-archive, then you definably should use object libraries:
# Lib2A/CMakeLists.txt
add_library(Lib2A OBJECT ${Lib2A_SRC})
# Lib2B/CMakeLists.txt
add_library(Lib2B OBJECT ${Lib2B_SRC})
It is portable and does not require use the linker option --whole-archive.

g++ not find .so files

I am trying to generate a c++ library using the g++ compiler. My library has another C library as dependency and I have compiled it in order to obtain the .so files.
I have the following structure:
src:
include/linux:
libcustom.a
libcustom.la
libcustom.so
libcustom.so.0
libcustom.so.0.0.0
Now, when I have all the .o files of my cpp classes, and I want to link the library, I execute the following command:
g++ -shared -L/usr/lib/R/lib -Wl,-Bsymbolic-functions -Wl,-z,relro -o mylibrary.so File1.o File2.o File3.o -L./include/linux -lc++ -lutil -lm -lcustom -Wl,-rpath='$ORIGIN/include/linux' -L/usr/lib/R/lib -lR
But it throws me the error:
libcustom.so.0: cannot open shared object file: No such file or directory
I am executing the command from the src directory.
I know it could be fixed editing the LD_LIBRARY_PATH, but the idea it is someone can use my library without the need of configuring anything, so I am trying to do that with the c++'s -rpath flag.
Any idea how can I fix it, or the reason for the error?
The error message you got seems to come from the run-time loader ld.so instead of the linker ld (I know the names are confusing). You have to distinguish between finding so's at link-time and at run-time. The -L flag you give at link-time has nothing to do with localizing the library at run-time.
Your rpath=./include/linux value is not correct, because dot is not recognized by the ld as relative path. Relative searching path should be given like
-Wl,-rpath='$ORIGIN/include/linux'
where the $ORIGIN represents the folder where your executable (not mylibrary.so) locates. Make sure to use single quote and not double quote because the string $ORIGIN should be passed to the linker literally and hard coded into the executable file.
More details goes
how to link to shared lib from shared lib with relative path
ld: Using -rpath,$ORIGIN inside a shared library (recursive)

Static and Dynamic/Shared Linking with MinGW

I want to start with a simple linking usage to explain my problem. Lets assume that there is a library z which could be compiled to shared library libz.dll(D:/libs/z/shared/libz.dll) or to static library libz.a (D:/libs/z/static/libz.a).
Let I want to link against it, then I do this:
gcc -o main.exe main.o -LD:/libs/z/static -lz
According to this documentation, gcc would search for libz.a, which is
archive files whose members are object files
I also can do the following:
gcc -o main.exe main.o -LD:/libs/z/shared -lz
It is not mentioned in the documentation above that -l flag will search for lib<name>.so.
What will happen if I libz.a and libz.dll will be in the same directory? How the library will be linked with a program? Why I need the flags -Wl,-Bstatic and -Wl,-Bdynamic if -l searches both for shared and static libraries?
Why some developers provide .a files with .dll files for the same modules, if I compile a shared library distribution?
For example, Qt provides .dll files in bin directory with .a files in lib directory. Is it the same library, but built like shared and static, respectively? Or .a files are some kind of dummy libraries which provide linking with shared libraries, where there are real library implementations?
Another example is OpenGL library on Windows. Why every compiler must provide the static OpenGL lib like libopengl32.a in MingW?
What are files with .dll.a and .la extensions used for?
P.S. There are a lot of questions here, but I think each one depends on the previous one and there is no need to split them into several questions.
Please, have a look at ld and WIN32 (cygwin/mingw). Especially, the direct linking to a dll section for more information on the behavior of -l flag on Windows ports of LD. Extract:
For instance, when ld is called with the argument -lxxx it will attempt to find, in the first directory of its search path,
libxxx.dll.a
xxx.dll.a
libxxx.a
cygxxx.dll (*)
libxxx.dll
xxx.dll
before moving on to the next directory in the search path.
(*) Actually, this is not cygxxx.dll but in fact is <prefix>xxx.dll, where <prefix> is set by the ld option -dll-search-prefix=<prefix>. In the case of cygwin, the standard gcc spec file includes -dll-search-prefix=cyg, so in effect we actually search for cygxxx.dll.
NOTE: If you have ever built Boost with MinGW, you probably recall that the naming of Boost libraries exactly obeys the pattern described in the link above.
In the past there were issues in MinGW with direct linking to *.dll, so it was advised to create a static library lib*.a with exported symbols from *.dll and link against it instead. The link to this MinGW wiki page is now dead, so I assume that it should be fine to link directly against *.dll now. Furthermore, I did it myself several times with the latest MinGW-w64 distribution, and had no issues, yet.
You need link flags -Wl,-Bstatic and -Wl,-Bdynamic because sometimes you want to force static linking, for example, when the dynamic library with the same name is also present in a search path:
gcc object1.o object2.o -lMyLib2 -Wl,-Bstatic -lMyLib1 -Wl,-Bdynamic -o output
The above snippet guarantees that the default linking priority of -l flag is overridden for MyLib1, i.e. even if MyLib1.dll is present in the search path, LD will choose libMyLib1.a to link against. Notice that for MyLib2 LD will again prefer the dynamic version.
NOTE: If MyLib2 depends on MyLib1, then MyLib1 is dynamically linked too, regardless of -Wl,-Bstatic (i.e. it is ignored in this case). To prevent this you would have to link MyLib2 statically too.

Error when static linking g++

I have a problem, i want to compile my application with static linking of mysql connector.
My command line:
g++ -o newserver stdafx.cpp ... -lboost_system -lboost_thread
-lpthread -lmysqlcppconn -static /usr/lib/libmysqlcppconn-static.a -std=c++0x
But i have error:
/usr/bin/ld: cannot find -lmysqlcppconn
/tmp/ccxpOfdZ.o: In function `IsEqualsDns(unsigned long, std::basic_string<char, std::char_traits<char>, std::allocator<char> >)':
Server.cpp:(.text+0x356e): warning: Using 'gethostbyname' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
collect2: ld returned 1 exit status
How can i fix this?
Thanks!
Where is the library libsqlcppconn.a or libsqucppconn.so
(static or dynamic)? The compiler is looking for it, and
doesn't find it.
Presumably, this is the same library as
/usr/lib/mysqlcppconn-static.a. If so, just drop the
-lmysqlcppconn. Or just use -lmysqlcppconn-static (no
spaces), and forget about the /usr/lib/libmysqlconn-static.a.
With a name like that, there shouldn't be a corresponding .so,
which means that g++ will link it statically, even without the
-static. You only need the -static if there is both
a libmysqlconn-static.so and a libmysqlconn-static.a in the
same directory.
With regards to the second error (which is just a warning, but
will cause problems if you try to run the linked program on
other machines, or even after an upgrade of your machine): if
you use -static anywhere in your command line (as you
currently do), then it applies to all files linked afterwards.
Including the system libraries, which you don't want to link
statically. My guess is that the -static isn't necessary (see
above); if it is, place it immediately before the library you
want to link statically, and place a -dynamic immediately
after (so that any following libraries, including the system
libraries, will be dynamically linked).
You could try g++ -static YOUR ARGUMENTS.
If you are coming from a Windows platform, linking against Boost can give a few surprises. The typicall Boost installation (e.g. after ./b2 install) will make both dynamic and static libraries and put them in the same directory. Typically, the two library forms only differ in their extension (.so or .a).
Windows supports auto-linking, which basically means that library files contain some flags in their first few bytes indicating whether they are for dynamic or for static linking. On Linux platforms, this is not the case and the linker gets confused which file to load (since you don't provide the extension of the library name). Therefore, you need to tell your linker which form of linking you want.

CMake: Shared library that uses static library

I am trying to create a shared library (really a Python module) that links against a static library. Both libraries are part of the same project and built using cmake.
Now, the shared library is built like this:
add_library(MyLibPython SHARED ${PYTHON_WRAPPERS_SRC})
set_target_properties(MyLibPython PROPERTIES PREFIX "")
target_link_libraries(MyLibPython MyLibStatic ${LIBS})
This builds without error, but when I try to import the Python module, I get:
ImportError:
lib/python/MyLibPython.so: undefined symbol: _Zone_of_my_MyLibStatic_functions
I also have a number of executables (unit tests) that are built in a similar way, and they work perfectly.
I should add, this is using gcc on Linux.
Check your linker command line. Is it passing something like -Wl,--as-needed? If so, it might not be including everything required by the static library.
I don't think your technique is portable in general. Can you get a shared library to link against? I think that there are some platforms where everything that goes into a shared library needs to be compiled as PIC.
Anyway, to link an entire archive with GNU ld (look up man ld):
gcc -o foo foo.o bar.o baz.o -Wl,--whole-archive libfoo.a -Wl,--no-whole-archive [rest-of-linker-args]