0

I'm working a patch-set to compile dpkg and APT onto Cygwin. I've almost got everything working, but I'm encountering some weird behavior with ar/g++ that I can't explain.

APT's stock Makefile uses some fancy wrapping around a pretty standard .cc → .o → .a flow for support libraries, which are then linked in with the main code. It works great under Linux. Under Cygwin, however, the linker stage, using slightly different commands, fails in a way that I don't understand.

Why is it that

g++ -g -O2 \
    -L../build/bin \
    -o ../build/bin/apt \
    ../build/obj/cmdline/apt.o \
    ../build/obj/apt-pkg/*.o \                                       ← (This is different.)
    -lapt-private -lbz2 -liconv -lintl -llzma -lz

works on my system, but

ar rcs ../build/bin/libapt-pkg.a ../build/obj/apt-pkg/*.o(This is different.)
g++ -g -O2 \
    -L../build/bin \
    -o ../build/bin/apt \
    ../build/obj/cmdline/apt.o \
    -lapt-pkg \                                                      ← (This is different.)
    -lapt-private -lbz2 -liconv -lintl -llzma -lz

doesn't? When I run the second one, libapt-pkg.a builds OK, but the g++ step produces errors of the form:

$ g++ -g -O2 -L../build/bin -o ../build/bin/apt ../build/obj/cmdline/apt.o -lapt-pkg -lapt-private -lbz2 -liconv -lintl -llzma -lz 2>&1 | head
../build/bin/libapt-private.a(private-upgrade.o): In function `CacheFile':
./apt/apt-private/../build/include/apt-private/private-cachefile.h:47: undefined reference to `pkgCacheFile::pkgCacheFile()'
./apt/apt-private/../build/include/apt-private/private-cachefile.h:47:(.text+0x1e): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `pkgCacheFile::pkgCacheFile()'

Shouldn't the two command sequences shown above be functionally equivalent? What's the difference?

  • 1
    Is pkgCacheFile::pkgCacheFile() defined in libapt-pkg.a? If it is, then try moving -lapt-pkg after -lapt-private. – Satō Katsura Aug 3 '15 at 8:25
  • @SatoKatsura, that works! How did you know that was the problem? Also, I'll upvote your answer if you submit it. – Nicholas Clark Aug 3 '15 at 17:43
  • I applaud Sato for spotting the problem — I didn’t see it — but, now that it’s been identified, I think I can explain it.  ld foo.o bar.o loads all of foo.o and all of bar.o.  By contrast, ld foo.o libquux.a or ld foo.o -lquux loads all of foo.o, and then anything from libquux.a that’s required to resolve undefined references in foo.o (i.e., in any code loaded so far).  That way, programs don’t get entire libraries loaded into them; they get only the pieces that they need.  … (Cont’d) – G-Man Aug 3 '15 at 21:57
  • (Cont’d) …  TL;DR  If pkgCacheFile::pkgCacheFile() is in libapt-pkg.a (i.e., it’s in one of the .o files in libapt-pkg.a), then it will get loaded (unconditionally) when you say ../build/obj/apt-pkg/*.o, but it will be loaded from libapt-pkg.a only if you put the -lapt-pkg after the first thing that calls pkgCacheFile::pkgCacheFile(). – G-Man Aug 3 '15 at 21:57
  • Thanks for the explanation, G-Man! Also for correcting the question ownership. – Nicholas Clark Aug 3 '15 at 23:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.