Check that all symbols defined in static library - c

I built some static library with no errors.
When I tried to link it to some app I realized that some symbols is undefined inside library.
I want to get error on library building step not on app.
In other words
$ cat mylib.h
void foo();
$ cat mylib.c
#include "mylib.h"
// no foo() implementation here;
$ cat test.c
#include "mylib.h"
int main() {
foo();
return 0;
}
$ gcc mylib.c -c
$ ar crf libmylib.a *.o
$ gcc test.c -lmylib -L.
/tmp/cc7201uP.o: In function `main':
test.c:(.text+0xa): undefined reference to `foo'
collect2: error: ld returned 1 exit status
I want to get error at one of those step
$ gcc mylib.c -c
$ ar crf libmylib.a *.o
Is it possible, and what is good practice for such situations?
Updated:
I tried
$ nm --undefined-only *.a
output is :
mylib.o:
It's little bit strange for me. I expect something like foo() inside output.

A static library is just a bunch of .o files and those are expected to have undefined references. No linking is involved when producing a .a from .o files.
You can run nm --undefined-only libmylib.a and that produces a list of all undefined symbols. That list will include all the symbols you use from C standard library because, again, no linking is involved when producing .a files.

Related

Hiding symbols from a DSO with DT_FILTER

I was recently trying to hide some symbols from 3rd party DSO and came across "--filter" LD option for creating "filter DSO". From the ld manpage, I have an impression that the dynamic linker will only take into account symbols which are present in filter DSO's dynsym:
"The dynamic linker will resolve symbols according to the symbol
table of the filter object as usual, but it will actually link to the
definitions found in the shared object name."
So it looks just what I need: a way to select which symbols from a DSO take part in dynamic linkage. Unfortunately, it does not work as I expect (this example can also be cloned from github)
Makefile:
lib1.so: lib1.c
gcc -shared -fPIC $^ -o $#
lib2.so: lib2.c
gcc -shared -fPIC $^ -o $#
lib2f.so: lib2f.c
gcc -shared -fPIC -Wl,--filter,lib2.so $^ -o $#
main: lib1.so lib2.so lib2f.so main.c
gcc main.c -L. -l2f -l1 -o $#
clean:
rm *.o *.so main
lib1.c
#include <stdio.h>
void func1()
{
printf("func1#lib1\n");
}
void func2()
{
printf("func2#lib1\n");
}
lib2.c
#include <stdio.h>
void func1()
{
printf("func1#lib2\n");
}
void func3()
{
printf("func3#lib2\n");
}
lib2f.c (filter for lib2.so):
void func3() {}
Executable
void func1();
void func2();
void func3();
int main()
{
func1();
func2();
func3();
return 0;
}
When I run that test program, I get following output:
> LD_LIBRARY_PATH=. ./main
func1#lib2
func2#lib1
func3#lib2
One can see that a symbol from lib2 is actually referenced despite the attempt to "filter" it with lib2f.so. What I would like the output to look like is
> LD_LIBRARY_PATH=. ./main
func1#lib1 // use func1 from lib1
func2#lib1
func3#lib2
Is it at all possible to achieve my goal (hiding some symbols from a DSO) with ld --filter option (aka DT_FILTER)?
If not, what is wrong in my expectations/reading of man pages?
Described behavior occurs on glibc 2.34 and 2.17.
According to https://sourceware.org/bugzilla/show_bug.cgi?id=27977:
DT_NEEDED puts the referenced object after the current object in the search scope. DT_FILTER puts it before it. I believe this is the only difference in the current glibc implementation. There is simply no filtering. It has been this way since basically forever
I'm trying to achieve the same thing. Looks like this is sensitive to the link order. I moved the -l1 before -l2f, i.e., change your link line in the Makefile to
main: lib1.so lib2.so lib2f.so main.c
gcc main.c -L. -l1 -l2f -o $#
With that I get:
$ ./main
func1#lib1
func2#lib1
func3#lib2

Unable to identify issue GNU archiver. Compiling with *.o works but libname.a dosen't

I'm trying to make a static library (.a) but facing issues that I'm unable to understand. So in brief compiling with *.o succeeds but archiving them using ar and then using the .a file to compile gives me an undefined reference to 'symbol' error.
So here is a simple code.
test.c
#include <stdio.h>
#include <string.h>
int main()
{
hello_world();
return 0;
}
hello_world.c
#include<stdio.h>
void hello_world (void) {
printf("Hello World\n");
}
Compile.
gcc -c -o hello_world.o hello_world.c
ar crs libhello.a hello_world.o
gcc libhello.a -o test test.c
gives me the error
/tmp/ccsO7AJl.o: In function `main':
test.c:(.text+0xa): undefined reference to `hello_world'
Instead doing this works(Compiles and runs fine)
gcc -c -o hello_world.o hello_world.c
gcc hello_world.o -o test test.c
I have no idea what I have done wrong so any help is appreciated.
This is an almost duplicate of Why does the order of '-l' option in gcc matter? - but the behaviour can be replicated without the -l switch by specifying the archive name on command line.
The GNU linker as executed by GCC will, by default, link from left to right, and only use those .o files from the library archive that are needed to satisfy undefined references so far. Since your library precedes the main translation unit on the command line, hello_world is not required at the time the linker is processing it.
The solution is to mention the library after the translation units/object files that depend on it:
gcc -o test test.c libhello.a

