Search code examples
gcclinkerclangldicc

How can I find and test the *actual linker* a compiler is using, on an arbitrary system?


I need to pass some objects from [ some assembler | another compiler | an archive ] directly to the linker.

But seems that the ld being found on the path is [ broken | missing | linking for the wrong ABI ].
And sometimes, I can't even find ld at all.

How can I find the actual linker being used, by whatever the C compiler happens to be,
[ on a Mac | on Linux | on BSD | from a configure script ]?


Solution

  • I just had to figure this one out.
    It was kind of tough, so I thought I'd share.

    Give this a shot:

    #!/usr/bin/env sh
    
    # 'main;' is the shortest C program possible (I think.).
    # So it is compiled, linked, and written to /dev/null.
    # So if the linker can't link, this should return 1.
    
    for link in collect2 ld; do # Order matters, because of GCC.
     echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -q $link &&
     echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep    $link |
     sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
    done
    
    # That should work on just about anything, and returns an absolute path,
    # except with ICC. If we want to try to get an absolute path there too,
    # we have to:
    
    # If 'which' is missing, and it might not have an -s flag.
    which="$(which which >/dev/null 2>&1)" || which=echo
    
    $which "$(for link in collect2 ld; do
     echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -q $link &&
     echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep    $link |
     sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
    done)"
    

    So you might have just said,

    Come on guy, no way that's necessary! Just, like, which ld.

    Honestly and truly, that doesn't work for me a large portion of the time.
    Its not so unusual today, since ld is frequently a wrapper.

    Lets test it, see what turns up:

    #!/usr/bin/env sh
    
    # On my Mac, nothing too special, I swear.
    # Just a MacBook, Xcode, GCC from Homebrew, and one commercial compiler.
    
    
    echo; $which ld; echo "...Not necessarily."; echo
    
    for CC in cc gcc clang icc; do echo $c:
      for link in collect2 ld; do
        echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -q $link &&
        echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep    $link |
           sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
       done
    
      which="$(which which 2>/dev/null 1>&1)" || which=echo
      $which "$(for link in collect2 ld; do
        echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep -q $link &&
        echo 'main;' | $CC -v -x c - -o /dev/null -\#\#\# 2>&1 | grep    $link |
       sed -e "s|\(.*$link\).*|\1|" -e 's/ //g' -e 's|"||' && break
      done)"
      echo
    done
    

    Returns:

    /usr/bin/ld
    ...Not necessarily.
    
    cc:
    /Applications/Xcode51-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
    /Applications/Xcode51-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
    
    gcc:
    /Users/Shared/usr/local/Cellar/gcc49/4.9-20140119/libexec/gcc/x86_64-apple-darwin13.1.0/4.9.0/collect2
    /Users/Shared/usr/local/Cellar/gcc49/4.9-20140119/libexec/gcc/x86_64-apple-darwin13.1.0/4.9.0/collect2
    
    clang:
    /Applications/Xcode51-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
    /Applications/Xcode51-Beta4.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld
    
    icc:
    ld
    /usr/bin/ld