circularly linked static libraries (linux )undefined libraries - static-libraries

I did a build for static libraries and put then at a location. Now when i build my source i get UNDEFINED REFERENCES for inter library calls. For example:
/home/xyz/lib/libA.a(ClassA.a):undefined reference to classB::funB()
here classB.a is also a static library .
In my source's project file the static linking order is :
LIBS+= -lclassB -lclassA
Now when i reverse the libraries order i start getting error in classes of library B for function calls inside library A.

For this kind of situation you generally need e.g.
LIBS += -lclassA -lclassB -lclassA
Linking the classA library twice helps to resolve the circular dependencies.

Ok friends I have found the solution .
I was using qmake build tool on gcc , i just needeed to tell qmake that some of my static libraries are circularly dependent .
So i modified my .pro file with a qmake linker flag
QMAKE_LFLAGS += -Wl , --start-group --end-group
gcc's documentation says that you need to put your archive names between --start-group --end-group , but qmake is smart enough to find out the dependent libs , and will do that automatically .
Have Fun .

Related

CMake + Xcode: how to select arm64 vs x86_64 libraries?

We have a CMake based project targeting Xcode, and must include a precompiled 3rd party library which supplies separate arm64 and x86_64 binaries.
What we have working now is to simply attach both binaries like
add_library( someLib INTERFACE )
add_library( someLib_x64 STATIC IMPORTED )
set_target_properties(
someLib_x64
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/x64/libsomeLib.a"
)
add_library( someLib_arm STATIC IMPORTED )
set_target_properties(
someLib_arm
PROPERTIES
IMPORTED_LOCATION_RELEASE "path/to/arm/libsomeLib.a"
)
target_link_libraries(
someLib
INTERFACE
someLib_x64
someLib_arm
)
This seems to result in a valid compilation for both architectures (building for "Any Mac (Apple Silicon, Intel)"), however it causes a bunch of linker warnings as each architecture complains about the other one.
ld: warning: ignoring file /path/to/x64/libsomeLib.a, building for macOS-arm64 but attempting to link with file built for macOS-x86_64
and vice versa.
What is a more accurate way to do this that avoids linker warnings? I couldn't find an applicable generator expression to change the link path?
Edited, I misunderstood this previously. I think you have 3 options
suppress error, the error doesn't affect anything in fact, so the simplist way to
add_link_option("-w")
to ignore it, or just change link option for the target
try the latest cmake concept IMPORTED_TARGET, it looks like perfectly fit your demand, but require new cmake version
try to compile an universal library from source code, this is some example
change flag or cmake official example, but this looks like need another project for source code of the lib
UPDATE: ACCEPTED ANSWER:
Based on the documentation for IMPORTED_TARGET linked here, it revealed that you can use the symbol $(CURRENT_ARCH) in the library path, which is interpreted by Xcode at link time.
Works perfectly.
You can combine the two .a files into the fat binary and use the combined library for compilation. The linker will select the correct version based on the architecture.
To combine the .a library files, you can use the lipo command:
lipo -create 'path/to/x64/libsomeLib.a' 'path/to/arm/libsomeLib.a' \
-output 'path/to/combined/libsomeLib.a'
The combined library file can be reused until you need to install an update to the library. Alternatively, you can create a aggregate target to combine the library files every time you compile if you prefer not to manage the library manually.

How to handle gcc link options(like whole-archive, --allow-multiple-definition) in CMake?

