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?

Nicholas Clark
  • 322
  • 1
  • 2
  • 10
  • 1
    Is `pkgCacheFile::pkgCacheFile()` defined in `libapt-pkg.a`? If it is, then try moving `-lapt-pkg` after `-lapt-private`. – Satō Katsura Aug 03 '15 at 08: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 03 '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 Says 'Reinstate Monica' Aug 03 '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 Says 'Reinstate Monica' Aug 03 '15 at 21:57
  • Thanks for the explanation, G-Man! Also for correcting the question ownership. – Nicholas Clark Aug 03 '15 at 23:02

0 Answers0