Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
Bug 526238 - sys-devel/gcc: gcc emits -L/usr/lib/gcc/$CHOST/$ver/../../.. regardless of ABI during linking
Summary: sys-devel/gcc: gcc emits -L/usr/lib/gcc/$CHOST/$ver/../../.. regardless of AB...
Status: RESOLVED INVALID
Alias: None
Product: Gentoo Linux
Classification: Unclassified
Component: Current packages (show other bugs)
Hardware: AMD64 Linux
: Normal major (vote)
Assignee: Gentoo Toolchain Maintainers
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2014-10-21 14:15 UTC by Vitaly Kirsanov
Modified: 2018-10-27 21:42 UTC (History)
3 users (show)

See Also:
Package list:
Runtime testing required: ---


Attachments
gcc -xc -v - (gcc.log,2.17 KB, text/x-log)
2014-10-21 14:15 UTC, Vitaly Kirsanov
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Vitaly Kirsanov 2014-10-21 14:15:15 UTC
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?
Comment 1 SpanKY gentoo-dev 2014-10-21 18:22:06 UTC
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.
Comment 2 Vitaly Kirsanov 2014-10-21 20:02:44 UTC
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.
Comment 3 SpanKY gentoo-dev 2014-10-22 05:11:29 UTC
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
Comment 4 Sergei Trofimovich (RETIRED) gentoo-dev 2018-06-30 20:07:32 UTC
(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;
Comment 5 Sergei Trofimovich (RETIRED) gentoo-dev 2018-06-30 22:22:01 UTC
(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.
Comment 6 Sergei Trofimovich (RETIRED) gentoo-dev 2018-07-01 09:53:43 UTC
(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).
Comment 7 Sergei Trofimovich (RETIRED) gentoo-dev 2018-07-01 10:55:21 UTC
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.
Comment 8 Sergei Trofimovich (RETIRED) gentoo-dev 2018-10-27 21:42:23 UTC
Closing as INVALID as -L search path should be supplied explicitly to make gcc/ld not guess liibrary ordering.