Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 9 Mar 2017 12:35:32 +0100
From:      Tijl Coosemans <tijl@FreeBSD.org>
To:        Dag-Erling =?UTF-8?B?U23DuHJncmF2?= <des@des.no>
Cc:        Baptiste Daroussin <bapt@FreeBSD.org>, ports@FreeBSD.org, arch@FreeBSD.org
Subject:   Re: manpath change for ports ?
Message-ID:  <20170309123532.09b87366@kalimero.tijl.coosemans.org>
In-Reply-To: <861su6ont5.fsf@desk.des.no>
References:  <20170306235610.cmpxk27jhoafel6l@ivaldir.net> <86mvcvojzt.fsf@desk.des.no> <20170308204126.6d152c44@kalimero.tijl.coosemans.org> <861su6ont5.fsf@desk.des.no>

next in thread | previous in thread | raw e-mail | index | archive | help
On Thu, 09 Mar 2017 09:29:42 +0100 Dag-Erling Sm=C3=B8rgrav <des@des.no> wr=
ote:
> Tijl Coosemans <tijl@FreeBSD.org> writes:
>> If you want to run a program from its build directory and the program
>> links to a library also in the build directory then you have to run the
>> program with LD_LIBRARY_PATH environment variable set to the build
>> directory.  Or, you could link the program with -rpath <builddir>, but
>> then you should relink it before installation.  It's one of the things
>> libtool takes care of automatically.
>>
>> If this is the problem you have then it has nothing to do with gcc.  If
>> you're not using libtool then your program probably does not have any
>> rpath or runpath so it falls back on rtld/ldconfig which may find it in
>> /usr/local/lib. =20
>=20
> You are correct in theory, but I am using libtool and it doesn't work.
>=20
> Here's a series of emails I wrote to the maintainer a little over six
> months ago explaining the problem:
>=20
> 1)
>=20
> | I discovered that lang/gcc48 (and presumably the other gcc ports as
> | well) not only have /usr/local/include in their default include path,
> | but actually place it ahead of /usr/include.  This is causing me no end
> | of grief with software that uses iconv, because GNU libiconv's <iconv.h>
> | f*s up your namespace so the build fails unless you explicitly link with
> | GNU libiconv instead of using the libc version.  [...]

Right, to use libc iconv(3) with -I/usr/local/include and GNU libiconv
installed you have to compile with -DLIBICONV_PLUG.

> 2)
>=20
> |                              [...] I realized over the weekend that the
> | situation is even worse than I initially thought.  Basically, ports gcc
> | is unusable for any other purpose than to build ports which don't
> | support clang.  Let me explain with a hypothetical scenario:
> |=20
> | You are developing a library which is important enough that you need to
> | have the stable version installed on your development system.  It is
> | installed in /usr/local as usual.  You've been working on fixing a bug,
> | and have written a unit test which exercises the relevant code and
> | verified that it can deterministically trigger the bug.  You fix the bug
> | and 'make check' again, all green.  Then you clean out your working
> | copy, re-run configure with CC=3Dgcc and 'make check' again.  Your tests
> | fail.
> |=20
> | What happened is that when you built your code with gcc, the tests were
> | linked and run with the stable version of the library, where the bug is
> | not fixed.  You can build with LDFLAGS=3D-L$(top_builddir)/lib, you can
> | even specify the full path to the library in LDADD for each individual
> | test, it doesn't matter.  It will *always* pick the installed version
> | first.  The only way to get your tests to pass is to not have the
> | library installed.
> |=20
> | Real-world example - a 10.3 system with upstream OpenPAM installed
> | because it uses OpenPAM's OATH implementation:
> |=20
> | with base clang:
> |=20
> | des@desk ~/src/openpam/trunk% libtool exec ldd ./t/t_openpam_dispatch
> | /home/des/src/openpam/trunk/t/.libs/t_openpam_dispatch:
> | 	libpam.so.2 =3D> /home/des/src/openpam/trunk/lib/libpam/.libs/libpam.s=
o.2 (0x800822000)
> | 	liboath.so.2 =3D> /home/des/src/openpam/trunk/lib/liboath/.libs/liboat=
h.so.2 (0x800a34000)
> | 	libcrypto.so.7 =3D> /lib/libcrypto.so.7 (0x800c39000)
> | 	libc.so.7 =3D> /lib/libc.so.7 (0x80102f000)
> |=20
> | with lang/gcc:
> |=20
> | des@desk ~/src/openpam/trunk% pkg which =3Dgcc
> | /usr/local/bin/gcc was installed by package gcc-4.8.5_2
> | des@desk ~/src/openpam/trunk% libtool exec ldd ./t/t_openpam_dispatch
> | /home/des/src/openpam/trunk/t/.libs/t_openpam_dispatch:
> | 	libpam.so.2 =3D> /usr/local/lib/libpam.so.2 (0x800822000)
> | 	liboath.so.2 =3D> /usr/local/lib/liboath.so.2 (0x800a34000)
> | 	libcrypto.so.7 =3D> /lib/libcrypto.so.7 (0x800c39000)
> | 	libc.so.7 =3D> /lib/libc.so.7 (0x80102f000)
> | 	libcrypto.so.8 =3D> /usr/local/lib/libcrypto.so.8 (0x8013dc000)
> | 	libthr.so.3 =3D> /lib/libthr.so.3 (0x8017e9000)
> |=20
> | (and don't ask me why the gcc version is linked with two different
> | versions of libcrypto!)

