Option to tell clang to echo linker commands?

For my education, I’m trying to compile a simple program from the command line to see how things work underneath all the IDEs and build tools.

Here are some minimal shell commands on my macOS system to build a C++ hello world, using a clang 15 binary that I just downloaded. (% is the shell prompt).

% SYSR=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk
% clang++ -isysroot $SYSR hello.cc
% ./a.out
hi

If I try to separate compile and link:

% clang++ -isysroot $SYSR -c hello.cc -o hello.o
% ld64.lld hello.o -arch x86_64 -platform_version macos 13 13 -L/Users/rob/Dev/clang+llvm-15.0.1-x86_64-apple-darwin/lib -lc++ -lunwind

I keep adding to that line in response to error messages, but it still fails. So I’m curious, is there way to make clang++ echo the commands that it sent to the linker so I can see what the flags are to do it manually?

You can pass -v to see the commands it runs. For example:

% clang++ -v /tmp/main.cc
Apple clang version 14.0.0 (clang-1400.0.29.102)
Target: arm64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple arm64-apple-macosx12.0.0 -Wundef-prefix=TARGET_OS_ -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -Werror=implicit-function-declaration -emit-obj -mrelax-all --mrelax-relocations -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name main.cc -mrelocation-model pic -pic-level 2 -mframe-pointer=non-leaf -fno-strict-return -fno-rounding-math -funwind-tables=2 -fobjc-msgsend-selector-stubs -target-sdk-version=12.3 -fvisibility-inlines-hidden-static-local-var -target-cpu apple-m1 -target-feature +v8.5a -target-feature +fp-armv8 -target-feature +neon -target-feature +crc -target-feature +crypto -target-feature +dotprod -target-feature +fp16fml -target-feature +ras -target-feature +lse -target-feature +rdm -target-feature +rcpc -target-feature +zcm -target-feature +zcz -target-feature +fullfp16 -target-feature +sm4 -target-feature +sha3 -target-feature +sha2 -target-feature +aes -target-abi darwinpcs -fallow-half-arguments-and-returns -debugger-tuning=lldb -target-linker-version 819.6 -v -resource-dir /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0 -isysroot /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -I/usr/local/include -stdlib=libc++ -internal-isystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1 -internal-isystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include -internal-isystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include -internal-externc-isystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include -internal-externc-isystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include -Wno-reorder-init-list -Wno-implicit-int-float-conversion -Wno-c99-designator -Wno-final-dtor-non-final-class -Wno-extra-semi-stmt -Wno-misleading-indentation -Wno-quoted-include-in-framework-header -Wno-implicit-fallthrough -Wno-enum-enum-conversion -Wno-enum-float-conversion -Wno-elaborated-enum-base -Wno-reserved-identifier -Wno-gnu-folding-constant -Wno-cast-function-type -Wno-bitwise-instead-of-logical -fdeprecated-macro -fdebug-compilation-dir=/Users/ksmiley/dev/dotfiles -ferror-limit 19 -stack-protector 1 -fstack-check -mdarwin-stkchk-strong-link -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fgnuc-version=4.2.1 -fno-cxx-modules -fcxx-exceptions -fexceptions -fmax-type-align=16 -fcommon -fcolor-diagnostics -clang-vendor-feature=+messageToSelfInClassMethodIdReturnType -clang-vendor-feature=+disableInferNewAvailabilityFromInit -clang-vendor-feature=+disableNonDependentMemberExprInCurrentInstantiation -fno-odr-hash-protocols -clang-vendor-feature=+enableAggressiveVLAFolding -clang-vendor-feature=+revert09abecef7bbf -clang-vendor-feature=+thisNoAlignAttr -clang-vendor-feature=+thisNoNullAttr -mllvm -disable-aligned-alloc-awareness=1 -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /var/folders/gj/wf3swl0x215b2sq1qy84kzkm0000gn/T/main-79918b.o -x c++ /tmp/main.cc
clang -cc1 version 14.0.0 (clang-1400.0.29.102) default target arm64-apple-darwin21.6.0
ignoring nonexistent directory "/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/local/include"
ignoring nonexistent directory "/Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/Library/Frameworks"
#include "..." search starts here:
#include <...> search starts here:
 /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/v1
 /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/include
 /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include
 /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/Frameworks (framework directory)
