diff options
author | fanquake <fanquake@gmail.com> | 2020-07-03 17:11:24 +0800 |
---|---|---|
committer | fanquake <fanquake@gmail.com> | 2020-07-03 17:38:27 +0800 |
commit | f61019f5a2c63d0a293e2ba2e57352d834f2c8d6 (patch) | |
tree | 85a840c83bfe226fcd3915d766e6959def4888c2 | |
parent | 7d9008f43e50db6a44cf5cac9456fce99e1aac12 (diff) | |
parent | a8d39b88406e2047746366355666b5f603105a2e (diff) | |
download | bitcoin-f61019f5a2c63d0a293e2ba2e57352d834f2c8d6.tar.xz |
Merge #19407: doc: explain why passing -mlinker-version is required when cross-compiling
a8d39b88406e2047746366355666b5f603105a2e doc: explain why passing -mlinker-version is required (fanquake)
Pull request description:
I have been down a 🐇 hole. Closes #19359.
When Clang is compiled, [a check is run](https://github.com/llvm/llvm-project/blob/release/8.x/clang/CMakeLists.txt#L353) to define `HOST_LINK_VERSION` as the output of `$CMAKE_LINKER -v`. Note the this is the version of the linker being used to compile Clang itself.. and this check is only run when compiling Clang for macOS.
In the Clang driver, if `HOST_LINK_VERSION` has been defined, there is some additional runtime functionality. An `-mlinker-version` argument, with the value of `HOST_LINK_VERSION` [will be added to the linker arguments](https://github.com/llvm/llvm-project/blob/89de0d8dfbb9a6ff1f8b141ed70b563ecc094878/clang/lib/Driver/Driver.cpp#L382), if `-mlinker-version` has not been passed in by the user.
This is a bit weird, as by default, you are setting `-mlinker-version` to the version of the linker that was used to build the Clang binary, not the linker which will be used when compiling. The commit which introduced the functionality, https://github.com/llvm/llvm-project/commit/628fcf4e3b79ba9f41dd1b49b1aba7a20b68fc0e, described it as a "hack", that should be replaced. However, that was 10 years ago, and the behaviour is still here.
In the Darwin driver, [a check is done](https://github.com/llvm/llvm-project/blob/89de0d8dfbb9a6ff1f8b141ed70b563ecc094878/clang/lib/Driver/ToolChains/Darwin.cpp#L208) for the `-mlinker-version` argument. If there is no argument, the version will default to `0`. Given the above, this should never happen when using Clang for macOS. A series of comparisons are then performed, to check whether the linker version is modern enough to enable certain features, like [`-demangle`](https://github.com/llvm/llvm-project/blob/89de0d8dfbb9a6ff1f8b141ed70b563ecc094878/clang/lib/Driver/ToolChains/Darwin.cpp#L215).
### What this means
#### macOS
A Clang compiled for macOS, i.e `clang+llvm-8.0.0-x86_64-apple-darwin`, will have `HOST_LINKER_VERSION` set to the version of the linker used to compile Clang itself.
At runtime, `-mlinker-version=HOST_LINKER_VERSION` will be added to the linker args, if `-mlinker-version` wasn't passed in. In the Darwin driver, additional arguments, like `-demangle`, will be added to the linker arguments, because `HOST_LINKER_VERSION` was likely some very modern version of `lld` or `ld64`.
#### Linux (cross compilation in depends)
A Clang compiled for Linux, i.e `clang+llvm-8.0.0-x86_64-linux-gnu-ubuntu-14.04`, which we now use for macOS builds in depends, will behave differently. As it's built for Linux, `HOST_LINKER_VERSION` was not defined at compile time, and there will be no default behaviour of appending `-mlinker-version=HOST_LINKER_VERSION` to the linker args. Thus, unless you pass in `-mlinker-version` yourself, when the version checks are done in the Darwin driver, no modern linker features will be enabled, as the version will have defaulted to `0`.
Therefore, it's important that we continue to pass `-mlinker-version="our LD64 version"` as part of our compilation flags, if we want to have "modern" linker features enabled for our macOS builds.
#### Summary
[Clang 8](https://releases.llvm.org/download.html#8.0.0). Building a macOS binary. Link line with path arguments trimmed.
| | default behaviour | `-mlinker-version=100` (`-demangle threshold`) | `-mlinker-version=530` |
| - | --------------- | --------------------- | ---------------------- |
| macOS Clang | `-demangle -lto_library ../libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.15.0 -o a.out ../test-b8b9b3.o -lc++ -lSystem ../libclang_rt.osx.a` | `-demangle -dynamic -arch x86_64 -macosx_version_min 10.15.0 -o a.out ../test-a66966.o -lc++ -lSystem ../libclang_rt.osx.a` | same as default |
| Linux Clang | `-dynamic -arch x86_64 -macosx_version_min 10.12.0 -o a.out ../test-bfce57.o -lc++ -lSystem` | `-demangle -dynamic -arch x86_64 -macosx_version_min 10.12.0 -o a.out ../test-a846a3.o -lc++ -lSystem` | `-demangle -lto_library ../libLTO.dylib -no_deduplicate -dynamic -arch x86_64 -macosx_version_min 10.12.0 -o a.out ../test-de0280.o -lc++ -lSystem` |
Note: Most links here are pointing to the 8.x branch of LLVM/Clang, as we are using that version in depends.
Note: To add a little more confusion, you wont see `-mlinker-version X` in your compile flags, you'll see [`-target-linker-version X`](https://github.com/llvm/llvm-project/blob/431daedee4dcce0c096c400dbf8e64dfe7254fb6/clang/lib/Driver/ToolChains/Clang.cpp#L4777).
ACKs for top commit:
laanwj:
ACK a8d39b88406e2047746366355666b5f603105a2e
Tree-SHA512: 92f93079a5e59a0d561e74336b5cb03e3bf5a34437f5850283b9128c7624494b8285ec16290b1fa8103fe87f8789a53ce44b17902b8c1db5fde24d74b76fb168
-rw-r--r-- | depends/hosts/darwin.mk | 3 |
1 files changed, 3 insertions, 0 deletions
diff --git a/depends/hosts/darwin.mk b/depends/hosts/darwin.mk index 5f0bffa5cb..0d4fab937d 100644 --- a/depends/hosts/darwin.mk +++ b/depends/hosts/darwin.mk @@ -5,6 +5,9 @@ XCODE_BUILD_ID=11C505 LD64_VERSION=530 OSX_SDK=$(SDK_PATH)/Xcode-$(XCODE_VERSION)-$(XCODE_BUILD_ID)-extracted-SDK-with-libcxx-headers + +# When cross-compiling for Darwin using Clang, -mlinker-version must be passed to +# ensure that modern linker features are enabled. darwin_CC=clang -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -mlinker-version=$(LD64_VERSION) darwin_CXX=clang++ -target $(host) -mmacosx-version-min=$(OSX_MIN_VERSION) --sysroot $(OSX_SDK) -stdlib=libc++ -mlinker-version=$(LD64_VERSION) |