ld would not link the static library because of it consider the library is not needed, but I need this library [duplicate]

I have a program and a static library:
// main.cpp
int main() {}
// mylib.cpp
#include <iostream>
struct S {
S() { std::cout << "Hello World\n";}
};
S s;
I want to link the static library (libmylib.a) to the program object (main.o), although the latter does not use any symbol of the former directly.
The following commands do not seem to the job with g++ 4.7. They will run without any errors or warnings, but apparently libmylib.a will not be linked:
g++ -o program main.o -Wl,--no-as-needed /path/to/libmylib.a
or
g++ -o program main.o -L/path/to/ -Wl,--no-as-needed -lmylib
Do you have any better ideas?
Use --whole-archive linker option.
Libraries that come after it in the command line will not have unreferenced symbols discarded. You can resume normal linking behaviour by adding --no-whole-archive after these libraries.
In your example, the command will be:
g++ -o program main.o -Wl,--whole-archive /path/to/libmylib.a
In general, it will be:
g++ -o program main.o \
-Wl,--whole-archive -lmylib \
-Wl,--no-whole-archive -llib1 -llib2
The original suggestion was "close":
How to force gcc to link unreferenced, static C++ objects from a library
Try this: -Wl,--whole-archive -lyourlib
I like the other answers better, but here is another "solution".
Use the ar command to extract all the .o files from the archive.
cd mylib ; ar x /path/to/libmylib.a
Then add all those .o files to the linker command
g++ -o program main.o mylib/*.o
If there is a specific function in the static library that is stripped by the linker as unused, but you really need it (one common example is JNI_OnLoad() function), you can force the linker to keep it (and naturally, all code that is called from this function). Add -u JNI_OnLoad to your link command.

Missing symbol compile error in C. Basic header file setup

I'm working on a C project implementing some generic containers and am having this weird issue when compiling. Here is some sample code that also replicates the error.
foo.h
void fooprint(void);
foo.c
#include "foo.h"
#include <stdio>
void fooprint(void){
printf("bar");
return;
}
main.c
#include "foo.h"
int main(void){
fooprint();
return 0;
}
I compile by typing
gcc main.c -o main
and this is what terminal outputs
Undefined symbols:
"_fooprint", referenced from:
_main in ccfMXGzj.o
ld: symbol(s) not found
collect2: ld returned 1 exit status
I'm compiling this on an OSX system but have also tried compiling on a red hat machine with the same effect.
The solution is probably painfully obvious but I have had multiple friends I'm working with look at this and they couldnt see the problem. I've googled around a lot but most symbol error issues are usually pertaining to objective C.
You need to compile them together:
gcc -Wall -Wextra -o main main.c foo.c
Or maybe make a Makefile ?
all: main
main: main.o foo.o
main.o: main.c
foo.o: foo.c
You have to compile also foo.c into an object file and link all of them together:
gcc -o foo.o foo.c
gcc -o main.o main.c
gcc -o main main.o foo.o
Yes, this is simple, so I recommend you to read a good C book and step these easy steps.

Creating libraries in C/C++ - ld can't find my library

I'm trying to learn how to create a C/C++ library in a linux environment but I'm having a problem (probably a trivial one) that online tutorials had not helped to solve.
For definiteness let's say I have a foo.c file with the following code:
//file: foo.c
#include <stdio.h>
void hello(void)
{
printf("hello!\n");
}
a foo.h:
//file: foo.h
void hello(void);
and a program that uses the function hello() from foo.c, named prog.c:
//file: prog.c
#include "foo.h"
int main(void)
{
hello();
return 0;
}
The three files are all on the same directory. Then I compiled foo.c with:
gcc -fPIC -c foo.c
and got a foo.o file. Then I used ld to create the library file:
ld -G foo.o -o libfoo.so
But when I try to compile prog.c with:
gcc -o prog prog.c -lfoo
I got an error message:
/usr/bin/ld: cannot find -lfoo
collect2: ld returned 1 exit status
I'm convinced that this is some kind of trivial path problem, but I couldn't find the solution. So my question is really if this procedure above is wrong or if I have to put the libfoo.so file in a special path.
Another question is how this changes if I'm using g++ instead of gcc.
Thanks.
EDIT:
I know I can compile both prog.c and foo.c to prog.o and foo.o an then link them to make an executable. But in my original problem I want to compile foo.c in a way that I can distribute to people who will use my functions in their own programs.
ld doesn't search the current directory by default. If you want it to do this you need to use the -L command line option, so if your library is in the current directory you need to add -L. to the last gcc call. If the library is dynamically linked you also need to add the current directory to the environment variable LD_LIBRARY_PATH (I assume you're on linux).
Of course, if your library is in any other non-standard path you need to use that instead of the current directory.
Try
gcc -o prog prog.c -lfoo -L.
The -L switch adds its argument to the set of paths that ld looks in for library files. The syntax is identical for g++.

Resources