question about headers and objects files

Hi all,
I have a question regarding how GCC relates a header file and its binary file.
The following example from "An Introduction to GCC" will help me to explain it better:

main.c
1
2
3
4
5
6
7
#include <math.h>
#include <stdio.h>
int main (void){
    double x = sqrt (2.0);
    printf ("The square root of 2.0 is %f\n", x);
    return 0;
}


we can compile it by running the line:

 
gcc main.c -lm -o main


My question is: How GCC knows where is the definition of sqrt?
First I was thinking that there was and object file with the name math.o inside libm.a (that is GCC will look for an object file with the same name as the header file), but after running the next line I think my assumption was wrong as there is not such file in libm.a.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
nm libm.a | grep math.o
nm: e_acos.o: no symbols
nm: k_cos.o: no symbols
nm: k_sin.o: no symbols
nm: s_cos.o: no symbols
nm: s_scalbln.o: no symbols
nm: s_lrint.o: no symbols
nm: s_llround.o: no symbols
nm: s_lrintf.o: no symbols
nm: e_rem_pio2l.o: no symbols
nm: k_cosl.o: no symbols
nm: k_rem_pio2l.o: no symbols
nm: k_sinl.o: no symbols
nm: k_tanl.o: no symbols
nm: s_nexttowardl.o: no symbols
nm: s_lrintl.o: no symbols
nm: t_sincosl.o: no symbols
nm: k_sincosl.o: no symbols




Any help would be much appreciated!
header files are not related to object files at all. gcc (technically, ld) will examine libc, libm, and all other libraries provided looking for the symbol sqrt, regardless of object file names.
thanks. when you say all the libraries provided, you means all the libraries listed when linking?

If we have these files...
1
2
a.h
int foo();


1
2
b.h 
int foo();

1
2
3
4
5
a.c
#include "a.h"
int foo(){
   //do a
}


1
2
3
4
5
b.c
#include "b.h"
int foo(){
   //do b
}


1
2
3
4
5
call_a.c
#include "a.h"
int call_a(){
   foo();
}



and we compile as follows.
gcc -o call_a.c a.c b.c

Assuming that a.h is the header of a.c; how does ld solve the reference to foo() inside call_a()?
Last edited on
The short answer is, it won't link.

Long answer:
After the preprocessor stage, you are left with three translation units:
TU "a"
1
2
3
4
int foo();
int foo(){
   //do a
}


TU "b"
1
2
3
4
int foo();
int foo(){
   //do b
}


TU "call_a"
1
2
3
4
int foo();
int call_a(){
   foo();
}


After the compilation stage, you have three object files:

$ nm a.o
0000000000000000 T foo
$ nm b.o
0000000000000000 T foo
$ nm call_a.o
0000000000000000 T call_a
                 U foo


then at linking stage, the linker is presented with undefined symbol foo in the module call_a.o, and two identically-named symbols foo in other object files (one in a.o, one in b.o).

This is an error even without call_a, just try to link together a.c and b.c and it will fail:

b.o: In function `foo':
b.c:(.text+0x0): multiple definition of `foo'
a.o:a.c:(.text+0x0): first defined here


Last edited on
I see, so the only way to deal with it is using namespace?
Last edited on
I would add another thing, that probably will help santiago.
Perhaps things can be a little clearer if you divide "compiling phase" and "linking phase". It will be usefull expecially when you will develop project made by more than one .cpp file (in your example you "compile" and "link" using only one command. In larger programs you will divide steps).

 
gcc -c -o main.o main.cpp

First step: compiling. During compiling phase the cpp file will be analyzed trying to see if there are sintax errors and all functions / classes are declared (included headers are "inglobed" in cpp). This phase, however, doesn't care WHERE actually a function or a classes is defined.
In the example, the sqrt function is declared in math header file (defined in libm.a, but it is no interest during compiling phase) so it will passed succesfull.

 
gcc -o test main.o -lm

here is the linking phase. During this phase the linker of gcc will analyze all modules (*.o and libraries) and "solve" every definitions (addressing to the module that actually defines every function).
The linking phase will ok becouse using -lm you will add the libm.a that actually contains the definition of sqrt. If -lm missing the linking phase will be return an error (undefined module or something similar) even if the main.cpp was compiled successfully.
This probably will help you to understand better what Cubbi explained before (I hope so).

----

Edit1:
> I see, so the only way to deal with it is using namespace?

To be simple, yes.

To be complex, you can also, as another option, to compile the two modules with the two functions (with the same name) providing preprocessor options... I am thinking about a case where you want to control the compiling in order to ensure that only one of those functions would actually exists in your system. But this option is a little harder to explain well (and mostly useful when you try to provide some little differences for different OS).
If you didn't understood (sorry if I was not clear), you can consider my answer as I said "yes, only using namespaces"

EDIT2: namespaces exists only in c++ not in c as Cubby correctly pointed. So read my "edit1" as a general answer for c++ (not related with the example)
Last edited on
so the only way to deal with it is using namespace?

What exactly is the problem you want to deal with using namespaces?

Also, is this question about C or C++? sqrt() is not in libm in C++, and there are no namespaces in C.
Thanks for the prompt replies!
I wasn't sure how GCC searches for references to external functions when linking.
Last edited on
Topic archived. No new replies allowed.