6

I have a strange problem: the code bellow perfectly compiled.
src.cpp:

extern "C" {
    #include "header.h"
}

void A::Execute() {
    B::Instance().Reset(ix);
    c_func(ix);// this is c functions declared in header.h
    C::Instance().Erase(ix);
}

But when I comment out the c_funk() I get linkage error in all places where I use c functions from the header.h file.

With that minor change:

void A::Execute() {
    B::Instance().Reset(ix);
    //c_func(ix);// this is c function declared in header.h
    C::Instance().Erase(ix);
}

I get: undefined reference to c_func().
Any ideas how to solve it? Thanks.

Update:
I have added a dummy function to header.h: foo_for_linkage_problem();
and in such way solved the problem. As I understand the linker try to make some optimization that couses this problem. new code:

void A::Execute() {
    B::Instance().Reset(ix);
    foo_for_linkage_problem();// this is c empty function declared in header.h 
    C::Instance().Erase(ix);
}
Todder
  • 85
  • 1
  • 6
  • So you're saying that if you try to use the function, your code compiles... and if you stop trying to use the function, the code fails to link because the function you're not using doesn't exist? That sounds rather backwards; perhaps you should create the most simple reproduction possible and include the full source and compiler output of that. – mah Apr 15 '15 at 14:41
  • hm... I afraid it is not possible to bring the code to here, as the code is of thousands lines length with complex and machine specific dependencies. – Todder Apr 15 '15 at 14:50
  • I do use this function (c_func() ) and other functions from the same c header in other places – Todder Apr 15 '15 at 14:52
  • 2
    If you are using c_func() from another places, then maybe header is included in another places without extern "C"? – Sandro Apr 15 '15 at 15:07
  • c_func() is defined or declared in header.h ? Sometimes you also should have a library file with function. – Sergei Nikulov Apr 15 '15 at 15:07
  • 3
    @Todder I understand all too well about "thousands of lines, complex, etc."... that's why I suggested _create the most simple reproduction_ etc. Reducing a problem like this to a small example is very useful -- not only does it enable you to get help from others efficiently (when the cause of the problem isn't obvious as in this case) but you'll often find that you can solve the problem on your own by taking that step. – mah Apr 15 '15 at 15:10
  • @Sandro I added the extern "c" inside the header.h. – Todder Apr 15 '15 at 15:30
  • @Sergey The declaration is in header.h, the implantation is in source files, all sources compiled to lib.a. – Todder Apr 15 '15 at 15:32
  • @Todder then add lib.a into compilation. – Sergei Nikulov Apr 15 '15 at 16:04
  • the lib.a is added, otherwise it would not compile when I call c_func(). – Todder Apr 15 '15 at 18:47

1 Answers1

23

tldnr: You have problem in the order the libraries are provided to linker.

I think that I know what is wrong. Let's assume that you have four files:

main.c:

#include <stdio.h>
    
int a();
int b();

int main()
{
    printf("%d\n", a());
    printf("%d\n", b());

    return 0;
}

main2.c:

#include <stdio.h>
    
int a();
int b();

int main()
{
    //printf("%d\n", a());
    printf("%d\n", b());

    return 0;
}

a.c:

int a()
{
    return 67;
}

b.c:

int a();

int b()
{
    return a()+5;
}

We create liba.a and libb.a:

gcc a.c -c -o a.o
gcc b.c -c -o b.o
ar rcs liba.a a.o
ar rcs libb.a b.o

Now we compile our exec:

gcc main.c liba.a libb.a -o test

And everything works just fine

gcc main2.c liba.a libb.a -o test

I get:

libb.a(b.o): In function `b':
b.c:(.text+0xa): undefined reference to `a'
collect2: error: ld returned 1 exit status

let's examine which symbols my libraries provides/requires:

$nm liba.a

a.o:
0000000000000000 T a

Symbol type T means that this library have file a.o which provides symbol a

$nm libb.a

b.o:
                 U a
0000000000000000 T b

libb.a contains file b.o which provides symbol b but requires symbol a

The linker does not include whole static library when asked. It looks which .o files are needed and links only those. Thus the order you provide the files is crucial.

When following command is executed, main.c gets compiled and it needs both a and b symbols. When linker gets liba.a library it links a.o file because it provides a symbol. When linker gets libb.a library it links b.o file because it provides b symbol. Everything works fine.

gcc main.c liba.a libb.a -o test

When the main2 command is executed, main2.c gets compiled and it needs only b symbols. When linker gets liba.a it does not link a.o becuase a is not needed at all. Then linker gets libb.a library it links b.o file because it provides b symbol. But the b.o file needs symbol a, and it is too late to link a.o, liba.a was already processed. Note that when I switch libraries it will compile cleanly:

gcc main2.c libb.a liba.a -o test
luantkow
  • 2,809
  • 20
  • 14