Created attachment 387138 [details] gcc -xc -v - CONFIGURATION [ebuild R ~] sys-devel/gcc-4.8.3:4.8 USE="cxx fortran (multilib) nls nptl openmp (-altivec) -awt -doc (-fixed-point) -gcj -go -graphite (-hardened) (-libssp) -mudflap (-multislot) -nopie -nossp -objc -objc++ -objc-gc -regression-test -vanilla" 0 kB Output of gcc -xc -v - is in the attached file PROBLEM DESCRIPTION When I compile a 32-bit (-m32) program on my amd64 with, say, 32-bit boost libraries PC I got warnings from ld, e.g.: /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../x86_64-pc-linux-gnu/bin/ld: skipping incompatible /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../libboost_chrono.so when searching for -lboost_chrono Although eventually ld finds the correct library version. I checked the search paths for ld with -Wl,--verbose and they are: SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib32"); SEARCH_DIR("/usr/i386-pc-linux-gnu/lib32"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.23.232"); SEARCH_DIR("/usr/local/lib32"); SEARCH_DIR("/lib32"); SEARCH_DIR("/usr/lib32"); SEARCH_DIR("/usr/i386-pc-linux-gnu/lib"); SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.23.2"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); But during linking ld comes across libboost_chrono.so twice: attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/32/libboost_chrono.so failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/32/libboost_chrono.a failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../lib32/libboost_chrono.so failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../lib32/libboost_chrono.a failed attempt to open /lib/../lib32/libboost_chrono.so failed attempt to open /lib/../lib32/libboost_chrono.a failed attempt to open /usr/lib/../lib32/libboost_chrono.so failed attempt to open /usr/lib/../lib32/libboost_chrono.a failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libboost_chrono.so failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/libboost_chrono.a failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../x86_64-pc-linux-gnu/lib/libboost_chrono.so failed attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../x86_64-pc-linux-gnu/lib/libboost_chrono.a failed >>>>> FIRST, WRONG, 64 <<<<<<< attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../libboost_chrono.so succeeded <<<<< FIRST, WRONG, 64 >>>>>>> attempt to open /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../libboost_chrono.a failed attempt to open /usr/x86_64-pc-linux-gnu/lib32/libboost_chrono.so failed attempt to open /usr/x86_64-pc-linux-gnu/lib32/libboost_chrono.a failed attempt to open /usr/i386-pc-linux-gnu/lib32/libboost_chrono.so failed attempt to open /usr/i386-pc-linux-gnu/lib32/libboost_chrono.a failed attempt to open /usr/lib64/binutils/x86_64-pc-linux-gnu/2.23.232/libboost_chrono.so failed attempt to open /usr/lib64/binutils/x86_64-pc-linux-gnu/2.23.232/libboost_chrono.a failed >>>>> SECOND, RIGHT, 32 <<<<<<< attempt to open /usr/local/lib32/libboost_chrono.so succeeded -lboost_chrono (/usr/local/lib32/libboost_chrono.so) <<<<< SECOND, RIGHT, 32 >>>>>>> So ld appears to look some of its 64-bit paths before 32-bit ones even if -m32 flag is given. Can it be a configuration issue?
fairly certain it's always been this way. for the vast majority of cases, if you're invoking the linker directly, you're doing it wrong. use gcc as the linker driver instead.
But I ran gcc, not ld directly. Why I said about probable configuration issue is because, for instance, on ubuntu the same version of gcc does not report such warnings when building the same code, and there ld looks first for 32-bit libraries and only after them their 64-bit counterparts. It's even more weird (at least I don't understand why) that the list of SEARCH_DIR variables shows that /usr/local/lib32 (where I had installed 32-bit boost to) goes before /usr/lib64 (a.k.a /usr/lib) where 64-bit boost is.
hmm, it's not ld that is adding that search path. gcc itself is passing that down. it seems to do it regardless of selected ABI. test case: $ gcc -m64 /dev/null -Wl,-v |& grep -e-L $ gcc -m32 /dev/null -Wl,-v |& grep -e-L $ gcc -mx32 /dev/null -Wl,-v |& grep -e-L each of those will emit in the middle: -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../.. going to have to dig down to find out where that's getting generated from
(In reply to SpanKY from comment #3) > hmm, it's not ld that is adding that search path. gcc itself is passing > that down. it seems to do it regardless of selected ABI. > > test case: > $ gcc -m64 /dev/null -Wl,-v |& grep -e-L > $ gcc -m32 /dev/null -Wl,-v |& grep -e-L > $ gcc -mx32 /dev/null -Wl,-v |& grep -e-L > > each of those will emit in the middle: > -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../.. > > going to have to dig down to find out where that's getting generated from I poked at it today. gcc-HEAD is still having '-L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../...' which is an elaborate way of encoding original '/usr/lib' path. '/lib' and '/usr/lib' are injected as a last-resort paths to search for crt startup files directly in gcc driver (comment above suggests these are legacy paths): https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.c;h=9ed8a03af0a2aa017be1fc75a81823dda94d7816;hb=HEAD#l7646 if (*standard_startfile_prefix_2) add_sysrooted_prefix (&startfile_prefixes, standard_startfile_prefix_2, "BINUTILS", PREFIX_PRIORITY_LAST, 0, 1); standard_startfile_prefix_2 is just a constant: #ifndef STANDARD_STARTFILE_PREFIX_2 #define STANDARD_STARTFILE_PREFIX_2 "/usr/lib/" #endif static const char *const standard_startfile_prefix_2 = STANDARD_STARTFILE_PREFIX_2;
(In reply to Sergei Trofimovich from comment #4) > (In reply to SpanKY from comment #3) > > hmm, it's not ld that is adding that search path. gcc itself is passing > > that down. it seems to do it regardless of selected ABI. > > > > test case: > > $ gcc -m64 /dev/null -Wl,-v |& grep -e-L > > $ gcc -m32 /dev/null -Wl,-v |& grep -e-L > > $ gcc -mx32 /dev/null -Wl,-v |& grep -e-L > > > > each of those will emit in the middle: > > -L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../.. > > > > going to have to dig down to find out where that's getting generated from > > I poked at it today. gcc-HEAD is still having > '-L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../...' which is an elaborate > way of encoding original '/usr/lib' path. > > '/lib' and '/usr/lib' are injected as a last-resort paths to search for crt > startup files directly in gcc driver (comment above suggests these are > legacy paths): > > https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.c; > h=9ed8a03af0a2aa017be1fc75a81823dda94d7816;hb=HEAD#l7646 > > if (*standard_startfile_prefix_2) > add_sysrooted_prefix (&startfile_prefixes, > standard_startfile_prefix_2, "BINUTILS", > PREFIX_PRIORITY_LAST, 0, 1); > Sorry. This location doe not cause '-L/usr/lib/gcc/x86_64-pc-linux-gnu/4.9.1/../../...'. It's slightly above: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.c;h=9ed8a03af0a2aa017be1fc75a81823dda94d7816;hb=HEAD#l7630 else if (*cross_compile == '0') { add_prefix (&startfile_prefixes, concat (gcc_exec_prefix ? gcc_exec_prefix : standard_exec_prefix, machine_suffix, standard_startfile_prefix, NULL), NULL, PREFIX_PRIORITY_LAST, 0, 1); } I don't understand yet why multilib suffix is not appended to this path when searched. Will explore more. Removing this line entirely workarounds the symptom.
(In reply to Sergei Trofimovich from comment #5) > I don't understand yet why multilib suffix is not appended to this path when > searched. Will explore more. Here is how both multilib-prefixed and non-multilib prefixes path get into linker path: All starts from %D expansion it the spec file: https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.c;h=9ed8a03af0a2aa017be1fc75a81823dda94d7816;hb=HEAD#l5312 case 'D': ... info.option = "-L"; for_each_path (&startfile_prefixes, true, 0, spec_path, &info); 'for_each_path' traverses startfile_prefixes twice: honoring multilib flag (and appending '../lib32') and ignoring it (returning path as-is): https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.c;h=9ed8a03af0a2aa017be1fc75a81823dda94d7816;hb=HEAD#l2556 Both paths are returned in this snippet in 'callback': /* Now try the base path. */ if (!pl->require_machine_suffix && !(pl->os_multilib ? skip_multi_os_dir : skip_multi_dir)) { const char *this_multi; size_t this_multi_len; if (pl->os_multilib) { this_multi = multi_os_dir; this_multi_len = multi_os_dir_len; } else { this_multi = multi_dir; this_multi_len = multi_dir_len; } if (this_multi_len) memcpy (path + len, this_multi, this_multi_len + 1); else path[len] = '\0'; ret = callback (path, callback_info); if (ret) break; } } The second traversal is flagged below in: /* Run through the paths again, this time without multilibs. Don't repeat any we have already seen. */ if (multi_dir) { free (CONST_CAST (char *, multi_dir)); multi_dir = NULL; free (CONST_CAST (char *, multi_suffix)); multi_suffix = machine_suffix; free (CONST_CAST (char *, just_multi_suffix)); just_multi_suffix = just_machine_suffix; } else skip_multi_dir = true; if (multi_os_dir) { free (CONST_CAST (char *, multi_os_dir)); multi_os_dir = NULL; } else skip_multi_os_dir = true; Note: if 'multi_os_dir' ('../lib32') was present os_multilib paths are not ignored on second traversal. They are returned again with multi_os_dir=NULL (empty string).
I'll try to clarify the original report. /usr/lib32 paths are searched before fallback /usr/lib/ paths (ok) but /usr/local/lib32 is searched after /usr/lib (produces warning): ... > /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../../lib32/libboost_chrono.so > failed ^ this was supposed to work if library would be installed via package manager > attempt to open /usr/lib/../lib32/libboost_chrono.so failed ^ or this (same resolved path) > >>>>> FIRST, WRONG, 64 <<<<<<< > attempt to open > /usr/lib/gcc/x86_64-pc-linux-gnu/4.8.3/../../../libboost_chrono.so succeeded ^ this is a /usr/lib/ fallback (/usr/lib64 on a SYMLINK_LIB=yes profiles) Only then /usr/local/ multilib paths are tried by ld. > attempt to open /usr/local/lib32/libboost_chrono.so succeeded > -lboost_chrono (/usr/local/lib32/libboost_chrono.so) > > So ld appears to look some of its 64-bit paths before 32-bit ones even if > -m32 flag is given. Can it be a configuration issue? Normally people don't see this error because they have boost installed to --prefix=/usr via package manager. Note: /usr/local path is not added or known by gcc on x86_64-linux (arguably it's gcc's infelicity). Thus gcc does not do /usr/local/ traversal when multilibs libs are searched. It's a binutils' default path from linker script. Thus the priority is: - ld uses all -L paths explicitly passed by gcc as commandline arguments. Namely /usr/lib32, ..., /usr/lib (produces warninig) - then ld uses builtin linker script paths passed via SEARCH_DIR (order depends on linker script position in commandline flags) One of the workarounds would be to pass LDFLAGS=-L/usr/local/lib32 explicitly to gcc command line when building your application.
Closing as INVALID as -L search path should be supplied explicitly to make gcc/ld not guess liibrary ordering.