I have a demo project and it's structure like as below:
top_dir
CMakeLists.txt
sub_dir1
CMakeLists.txt
sub_dir2
CMakeLists.txt
top_dir/sub_dir1/CMakeLists.txt used to build lib1 by using add_library(lib1 ...),
top_dir/sub_dir2/CMakeLists.txt used to build exe1 with linking lib1 by target_link_library(exe1 lib1).
And the content of top_dir/CMakeLists.txt is as below:
add_subdirectory(sub_dir2)
add_subdirectory(sub_dir1)
Normally, when build target exe1, cmake will check dependency so lib1 will be built before building exe1. The problem is I am transfering an existed makefile project into CMake, and there are many gcc link options, like "whole-archive ... no-whole-archive, allow-mutiple-definition", if use like target_link_library(exe1 "-Wl, --whole-archive ../sub_dir1/liblib1.a --no-whole-archive")(The form like this, and this may not work, it just a e.g.), cmake seem don't built lib1 any more. Is there any way i can use target_link_library like target_link_library(exe1 "-Wl, --whole-archive ../sub_dir1/liblib1.a") and cmake link dependency checking still work, or other way i can transfer these gcc link options into cmake?
Arguments for target_link_libraries are going into the resulted command line in the same order they appears. Whenever target name is used as argument, path to target's output is used in resulted command line. So, you may use library target whenever you need path to that library in the command line:
target_link_libraries(exe1 -Wl,--whole-archive lib1 -Wl,--no-whole-archive)
Such a way a target-level dependency between executable exe1 and library lib1 is automatically deduced by CMake, as usual.
The next hack permits to locally define the flags to the library to which you want to apply the flags, without modifying all exe link flags :
add_library(lib1_internal STATIC lib1.cpp)
add_library(lib1 STATIC dummy.cpp) # dummy.cpp is an empty file
target_link_libraries(lib1 PRIVATE -Wl,--whole-archive lib1_internal -Wl,--no-whole-archive )
....
target_link_libraries(exe1 lib1)

Building a Shared Library but linking against a Static One

