How do you link correctly in C to stop symbols being stripped?
Asked Answered
K

3

4

I'm having some trouble linking properly against libraries in C.

I'm sure this is one of those arcane C linking rules I don't fully understand, but I can't figure it out.

I have libn, which I compile into a static libary, libn.a

nm libn shows:

doug@ninja:~/projects/libnw/build$ nm ../../libn/build/libn.a |grep nIndex
00000034 T nIndex
00000000 D nIndex_
00000026 T nIndex_finalize
00000013 T nIndex_init
00000000 T nIndex_map

I also have libnw, which depends on libn. nm on libnw shows:

doug@ninja:~/projects/libnw/build$ nm libnw.a |grep Index
         U nIndex

However, when I compile a programming linking against libnw and libn I get:

doug@ninja:~/projects/libnw/build$ make
[ 70%] Built target nw
[ 80%] Built target test-template
Scanning dependencies of target test-Core
[ 85%] Building C object tests/nw/mvc/Core/CMakeFiles/test-Core.dir/Tests.c.o
[ 90%] Building C object tests/nw/mvc/Core/CMakeFiles/test-Core.dir/test.c.o
Linking C executable test-Core
../../../../libnw.a(Impl.c.o): In function `nwCore__Impl_init':
/home/doug/projects/libnw/src/nw/mvc/Core/Impl.c:76: undefined reference to `nIndex'
collect2: ld returned 1 exit status
make[2]: *** [tests/nw/mvc/Core/test-Core] Error 1
make[1]: *** [tests/nw/mvc/Core/CMakeFiles/test-Core.dir/all] Error 2
make: *** [all] Error 2

The reason, is quite clear. When Tests.c --> Tests.c.o, it's not picking nIndex up as a symbol it needs to keep:

doug@ninja:~/projects/libnw/build$ nm tests/nw/mvc/Core/CMakeFiles/test-Core.dir/Tests.c.o 
         U MyController
000005a4 T Tests
00000000 D Tests_
00000125 T Tests_can_attach_controller
00000080 T Tests_can_create_core
000003d3 T Tests_can_handle_native_event
000001c8 T Tests_can_set_controller
00000322 T Tests_can_update
00000000 t Tests_core_factory
0000056c T Tests_finalize
000005c0 T Tests_getType
0000048c T Tests_init
         U nFactory
         U nTest
         U nType_nalloc
         U nType_nfree
         U nwCore
         U nwDummyContext_getType
         U nwDummyEvents_getType
         U nwDummyRender_getType
         U nwIContext_getType
         U nwIEvents_getType
         U nwIRender_getType

(Notice the total absence of U nIndex in the tests object file).

So, I can fix this easily by adding a call to nIndex() in my tests script, but that doesn't solve the basic problem:

Program depends on liba depends on libb, liba has missing symbols from libb it needs to resolve, but program has no references to those symbols, so they seem to be being stripped.

What am I doing wrong?

(Yes, I'm building using cmake and depending on the statically built versions of libn and libnw).

Edit:

Now with linker line:

/usr/bin/gcc  -std=c99 -g   CMakeFiles/test-Core.dir/Tests.c.o \
      CMakeFiles/test-Core.dir/test.c.o \
      CMakeFiles/test-Core.dir/helpers/MyController.c.o \
      CMakeFiles/test-Core.dir/helpers/MyModel.c.o \
      -o test-Core -rdynamic \
      /home/doug/projects/tapspin-android/source/deps/libn/build/libn.a \
      ../../../../libnw.a 
Keynesianism answered 2/10, 2011 at 2:12 Comment(3)
This should be tagged with the particular c compiler or linker you are using because this is not a feature of the language, but of the program.Kingsize
(1) It's odd that you're getting a file called "Tests.c.o". Normally (using gcc, for example), you'd compile like this: gcc -c Tests.c, which would generate an object file called "Tests.o". (2) I see nothing in your question that's specific to C99; as far as I can tell, it's all equally applicable to C90. (3) Is there any sigificance to the ~ character in the first line of your question?Glycogenesis
I added c99 as a tag because I'm compiling using the c99 std and I wasn't sure if that was somehow relevant. The ~ isn't relevant at all (now removed for clarity), and as I mentioned I'm using cmake, which generates verbose object file paths (Tests.c.o) as described.Keynesianism
A
5

I don't see you link line so i's hard to tell for sure but this seems like it could be an ordering problem

If all of the symbols that are needed by libb are in liba, then you should list libb first, so that they are listed as symbols-to-be-resolved, and when libb is visited they will be resolved. This is not stripping per-se, it is just not including (i.e. it is omission not an active removal, am I splitting hairs? maybe)

Also, sometimes if there is a cyclical dependency (liba needs some symbols from libb and libb needs some symbols from liba) one has to list the libs multiple times (this is not a cmake answer as I do not use cmake, but have used linkers for many years, this where is a common error).

Note that unlike symbols from libraries, all symbols from object files are linked

Easiest fix to try first is just swap the order of the two libs

Anemometer answered 2/10, 2011 at 2:22 Comment(1)
Ah, you are so completely correct~ Swapping the order of the libraries was what I needed to do.Keynesianism
P
1

Since it is a problem of linking order, you can also solve it by using

--start-group

--end-group

GCC: what are the --start-group and --end-group command line options?

It works as long as we are speaking about static libraries/archive files.

Pyromania answered 18/6, 2013 at 12:18 Comment(3)
Putting the used libraries in correct order is normally the simplest solution. These flags really come in handy when there's no correct order (e.g. each library uses some symbols from the other).Micronutrient
You are right, but sadly enough I have seen many times that different compiler/linker versions behave differently, and some ordering error (previously committed) might show up only after updating the compiler/linker.Pyromania
Indeed, it's hard to say whether incorrect order would be a problem or not. Your solution is more bullet-proof.Micronutrient
P
1

To find the correct order of dependent libraries, the following *nix command pipeline can be used:

lorder libA.a libB.a ... | tsort

If one gets an error about a cyclical reference, then although the above GCC kludge using --start-group and --end-group will work, or simply listing the offending libraries a second time, one really ought to fix the libraries so they don't have cyclical dependencies.

Petes answered 25/11, 2014 at 23:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.