Here you can probably get things working by adding -Wl,--enable-new-dtags
to LDFLAGS in the configure script (or to AM_LDFLAGS in Makefile.am).
Clang runs ld(1) with this flag by default, gcc does not.  With clang the
program has DT_RUNPATH /usr/local/lib, which rtld(1) checks after
LD_LIBRARY_PATH, and with gcc the program has DT_RPATH /usr/local/lib which
rtld checks *before* LD_LIBRARY_PATH.

(The gold(1) linker also enables this flag by default.)

The reason it links to libcrypto twice is because liboath.so.2 pulls in
libcrypto.so.7 while gcc has linked libpam with libcrypto.so.8 because of
the implicit -L/usr/local/lib.

> 3)
>=20
> | I honestly thought this was a recent change, but I realize now that the
> | recent change is that I switched from developing on systems that still
> | had gcc in base (without /usr/local in the search path) to systems that
> | don't, and therefore use gcc from ports.
> |=20
> | The correct solution, in my opinion, is to remove /usr/local from all
> | search paths.  There is no need for it, even for ports, because most
> | ports add /usr/local to CPPFLAGS and LDFLAGS, either explicitly or
> | implicitly (by passing --prefix=3D${LOCALBASE} to the configure script).
> | If there are gcc-only ports which *don't* do it, they can easily be
> | fixed.

I agree.

> | I initially thought that merely changing the library search order would
> | be sufficient, but apparently gcc somehow forces /usr/local/lib to take
> | precedence even over ${LD_LIBRARY_PATH}, which is what causes my unit
> | tests to fail.  Here is an example from another project where I modified
> | the libtool wrapper to show its environment and run ldd before executing
> | the binary:
> |=20
> | des@desk ~/src/cryb-to% ./t/t_core
> | PATH=3D/home/des/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:=
/bin:/sbin
> | LD_LIBRARY_PATH=3D/home/des/src/cryb-to/lib/test/.libs:/home/des/src/cr=
yb-to/lib/core/.libs
> | /home/des/src/cryb-to/t/.libs/t_core:
> | 	libcryb-test.so.0 =3D> /usr/local/lib/libcryb-test.so.0 (0x80081f000)
> | 	libcryb-core.so.0 =3D> /usr/local/lib/libcryb-core.so.0 (0x800a26000)
> | 	libc.so.7 =3D> /lib/libc.so.7 (0x800c2a000)
> | 1..2
> | not ok 1 - version
> | ok 2 - no memory leaked
> |=20
> | This is a skeleton test which only verifies that the library it's linked
> | with has the same version as the one it was compiled with.  Here's the
> | same test, with the same modifications, built with clang:
> |=20
> | des@desk ~/src/cryb-to% ./t/t_core =20
> | PATH=3D/home/des/bin:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:=
/bin:/sbin
> | LD_LIBRARY_PATH=3D/home/des/src/cryb-to/lib/test/.libs:/home/des/src/cr=
yb-to/lib/core/.libs
> | /home/des/src/cryb-to/t/.libs/t_core:
> | 	libcryb-test.so.0 =3D> /home/des/src/cryb-to/lib/test/.libs/libcryb-te=
st.so.0 (0x80081f000)
> | 	libcryb-core.so.0 =3D> /home/des/src/cryb-to/lib/core/.libs/libcryb-co=
re.so.0 (0x800a27000)
> | 	libc.so.7 =3D> /lib/libc.so.7 (0x800c2c000)
> | 1..2
> | ok 1 - version
> | ok 2 - no memory leaked
> |=20
> | Please understand that the *only* way I can think of to work around this
> | is to set --nostdinc and --nostdlib and explicitly pass the correct
> | search path and list of libraries (-lgcc -lc) to gcc, and even then I'm
> | not sure it would work.  I don't find that reasonable at all.
> |=20
> | Note that I am not sure whether this problem is limited to gcc or if ld
> | is also involved.  The iconv problem which I originally reported is
> | caused by gcc picking up iconv.h from /usr/local/include instead of over
> | /usr/include, but I'm not sure whether the linking problem is caused by
> | gcc passing its search path on to ld, or to ld having its own incorrect
> | search path.  I tried explicitly setting LD=3D/usr/bin/ld, but that
> | doesn't make any difference since libtool uses gcc as a linker instead
> | of calling ${LD} directly.

Note that -rpath /usr/local/lib isn't added by gcc but by libtool
because it assumes rtld will not search that directory automatically.
If you run './configure CC=3Dgcc --prefix=3D/usr && make check' the tests
should succeed (without --enable-new-dtags) because -rpath isn't used
then.

You can examine rpath differences with 'objdump -p program | grep PATH'.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20170309123532.09b87366>