I have an Autogen Makefile.am that I'm trying to use to build a test program for a shared library. To build my test binary, I want to continue building the shared library as target but I want the test program to be linked statically. I've spent the last few hours trying to craft my Makefile.am to get it to do this.
I've tried explicitly changing the LDADD line to use the .a version of the library and get a file not found error even though I can see this library is getting built.
I try to add the .libs directory to my link path via LDFLAGS and still it can't find it.
I tried moving my library sources to my test SOURCES list and this won't work because executable object files are built differently than those for static libraries.
I even tried replicating a lib_LIBRARIES entry for the .a version (so there's both a lib_LTLIBRARIES and a lib_LIBRARIES) and replicate all the LDFLAGS, SOURCES, dir and HEADERS for the shared version as part of the static version (replacing la with a of the form _a_SOURCES = _la_SOURCES. Still that doesn't work because now it can't figure out what to build.
My configure.ac file is using the default LT_INIT which should give me both static and dynamic libraries and as I said it is apprently building both even if the libtool can't see the .a file.
Please, anyone know how to do this?
As #Brett Hale mentions in his comment, you should tell Makefile.am that you want the program to be statically linked.
To achieve this you must append -static to your LDFLAGS.
Changing the LDFLAGS for a specific binary is achieved by changing binary_LDFLAGS (where binary is the name of the binary you want to build).
so something like this should do the trick:
binary_LDFLAGS = $(AM_LDFLAGS) -static

Difference between linking a library with -ldl and -l

I'm trying to link some VTK libraries in my program...and It is not working like this
-ldl /usr/lib/libvtkIO.so, which is the way CMake does. But If I compile it manually using -L -lvtkIO, it works. What is the difference ?
Is dynamic versus static linking?
Thanks
CMake tries to use the full path to the library, rather than letting the linker search the library path(s). If you use ldd on the resulting binaries you will see they are linked to the same thing (dynamically in both cases). For things like VTK it is generally best to use CMake as it also tracks things like interface libraries for you.
I think you have misunderstood some of the arguments to the linker, -lvtkIO would link to a library in the library path called libvtkIO.so, -ldl would link to a library called libdl.so. The -L argument is used to add additional paths the linker should search for libraries.

linker woes - undefined reference

I'm having a problem with my compiler telling me there is an 'undefined reference to' a function I want to use in a library. Let me share some info on the problem:
I'm cross compiling with gcc for C.
I am calling a library function which is accessed through an included header which includes another header, which contains the prototype.
I have included the headers directory using -I and i'm sure it's being found.
I'm first creating the .o files then linking them in a separate command.
So my thought is it might be the order in which I include the library files, but i'm not sure what is the correct way to order them. I tried with including the headers folder both before and after the .o file.
Some suggests would be great, and maybe and explanation of how the linker does its thing.
Thanks!
Response to answers
there is no .a library file, just .h and .c in the library, so -l isn't appropriate
my understanding of a library file is that it is just a collection of header and source files, but maybe it's a collection of .o files created from the source?!
there is no library object file being created, maybe there should be?? Yes seems I don't understand the difference between includes and libraries...i'll work on that :-)
Thanks for all the responses! I learned a lot about libraries. I'd like to put all the responses as the accepted answer :-)
Headers provide function declarations and function definitions. To allow the linker find the function's implementation (and get rid of the undefined reference) you need to ask the compiler driver (gcc) to link the specific library where the function resides using the -l flag. For instance, -lm will link the math library. A function's manual page typically specifies what library, if any, must be specified to find the function.
If the linker can't find a specified library you can add a library search path using the -L switch (for example, -L/usr/local/lib). You can also permanently affect the library path through the LIBRARY_PATH environment variable.
Here are some additional details to help you debug your problem. By convention the names of library files are prefixed with lib and (in their static form) have a .a extension. Thus, the statically linked version of the system's default math library (the one you link with -lm) typically resides in /usr/lib/libm.a. To see what symbols a given library defines you can run nm --defined-only on the library file. On my system, running the command on libm.a gives me output like the following.
e_atan2.o:
00000000 T atan2
e_asinf.o:
00000000 T asinf
e_asin.o:
00000000 T asin
To see the library path that your compiler uses and which libraries it loads by default you can invoke gcc with the -v option. Again on my system this gives the following output.
GNU assembler version 2.15 [FreeBSD] 2004-05-23 (i386-obrien-freebsd)
using BFD version 2.15 [FreeBSD] 2004-05-23
/usr/bin/ld -V -dynamic-linker /libexec/ld-elf.so.1 /usr/lib/crt1.o
/usr/lib/crti.o /usr/lib/crtbegin.o -L/usr/lib /var/tmp//ccIxJczl.o -lgcc -lc
-lgcc /usr/lib/crtend.o /usr/lib/crtn.o
It sounds like you are not compiling the .c file in the library to produce a .o file. The linker would look for the prototype's implementation in the .o file produced by compiling the library
Does your build process compile the library .c file?
Why do you call it a "library" if it's actually just source code?
I fear you mixed the library and header concepts.
Let's say you have a library libmylib.a that contains the function myfunc() and a corresponding header mylib.h that defines its prototype. In your source file myapp.c you include the header, either directly or including another header that includes it. For example:
/* myapp.h
** Here I will include and define my stuff
*/
...
#include "mylib.h"
...
your source file looks like:
/* myapp.c
** Here is my real code
*/
...
#include "myapp.h"
...
/* Here I can use the function */
myfunc(3,"XYZ");
Now you can compile it to obtain myapp.o:
gcc -c -I../mylib/includes myapp.c
Note that the -I just tells gcc where the headers files are, they have nothing to do with the library itself!
Now you can link your application with the real library:
gcc -o myapp -L../mylib/libs myapp.o -lmylib
Note that the -L switch tells gcc where the library is, and the -l tells it to link your code to the library.
If you don't do this last step, you may encounter the problem you described.
There might be other more complex cases but from your question, I hope this would be enough to solve your problem.
Post your makefile, and the library function you are trying to call. Even simple gcc makefiles usually have a line like this:
LIBFLAGS =-lc -lpthread -lrt -lstdc++ -lShared -L../shared
In this case, it means link the standard C library, among others
I guess you have to add the path where the linker can find the libraray. In gcc/ld you can do this with -L and libraray with -l.
-Ldir, --library-path=dir
Search directory dir before standard
search directories (this option must
precede the -l option that searches
that directory).
-larch, --library=archive
Include the archive file arch in the
list of files to link.
Response to answers - there is no .a library file, just .h and .c in the library, so -l isn't approriate
Then you may have to create the libraray first?
gcc -c mylib.c -o mylib.o
ar rcs libmylib.a mylib.o
I have encountered this problem when building a program with a new version of gcc. The problem was fixed by calling gcc with the -std=gnu89 option. Apparently this was due to inline function declarations. I have found this solution at https://gcc.gnu.org/gcc-5/porting_to.html

Resources