diff --git a/build/core/build-binary.mk b/build/core/build-binary.mk index d042c39f6..9219219f7 100644 --- a/build/core/build-binary.mk +++ b/build/core/build-binary.mk @@ -533,6 +533,15 @@ ifneq ($(filter armeabi%,$(TARGET_ARCH_ABI)),) my_ldflags += $(TARGET_$(my_link_arm_mode)_LDFLAGS) endif +# https://github.com/android-ndk/ndk/issues/855 +ifeq ($(HOST_OS),windows) + ndk_fuse_ld_flags := $(filter -fuse-ld=%,$(my_ldflags)) + ndk_used_linker := $(lastword $(ndk_fuse_ld_flags)) + ifeq ($(ndk_used_linker),-fuse-ld=lld) + my_ldflags += -Wl,--no-threads + endif +endif + # When LOCAL_SHORT_COMMANDS is defined to 'true' we are going to write the # list of all object files and/or static/shared libraries that appear on the # command line to a file, then use the @ syntax to invoke it. diff --git a/docs/BuildSystemMaintainers.md b/docs/BuildSystemMaintainers.md index 712d26078..02c1b98f6 100644 --- a/docs/BuildSystemMaintainers.md +++ b/docs/BuildSystemMaintainers.md @@ -210,7 +210,13 @@ installed to the triple directory and is not triple-prefixed, but rather is only installed as `/toolchains/llvm/prebuilt//bin/ld.lld` because the one binary supports all ABIs. + +Warning: Multithreaded linking with LLD may hang on Windows. This feature is on +by default. To workaround this, `-Wl,--no-threads` must be passed to Clang when +using LLD on Windows. See [Issue 855]. + [Issue 70838247]: https://issuetracker.google.com/70838247 +[Issue 855]: https://github.com/android-ndk/ndk/issues/855 ## Sysroot diff --git a/docs/changelogs/Changelog-r19.md b/docs/changelogs/Changelog-r19.md index d5b1d4b3f..4a136bf8f 100644 --- a/docs/changelogs/Changelog-r19.md +++ b/docs/changelogs/Changelog-r19.md @@ -61,6 +61,10 @@ Announcements r19b ---- + * [Issue 855]: ndk-build automatically disables multithreaded linking for LLD + on Windows, where it may hang. It is not possible for the NDK to detect this + situation for CMake, so CMake users and custom build systems must pass + `-Wl,--no-threads` when linking with LLD on Windows. * [Issue 849]: Fixed unused command line argument warning when using standalone toolchains to compile C code. * [Issue 890]: Fixed `CMAKE_FIND_ROOT_PATH`. CMake projects will no longer @@ -124,6 +128,10 @@ Known Issues to not call `dlclose`. * [Issue 70838247]: Gold emits broken debug information for AArch64. AArch64 still uses BFD by default. + * [Issue 855]: LLD may hang on Windows when using multithreaded linking. + ndk-build will automatically disable multithreaded linking in this situation, + but CMake users and custom build systems should pass `-Wl,--no-threads` when + using LLD on Windows. The other linkers and operating systems are unaffected. * [Issue 884]: Third-party build systems must pass `-fno-addrsig` to Clang for compatibility with binutils. ndk-build, CMake, and standalone toolchains handle this automatically. @@ -135,6 +143,7 @@ Known Issues [Issue 360]: https://github.com/android-ndk/ndk/issues/360 [Issue 70838247]: https://issuetracker.google.com/70838247 +[Issue 855]: https://github.com/android-ndk/ndk/issues/855 [Issue 884]: https://github.com/android-ndk/ndk/issues/884 [Issue 888]: https://github.com/android-ndk/ndk/issues/888 [use plugin version 3.1 or newer]: https://developer.android.com/studio/releases/gradle-plugin#updating-plugin diff --git a/tests/build/lld_no_threads/project/jni/Android.mk b/tests/build/lld_no_threads/project/jni/Android.mk new file mode 100644 index 000000000..68fa43372 --- /dev/null +++ b/tests/build/lld_no_threads/project/jni/Android.mk @@ -0,0 +1,6 @@ +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) +LOCAL_MODULE := libfoo +LOCAL_SRC_FILES := foo.cpp +include $(BUILD_SHARED_LIBRARY) diff --git a/tests/build/lld_no_threads/project/jni/foo.cpp b/tests/build/lld_no_threads/project/jni/foo.cpp new file mode 100644 index 000000000..85e6cd8c3 --- /dev/null +++ b/tests/build/lld_no_threads/project/jni/foo.cpp @@ -0,0 +1 @@ +void foo() {} diff --git a/tests/build/lld_no_threads/test.py b/tests/build/lld_no_threads/test.py new file mode 100644 index 000000000..1b7f07b29 --- /dev/null +++ b/tests/build/lld_no_threads/test.py @@ -0,0 +1,67 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Check that Windows LLD does not use threads with ndk-build. + +https://github.com/android-ndk/ndk/issues/855 reports that this sometimes hangs +on Windows. +""" +import os +import subprocess +import sys + + +def check_ndk_build(ndk_path, abi, platform, build_flags, use_lld): + """Checks --no-threads behavior with ndk-build. + + If use_lld is used, the test will build the ndk-build project with + APP_LDFLAGS=-fuse-ld=lld to force the project to use lld. In this case, we + expect to see -Wl,--no-threads passed to the linker on Windows. + """ + ndk_build = os.path.join(ndk_path, 'ndk-build') + is_win = sys.platform == 'win32' + if is_win: + ndk_build += '.cmd' + if use_lld: + build_flags.append('APP_LDFLAGS=-fuse-ld=lld') + project_path = 'project' + ndk_args = build_flags + [ + 'APP_ABI=' + abi, + 'APP_PLATFORM=android-{}'.format(platform), + 'V=1', + '-B', + ] + proc = subprocess.Popen([ndk_build, '-C', project_path] + ndk_args, + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) + out, _ = proc.communicate() + out = out.decode('utf-8') + if proc.returncode != 0: + return proc.returncode == 0, out + + out_words = out.split(' ') + if is_win and use_lld: + result = '-Wl,--no-threads' in out_words + else: + result = '-Wl,--no-threads' not in out_words + + return result, out + + +def run_test(ndk_path, abi, platform, build_flags): + """Checks --no-threads-behavior.""" + result, out = check_ndk_build(ndk_path, abi, platform, build_flags, False) + if not result: + return result, out + return check_ndk_build(ndk_path, abi, platform, build_flags, True)