End of search list.
 "/Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld" -demangle -lto_library /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/libLTO.dylib -no_deduplicate -dynamic -arch arm64 -platform_version macos 12.0.0 12.3 -syslibroot /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -o a.out -L/usr/local/lib /var/folders/gj/wf3swl0x215b2sq1qy84kzkm0000gn/T/main-79918b.o -lc++ -lSystem /Applications/Xcode-14.0.0-RC1.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/14.0.0/lib/darwin/libclang_rt.osx.a

There’s some extra info here but you can see the compile command is the clang -cc1 line, and my link is the last line.

1 Like

If clang++ is an Apple clang, then it should be really simple:

clang++ -c hello.cc -o hello.o
clang++ hello.o -o a.out

Minus typos. Apple Clang will find all the paths that it needs. If clang++ is an Open Source clang, then it is going to be complicated. But note that clang can invoke the linker for you.

SYS=`xcrun --sdk macosx12.3 --show-sdk-path`
clang++ -isysroot $SYS -c hello.cc -o hello.o
clang++ -isysroot $SYS hello.o -o a.out

Again minus typos.

clang -### -c hello.cc -o hello.o

It will show you what clang actually did.

(For easier reading I’ve stripped an irrelevant path prefix from my clang 15 directory below)

Thanks, that’s interesting. The -v or -### to clang++ shows the linker command. It’s calling /usr/bin/ld, even though I started by calling my newer clang++ at another path (/clang+llvm-15.0.1-x86_64-apple-darwin/bin/clang++).

I can substitute /usr/bin/ld with the newer linker next to clang 15, and it works. (I had to add a -platform_version flag.) However, I think it is still linking to the older C++ library with Xcode, not the newer one in the custom clang directory.

Related question: is there a similar way to see the libraries that the linker finds? I tried -v to the linker and it does print its search path, but it doesn’t show what it finally linked to. The library search paths suggest it will find the older C++ lib.

% which ld64.lld
/clang+llvm-15.0.1-x86_64-apple-darwin/bin/ld64.lld
 % ld64.lld -dynamic -arch x86_64 -macosx_version_min 13.0.0 -platform_version macos 13 13 -syslibroot $SYSR -o hi2 hello.o -lc++ -lSystem /clang+llvm-15.0.1-x86_64-apple-darwin/lib/clang/15.0.1/lib/darwin/libclang_rt.osx.a -v   
LLD 15.0.1
Library search paths:
	/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/usr/lib
Framework search paths:
	/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX12.3.sdk/System/Library/Frameworks
% ./hi2
hi
% otool -L hi2                                             
hi2:
	/usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 1300.23.0)
	/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1311.100.3)

Maybe if download a newer clang and want to link to new libc++, the best way is to include the static library in the build commands.

/clang+llvm-15.0.1-x86_64-apple-darwin/lib/libc++.a

There was an rust issue:

You could try something ala:

clang++ -B<path-to-new-lld-dir> -fuse-lld=lld ...

Then it will use the new lld that shipped with your clang+15.
/usr/bin/ld is an OSX trick. It actually will invoke a different binary.

    -t      Logs each file (object, archive, or dylib) the linker loads.  Useful for debugging problems with search paths where the wrong library
             is loaded.

from man ld.

1 Like

-fuse-lld appears to be a GCC flag. That rust link says: “Clang chooses the linker name based on passed --target”. But I don’t know what the target value should be there. I tried a few things, but clang++ is still using /usr/bin/ld.

LLVM has linkers (lld) for Linux, Apple, Windows, and WASM? Your OS Clang will know that the target is Apple and will pick ld64.lld. -fuse-lld is supported by clang and gcc.

Ah, got it. It’s just one ‘ell’ : -fuse-ld. I don’t see it in clang++ --help or man clang so I got lost a bit there.

You can see it in the rust issue or at ⚙ D74704 Support -fuse-ld=lld for riscv. It is two els. -fuse-ld=lld. I couldn’t find in man clang nor clang --help?!?