On 2004-11-15T19:27-0600, Bob Friesenhahn wrote: ) >> Yes. When you're making a distribution, Libtool's behaviour of directly ) >> linking indirect-dependencies is insane. For a SONAME change to a ) >> library deep in the stack, that only affects the library immediately ) >> above it, you suddenly need to rebuild your entire desktop environment.
Iteration 1: libgeneral provides general_utility(). libadmiral provides admiral_electric() and admiral_water(). libcadet provides cadet_dance(), which uses general_utility() and admiral_electric(). service uses cadet_dance() and admiral_water() in its main(). libcadet is linked to libgeneral and libadmiral. service is linked to libcadet and libadmiral. The resulting service executable is indirectly linked to libgeneral to satisfy libcadet's dependency. Iteration 2: libcadet is changed to use libgeneral2's general2_utility(). service is now indirectly linked to libgeneral2 to satisfy libcadet's dependency, and libgeneral is no longer in use. (21:43)[EMAIL PROTECTED]:~/test> make service COMPILE=gcc LINK=gcc gcc libgeneral.c -c -o libgeneral.o gcc libgeneral.o -shared -o libgeneral.so gcc libadmiral.c -c -o libadmiral.o gcc libadmiral.o -shared -o libadmiral.so gcc libcadet.c -c -o libcadet.o gcc libcadet.o -shared -o libcadet.so -L. -Wl,-rpath,. -lgeneral -ladmiral gcc service.c -c -o service.o gcc service.o -o service -L. -Wl,-rpath,. -lcadet -ladmiral (21:44)[EMAIL PROTECTED]:~/test> ldd service libcadet.so => ./libcadet.so (0xf6ffe000) libadmiral.so => ./libadmiral.so (0xf6ffb000) libc.so.6 => /lib/tls/libc.so.6 (0x00703000) libgeneral.so => ./libgeneral.so (0xf6fd9000) /lib/ld-linux.so.2 (0x006ea000) (21:44)[EMAIL PROTECTED]:~/test> ./service main cadet_dance general_utility admiral_electric admiral_water (21:44)[EMAIL PROTECTED]:~/test> The base case is sane. (21:46)[EMAIL PROTECTED]:~/test> make service COMPILE="libtool --mode=compile gcc" LINK="libtool --mode=link gcc" libtool --mode=compile gcc libgeneral.c -c -o libgeneral.o mkdir .libs gcc libgeneral.c -c -fPIC -DPIC -o .libs/libgeneral.o gcc libgeneral.c -c -o libgeneral.o >/dev/null 2>&1 libtool --mode=link gcc libgeneral.o -shared -o libgeneral.so gcc libgeneral.o -shared -o libgeneral.so libtool --mode=compile gcc libadmiral.c -c -o libadmiral.o gcc libadmiral.c -c -fPIC -DPIC -o .libs/libadmiral.o gcc libadmiral.c -c -o libadmiral.o >/dev/null 2>&1 libtool --mode=link gcc libadmiral.o -shared -o libadmiral.so gcc libadmiral.o -shared -o libadmiral.so libtool --mode=compile gcc libcadet.c -c -o libcadet.o gcc libcadet.c -c -fPIC -DPIC -o .libs/libcadet.o gcc libcadet.c -c -o libcadet.o >/dev/null 2>&1 libtool --mode=link gcc libcadet.o -shared -o libcadet.so -L. -Wl,-rpath,. -lgeneral -ladmiral gcc libcadet.o -shared -o libcadet.so -Wl,-rpath -Wl,. -L/home/boston/dreed/test -lgeneral -ladmiral libtool --mode=compile gcc service.c -c -o service.o gcc service.c -c -fPIC -DPIC -o .libs/service.o gcc service.c -c -o service.o >/dev/null 2>&1 libtool --mode=link gcc service.o -o service -L. -Wl,-rpath,. -lcadet -ladmiral gcc service.o -o service -Wl,-rpath -Wl,. -L/home/boston/dreed/test -lcadet -ladmiral (21:46)[EMAIL PROTECTED]:~/test> ldd service libcadet.so => ./libcadet.so (0xf6ffe000) libadmiral.so => ./libadmiral.so (0xf6ffb000) libc.so.6 => /lib/tls/libc.so.6 (0x00703000) libgeneral.so => ./libgeneral.so (0xf6fd9000) /lib/ld-linux.so.2 (0x006ea000) (21:46)[EMAIL PROTECTED]:~/test> Looks good. Let's try iteration 2's change... (21:50)[EMAIL PROTECTED]:~/test> make service2 COMPILE="libtool --mode=compile gcc" LINK="libtool --mode=link gcc" libtool --mode=compile gcc libgeneral2.c -c -o libgeneral2.o gcc libgeneral2.c -c -fPIC -DPIC -o .libs/libgeneral2.o gcc libgeneral2.c -c -o libgeneral2.o >/dev/null 2>&1 libtool --mode=link gcc libgeneral2.o -shared -o libgeneral2.so gcc libgeneral2.o -shared -o libgeneral2.so libtool --mode=compile gcc libcadet2.c -c -o libcadet2.o gcc libcadet2.c -c -fPIC -DPIC -o .libs/libcadet2.o gcc libcadet2.c -c -o libcadet2.o >/dev/null 2>&1 libtool --mode=link gcc libcadet2.o -shared -o libcadet.so -L. -Wl,-rpath,. -lgeneral2 -ladmiral gcc libcadet2.o -shared -o libcadet.so -Wl,-rpath -Wl,. -L/home/boston/dreed/test -lgeneral2 -ladmiral (21:50)[EMAIL PROTECTED]:~/test> ldd service libcadet.so => ./libcadet.so (0xf6ffe000) libadmiral.so => ./libadmiral.so (0xf6ffb000) libc.so.6 => /lib/tls/libc.so.6 (0x00703000) libgeneral2.so => ./libgeneral2.so (0xf6fd9000) /lib/ld-linux.so.2 (0x006ea000) (21:50)[EMAIL PROTECTED]:~/test> ./service main cadet_dance general2_utility admiral_electric admiral_water (21:50)[EMAIL PROTECTED]:~/test> Still good. The service executable is no longer linked to libgeneral.so in any way and works as expected. Let's try "full blown" Libtool (using .la files)... (22:00)[EMAIL PROTECTED]:~/test> make servicela COMPILE="libtool --mode=compile gcc" LINK="libtool --mode=link gcc" libtool --mode=compile gcc libgeneral.c -c -o libgeneral.lo mkdir .libs gcc libgeneral.c -c -fPIC -DPIC -o .libs/libgeneral.o gcc libgeneral.c -c -o libgeneral.o >/dev/null 2>&1 libtool --mode=link gcc libgeneral.lo -shared -o libgeneral.la -rpath /tmp gcc -shared .libs/libgeneral.o -Wl,-soname -Wl,libgeneral.so.0 -o .libs/libgeneral.so.0.0.0 (cd .libs && rm -f libgeneral.so.0 && ln -s libgeneral.so.0.0.0 libgeneral.so.0) (cd .libs && rm -f libgeneral.so && ln -s libgeneral.so.0.0.0 libgeneral.so) ar cru .libs/libgeneral.a libgeneral.o ranlib .libs/libgeneral.a creating libgeneral.la (cd .libs && rm -f libgeneral.la && ln -s ../libgeneral.la libgeneral.la) libtool --mode=compile gcc libadmiral.c -c -o libadmiral.lo gcc libadmiral.c -c -fPIC -DPIC -o .libs/libadmiral.o gcc libadmiral.c -c -o libadmiral.o >/dev/null 2>&1 libtool --mode=link gcc libadmiral.lo -shared -o libadmiral.la -rpath /tmp gcc -shared .libs/libadmiral.o -Wl,-soname -Wl,libadmiral.so.0 -o .libs/libadmiral.so.0.0.0 (cd .libs && rm -f libadmiral.so.0 && ln -s libadmiral.so.0.0.0 libadmiral.so.0) (cd .libs && rm -f libadmiral.so && ln -s libadmiral.so.0.0.0 libadmiral.so) ar cru .libs/libadmiral.a libadmiral.o ranlib .libs/libadmiral.a creating libadmiral.la (cd .libs && rm -f libadmiral.la && ln -s ../libadmiral.la libadmiral.la) libtool --mode=compile gcc libcadet.c -c -o libcadet.lo gcc libcadet.c -c -fPIC -DPIC -o .libs/libcadet.o gcc libcadet.c -c -o libcadet.o >/dev/null 2>&1 libtool --mode=link gcc libcadet.lo -shared -o libcadet.la -rpath /tmp -L. -Wl,-rpath,. -lgeneral -ladmiral gcc -shared .libs/libcadet.o -Wl,--rpath -Wl,/home/boston/dreed/test/.libs -Wl,--rpath -Wl,/tmp -L/home/boston/dreed/test /home/boston/dreed/test/.libs/libgeneral.so /home/boston/dreed/test/.libs/libadmiral.so -Wl,-rpath -Wl,. -Wl,-soname -Wl,libcadet.so.0 -o .libs/libcadet.so.0.0.0 (cd .libs && rm -f libcadet.so.0 && ln -s libcadet.so.0.0.0 libcadet.so.0) (cd .libs && rm -f libcadet.so && ln -s libcadet.so.0.0.0 libcadet.so) ar cru .libs/libcadet.a libcadet.o ranlib .libs/libcadet.a creating libcadet.la (cd .libs && rm -f libcadet.la && ln -s ../libcadet.la libcadet.la) libtool --mode=compile gcc service.c -c -o service.o gcc service.c -c -fPIC -DPIC -o .libs/service.o gcc service.c -c -o service.o >/dev/null 2>&1 libtool --mode=link gcc service.o -o service -L. -Wl,-rpath,. -lcadet -ladmiral gcc service.o -o .libs/service -Wl,-rpath -Wl,. -L/home/boston/dreed/test /home/boston/dreed/test/.libs/libcadet.so /home/boston/dreed/test/.libs/libgeneral.so /home/boston/dreed/test/.libs/libadmiral.so -Wl,--rpath -Wl,/tmp creating service (22:00)[EMAIL PROTECTED]:~/test> env LD_LIBRARY_PATH=.libs ldd .libs/service libcadet.so.0 => .libs/libcadet.so.0 (0xf6ffe000) libgeneral.so.0 => .libs/libgeneral.so.0 (0xf6ffb000) libadmiral.so.0 => .libs/libadmiral.so.0 (0xf6ff9000) libc.so.6 => /lib/tls/libc.so.6 (0x00703000) /lib/ld-linux.so.2 (0x006ea000) (22:00)[EMAIL PROTECTED]:~/test> We're beginning to see trouble here. Libtool explicitly linked service against .libs/libgeneral.so, even though I did not specify it as a dependency of the service executable (no explicit -lgeneral). Let's try iteration 2... (22:07)[EMAIL PROTECTED]:~/test> make servicela2 COMPILE="libtool --mode=compile gcc" LINK="libtool --mode=link gcc" libtool --mode=compile gcc libgeneral2.c -c -o libgeneral2.lo gcc libgeneral2.c -c -fPIC -DPIC -o .libs/libgeneral2.o gcc libgeneral2.c -c -o libgeneral2.o >/dev/null 2>&1 libtool --mode=link gcc libgeneral2.lo -shared -o libgeneral2.la -rpath /tmp gcc -shared .libs/libgeneral2.o -Wl,-soname -Wl,libgeneral2.so.0 -o .libs/libgeneral2.so.0.0.0 (cd .libs && rm -f libgeneral2.so.0 && ln -s libgeneral2.so.0.0.0 libgeneral2.so.0) (cd .libs && rm -f libgeneral2.so && ln -s libgeneral2.so.0.0.0 libgeneral2.so) ar cru .libs/libgeneral2.a libgeneral2.o ranlib .libs/libgeneral2.a creating libgeneral2.la (cd .libs && rm -f libgeneral2.la && ln -s ../libgeneral2.la libgeneral2.la) libtool --mode=compile gcc libcadet2.c -c -o libcadet2.lo gcc libcadet2.c -c -fPIC -DPIC -o .libs/libcadet2.o gcc libcadet2.c -c -o libcadet2.o >/dev/null 2>&1 libtool --mode=link gcc libcadet2.lo -shared -o libcadet.la -rpath /tmp -L. -Wl,-rpath,. -lgeneral2 -ladmiral rm -fr .libs/libcadet.a .libs/libcadet.la .libs/libcadet.lai .libs/libcadet.so .libs/libcadet.so.0 .libs/libcadet.so.0.0.0 gcc -shared .libs/libcadet2.o -Wl,--rpath -Wl,/home/boston/dreed/test/.libs -Wl,--rpath -Wl,/tmp -L/home/boston/dreed/test /home/boston/dreed/test/.libs/libgeneral2.so /home/boston/dreed/test/.libs/libadmiral.so -Wl,-rpath -Wl,. -Wl,-soname -Wl,libcadet.so.0 -o .libs/libcadet.so.0.0.0 (cd .libs && rm -f libcadet.so.0 && ln -s libcadet.so.0.0.0 libcadet.so.0) (cd .libs && rm -f libcadet.so && ln -s libcadet.so.0.0.0 libcadet.so) ar cru .libs/libcadet.a libcadet2.o ranlib .libs/libcadet.a creating libcadet.la (cd .libs && rm -f libcadet.la && ln -s ../libcadet.la libcadet.la) (22:07)[EMAIL PROTECTED]:~/test> env LD_LIBRARY_PATH=.libs ldd .libs/service libcadet.so.0 => .libs/libcadet.so.0 (0xf6ffe000) libgeneral.so.0 => .libs/libgeneral.so.0 (0xf6ffb000) libadmiral.so.0 => .libs/libadmiral.so.0 (0xf6ff9000) libc.so.6 => /lib/tls/libc.so.6 (0x00703000) libgeneral2.so.0 => /home/boston/dreed/test/.libs/libgeneral2.so.0 (0xf6fd7000) /lib/ld-linux.so.2 (0x006ea000) (22:07)[EMAIL PROTECTED]:~/test> Brilliant. Because service was not recompiled against the new libcadet.la, it now links against both libgeneral.so and libgeneral2.so (the latter by way of the new libcadet.so) :( In situations where only the .so is present, Libtool arguably does the right thing. (It does not try to guess dependency dependencies based on ldd or anything like that; it just doesn't link in dependency dependencies.) In situations where the .la is present, Libtool *does* try to link in dependency dependencies, even though that isn't necessary. I believe the point of this proposed change is to eliminate that latter behavior. It would be a benefit on Linux and similar systems without directly hindering dissimilar systems (as the behavior would not change on those systems). As far as encouraging developers to list dependencies incorrectly or not at all, in the above scenario, even if the package developer had caused the service executable's build scripts to link explicitly against its dependencies dependencies (libgeneral, in this case), it still would have broken on systems that do not implicitly link dependencies dependencies at run time (as service would have been explicitly linked with libgeneral, not libgeneral2, just as with the current Libtool behavior when dealing with .la files). I do not believe there is a developer education danger from this proposed change. -- Daniel Reed <[EMAIL PROTECTED]> http://people.redhat.com/djr/ http://naim.n.ml.org/ "Murphy's Law is recursive. Washing your car to make it rain doesn't work." _______________________________________________ Libtool mailing list [EMAIL PROTECTED] http://lists.gnu.org/mailman/listinfo/libtool