Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Android: Switch to native ELF TLS & latest LTS NDK, and enable shared druntime/Phobos #4618

Merged
merged 2 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions .github/actions/3-build-cross/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ inputs:
default: false
android_ndk_version:
required: false
default: r21e
default: r26d
android_api_level:
required: false
default: 21
default: 29
runs:
using: composite
steps:
Expand Down Expand Up @@ -92,32 +92,30 @@ runs:
cd ..
version='${{ inputs.android_ndk_version }}'
curl -fL --retry 3 --max-time 300 -o android-ndk.zip \
https://dl.google.com/android/repository/android-ndk-$version-linux-x86_64.zip
https://dl.google.com/android/repository/android-ndk-$version-linux.zip
unzip android-ndk.zip >/dev/null
mv "android-ndk-$version" android-ndk
rm android-ndk.zip

# The NDK toolchain file enforces `-g` as base C[XX] flag - remove it to
# *significantly* reduce executable sizes
toolchainFile="$PWD/android-ndk/build/cmake/android.toolchain.cmake"
sed -i 's|^ -g$||' "$toolchainFile"

arch='${{ inputs.arch }}'
apiLevel='${{ inputs.android_api_level }}'
cmakeFlags="-DTARGET_SYSTEM='Android;Linux;UNIX'"
if [[ "$arch" == armv7a ]]; then
triple="$arch-linux-androideabi$apiLevel"
cmakeFlags+=' -DANDROID_ABI=armeabi-v7a'
elif [[ "$arch" == aarch64 ]]; then
# FIXME: as of NDK rc26d, libc.a has __tls_get_addr, but libc.so only since API level 30 (Android v11)
apiLevel=30
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bit weird that the AArch64 libc.so got the required __tls_get_addr symbol in level 30, not level 29 as for armv7a; the NDK changelog doesn't mention this. Not sure whether this is an oversight in the NDK (it's like this for r26c and r26d), or whether there's a good reason why __tls_get_addr requires Android v11+ on AArch64 (unless linking libc statically).

triple="$arch-linux-android$apiLevel"
cmakeFlags+=' -DANDROID_ABI=arm64-v8a'
fi
cmakeFlags+=" -DANDROID_NATIVE_API_LEVEL=$apiLevel"
cmakeFlags+=" -DANDROID_STL=c++_static"
cmakeFlags+=" -DCMAKE_TOOLCHAIN_FILE=$toolchainFile"
cmakeFlags+=" -DLDC_LINK_MANUALLY=ON -DD_LINKER_ARGS='-fuse-ld=bfd;-L$PWD/build-cross-libs/lib;-lphobos2-ldc;-ldruntime-ldc'"
cmakeFlags+=" -DCMAKE_TOOLCHAIN_FILE=$PWD/android-ndk/build/cmake/android.toolchain.cmake"
cmakeFlags+=" -DANDROID_USE_LEGACY_TOOLCHAIN_FILE=OFF"
cmakeFlags+=" -DLDC_LINK_MANUALLY=ON -DD_LINKER_ARGS='-L$PWD/build-cross-libs/lib;-lphobos2-ldc;-ldruntime-ldc'"

echo "DFLAGS=-mtriple=$triple -fvisibility=hidden -L-L$PWD/build-cross-libs/lib -gcc=$PWD/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/$triple-clang" >> $GITHUB_ENV
echo "DFLAGS=-mtriple=$triple -L-L$PWD/build-cross-libs/lib -gcc=$PWD/android-ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/$triple-clang" >> $GITHUB_ENV
echo "CROSS_TRIPLE=$triple" >> $GITHUB_ENV
echo "CROSS_CMAKE_FLAGS=$cmakeFlags" >> $GITHUB_ENV

Expand Down
18 changes: 9 additions & 9 deletions .github/actions/3-build-cross/android-llvm-config.in
Original file line number Diff line number Diff line change
Expand Up @@ -53,25 +53,25 @@ LIBFILE="${prefix}/lib/libLLVM-$version.so"
components="aarch64 aarch64asmparser aarch64codegen aarch64desc aarch64disassembler aarch64info aarch64utils \
aggressiveinstcombine all all-targets analysis arm armasmparser armcodegen armdesc armdisassembler arminfo armutils \
asmparser asmprinter binaryformat bitreader bitstreamreader bitwriter cfguard codegen codegentypes core coroutines coverage \
debuginfobtf debuginfocodeview debuginfodwarf debuginfogsym debuginfologicalview debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker dwarflinkerparallel dwp \
engine executionengine extensions filecheck frontendhlsl frontendopenacc frontendopenmp fuzzercli fuzzmutate globalisel instcombine \
debuginfobtf debuginfocodeview debuginfodwarf debuginfogsym debuginfologicalview debuginfomsf debuginfopdb demangle dlltooldriver dwarflinker dwarflinkerclassic dwarflinkerparallel dwp \
engine executionengine extensions filecheck frontenddriver frontendhlsl frontendoffloading frontendopenacc frontendopenmp fuzzercli fuzzmutate globalisel hipstdpar instcombine \
instrumentation interfacestub interpreter ipo irprinter irreader jitlink libdriver lineeditor linker lto mc mca mcdisassembler \
mcjit mcparser mirparser native nativecodegen objcarcopts objcopy object objectyaml option orcjit orcshared orctargetprocess \
mcjit mcparser mirparser native nativecodegen objcarcopts objcopy object objectyaml option orcdebugging orcjit orcshared orctargetprocess \
passes profiledata remarks runtimedyld scalaropts selectiondag spirv spirvcodegen spirvdesc spirvinfo support symbolize tablegen target targetparser textapi \
transformutils vectorize webassembly webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler \
textapibinaryreader transformutils vectorize webassembly webassemblyasmparser webassemblycodegen webassemblydesc webassemblydisassembler \
webassemblyinfo webassemblyutils windowsdriver windowsmanifest x86 x86asmparser x86codegen x86desc x86disassembler x86info \
x86targetmca xray"
static_libs="-lLLVMWindowsManifest -lLLVMXRay -lLLVMLibDriver -lLLVMDlltoolDriver -lLLVMCoverage -lLLVMLineEditor \
static_libs="-lLLVMWindowsManifest -lLLVMXRay -lLLVMLibDriver -lLLVMDlltoolDriver -lLLVMTextAPIBinaryReader -lLLVMCoverage -lLLVMLineEditor \
-lLLVMSPIRVCodeGen -lLLVMSPIRVDesc -lLLVMSPIRVInfo \
-lLLVMX86TargetMCA -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMWebAssemblyDisassembler \
-lLLVMWebAssemblyAsmParser -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyUtils -lLLVMWebAssemblyDesc -lLLVMWebAssemblyInfo -lLLVMARMDisassembler \
-lLLVMARMAsmParser -lLLVMARMCodeGen -lLLVMARMDesc -lLLVMARMUtils -lLLVMARMInfo -lLLVMAArch64Disassembler \
-lLLVMAArch64AsmParser -lLLVMAArch64CodeGen -lLLVMAArch64Desc -lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMOrcJIT \
-lLLVMAArch64AsmParser -lLLVMAArch64CodeGen -lLLVMAArch64Desc -lLLVMAArch64Utils -lLLVMAArch64Info -lLLVMOrcDebugging -lLLVMOrcJIT \
-lLLVMWindowsDriver -lLLVMMCJIT -lLLVMJITLink -lLLVMInterpreter -lLLVMExecutionEngine -lLLVMRuntimeDyld -lLLVMOrcTargetProcess -lLLVMOrcShared \
-lLLVMDWP -lLLVMDebugInfoLogicalView -lLLVMDebugInfoGSYM -lLLVMOption -lLLVMObjectYAML -lLLVMObjCopy -lLLVMMCA \
-lLLVMMCDisassembler -lLLVMLTO -lLLVMPasses -lLLVMCFGuard -lLLVMCoroutines -lLLVMipo \
-lLLVMVectorize -lLLVMLinker -lLLVMInstrumentation -lLLVMFrontendOpenMP -lLLVMFrontendOpenACC -lLLVMFrontendHLSL -lLLVMExtensions \
-lLLVMDWARFLinkerParallel -lLLVMDWARFLinker -lLLVMGlobalISel -lLLVMMIRParser -lLLVMAsmPrinter -lLLVMSelectionDAG \
-lLLVMMCDisassembler -lLLVMLTO -lLLVMPasses -lLLVMHipStdPar -lLLVMCFGuard -lLLVMCoroutines -lLLVMipo \
-lLLVMVectorize -lLLVMLinker -lLLVMInstrumentation -lLLVMFrontendOpenMP -lLLVMFrontendOffloading -lLLVMFrontendOpenACC -lLLVMFrontendHLSL -lLLVMFrontendDriver -lLLVMExtensions \
-lLLVMDWARFLinkerParallel -lLLVMDWARFLinkerClassic -lLLVMDWARFLinker -lLLVMGlobalISel -lLLVMMIRParser -lLLVMAsmPrinter -lLLVMSelectionDAG \
-lLLVMCodeGen -lLLVMTarget -lLLVMObjCARCOpts -lLLVMCodeGenTypes -lLLVMIRPrinter -lLLVMInterfaceStub -lLLVMFileCheck -lLLVMFuzzMutate \
-lLLVMScalarOpts -lLLVMInstCombine -lLLVMAggressiveInstCombine -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis \
-lLLVMProfileData -lLLVMSymbolize -lLLVMDebugInfoBTF -lLLVMDebugInfoPDB -lLLVMDebugInfoMSF -lLLVMDebugInfoDWARF -lLLVMObject -lLLVMTextAPI -lLLVMMCParser -lLLVMIRReader -lLLVMAsmParser -lLLVMMC -lLLVMDebugInfoCodeView \
Expand Down
4 changes: 2 additions & 2 deletions .github/actions/5a-android-x86/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ runs:
# use bootstrap-ldc, which is guaranteed to be native
bootstrap-ldc/bin/ldc-build-runtime --ninja \
--buildDir="build-libs-$arch" \
--dFlags="-mtriple=$triple;-fvisibility=hidden" \
--dFlags="-mtriple=$triple" \
--ldcSrcDir="$PWD/ldc" \
"${flags[@]}" \
ANDROID_ABI="$abi" # override the one in CROSS_CMAKE_FLAGS

mkdir "installed/lib-$arch"
cp "build-libs-$arch"/lib/*.a "installed/lib-$arch/"
cp "build-libs-$arch"/lib/* "installed/lib-$arch/"
6 changes: 3 additions & 3 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ jobs:
-DD_COMPILER_FLAGS="-O -flto=full -defaultlib=phobos2-ldc-lto,druntime-ldc-lto -L-exported_symbol '-L__*' -L-w"
-DEXTRA_CXXFLAGS=-flto=full
with_pgo: true
llvm_version: 17.0.6 # TODO

- job_name: Android armv7a
host_os: ubuntu-20.04
Expand All @@ -192,7 +193,6 @@ jobs:
timeout-minutes: 60
env:
MACOSX_DEPLOYMENT_TARGET: 11.0
LLVM_VERSION: 17.0.6 # TODO
steps:
- uses: actions/checkout@v4
with:
Expand All @@ -202,7 +202,7 @@ jobs:
uses: ./.github/actions/1-setup
with:
clang_version: ${{ env.CLANG_VERSION }}
llvm_version: ${{ env.LLVM_VERSION }}
llvm_version: ${{ matrix.llvm_version || env.LLVM_VERSION }}
arch: x86_64
- name: Build bootstrap LDC
uses: ./.github/actions/2-build-bootstrap
Expand All @@ -218,7 +218,7 @@ jobs:
with:
arch: ${{ matrix.arch }}
os: ${{ matrix.os }}
llvm_version: ${{ env.LLVM_VERSION }}
llvm_version: ${{ matrix.llvm_version || env.LLVM_VERSION }}
cmake_flags: ${{ matrix.extra_cmake_flags }}
with_pgo: ${{ matrix.with_pgo }}

Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@

#### Big news
- Frontend, druntime and Phobos are at version [2.108.0+](https://dlang.org/changelog/2.108.0.html). (#4591, #4615, #4619)
- Support for [LLVM 18](https://releases.llvm.org/18.1.0/docs/ReleaseNotes.html). The prebuilt packages use v18.1.3 (except for Android and macOS arm64). (#4599, #4605, #4607, #4604, #4622)
- Support for [LLVM 18](https://releases.llvm.org/18.1.0/docs/ReleaseNotes.html). The prebuilt packages use v18.1.3 (except for macOS arm64). (#4599, #4605, #4607, #4604, #4622)
- Android: Switch to native ELF TLS, supported since API level 29 (Android v10), dropping our former custom TLS emulation (requiring a modified LLVM and a legacy ld.bfd linker). The prebuilt packages themselves require Android v10+ (armv7a) / v11+ (aarch64) too, and are built with NDK r26d. Shared druntime and Phobos libraries are now available (`-link-defaultlib-shared`), as on regular Linux. (#4618)

#### Platform support
- Supports LLVM 11 - 18.

#### Bug fixes
- Android: Support the lld linker. (#3918)

# LDC 1.37.0 (2024-03-03)

Expand Down
8 changes: 0 additions & 8 deletions driver/linker-gcc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -621,14 +621,6 @@ void ArgsBuilder::build(llvm::StringRef outputPath,
void ArgsBuilder::addLinker() {
llvm::StringRef linker = opts::linker;

// Default to ld.bfd for Android (placing .tdata and .tbss sections adjacent
// to each other as required by druntime's rt.sections_android, contrary to
// gold and lld as of Android NDK r21d).
if (global.params.targetTriple->getEnvironment() == llvm::Triple::Android &&
opts::linker.getNumOccurrences() == 0) {
linker = "bfd";
}

if (!linker.empty())
args.push_back(("-fuse-ld=" + linker).str());
}
Expand Down
15 changes: 0 additions & 15 deletions driver/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -59,18 +59,3 @@ version (Windows)
SetConsoleOutputCP(originalOutputCP);
}
}

// TLS bracketing symbols required for our custom TLS emulation on Android
// as we don't have a D main() function for LDC and LDMD.
version (Android)
{
import ldc.attributes;

extern(C) __gshared
{
@section(".tdata")
int _tlsstart = 0;
@section(".tcommon")
int _tlsend = 0;
}
}
8 changes: 5 additions & 3 deletions driver/targetmachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -639,12 +639,14 @@ createTargetMachine(const std::string targetTriple, const std::string arch,
targetOptions.DataSections = true;
}

// On Android, we depend on a custom TLS emulation scheme implemented in our
// LLVM fork. LLVM 7+ enables regular emutls by default; prevent that.
// On Android, enforce native ELF TLS (supported since API level 29 = Android
// v10), as required by druntime. (Some older LLVM versions might default to
// EmuTLS).
if (triple.getEnvironment() == llvm::Triple::Android) {
targetOptions.EmulatedTLS = false;
#if LDC_LLVM_VER < 1700
// Removed in this commit: https://github.com/llvm/llvm-project/commit/0d333bf0e3aa37e2e6ae211e3aa80631c3e01b85
// Removed in this commit:
// https://github.com/llvm/llvm-project/commit/0d333bf0e3aa37e2e6ae211e3aa80631c3e01b85
targetOptions.ExplicitEmulatedTLS = true;
#endif
}
Expand Down
3 changes: 1 addition & 2 deletions runtime/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@ else()
endif()

set(SHARED_LIBS_SUPPORTED OFF)
if("${TARGET_SYSTEM}" MATCHES "Windows|Linux|FreeBSD|DragonFly|APPLE"
AND (NOT "${TARGET_SYSTEM}" MATCHES "Android"))
if("${TARGET_SYSTEM}" MATCHES "Windows|Linux|FreeBSD|DragonFly|APPLE")
set(SHARED_LIBS_SUPPORTED ON)
endif()

Expand Down
18 changes: 13 additions & 5 deletions runtime/druntime/src/core/sys/posix/dlfcn.d
Original file line number Diff line number Diff line change
Expand Up @@ -372,12 +372,20 @@ else version (Solaris)
}
else version (CRuntime_Bionic)
{
enum
enum RTLD_LOCAL = 0;
enum RTLD_LAZY = 0x00001;
enum RTLD_NOLOAD = 0x00004;
enum RTLD_NODELETE = 0x01000;

version (D_LP64)
{
enum RTLD_NOW = 0x00002;
enum RTLD_GLOBAL = 0x00100;
}
else // NDK: 'LP32 is broken for historical reasons'
{
RTLD_NOW = 0,
RTLD_LAZY = 1,
RTLD_LOCAL = 0,
RTLD_GLOBAL = 2
enum RTLD_NOW = 0;
enum RTLD_GLOBAL = 0x00002;
}

int dladdr(const scope void*, Dl_info*);
Expand Down
2 changes: 1 addition & 1 deletion runtime/druntime/src/rt/sections.d
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ else version (CRuntime_Microsoft)
public import rt.sections_win64;
}
else version (CRuntime_Bionic)
public import rt.sections_android;
public import rt.sections_elf_shared;
else version (CRuntime_UClibc)
public import rt.sections_elf_shared;
else
Expand Down
2 changes: 2 additions & 0 deletions runtime/druntime/src/rt/sections_android.d
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

module rt.sections_android;

version (LDC) { /* implemented in rt.sections_elf_shared */ } else:

version (CRuntime_Bionic):

// debug = PRINTF;
Expand Down
8 changes: 8 additions & 0 deletions runtime/druntime/src/rt/sections_elf_shared.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ else version (CRuntime_Musl) enum SharedELF = true;
else version (FreeBSD) enum SharedELF = true;
else version (NetBSD) enum SharedELF = true;
else version (DragonFlyBSD) enum SharedELF = true;
else version (CRuntime_Bionic) enum SharedELF = true;
else version (CRuntime_UClibc) enum SharedELF = true;
else enum SharedELF = false;

Expand Down Expand Up @@ -1171,6 +1172,8 @@ else

version (LDC)
{
version (Android) version (X86) version = Android_X86;

version (PPC)
{
extern(C) void* __tls_get_addr_opt(tls_index* ti) nothrow @nogc;
Expand All @@ -1181,6 +1184,11 @@ version (LDC)
extern(C) void* __tls_get_addr_opt(tls_index* ti) nothrow @nogc;
alias __tls_get_addr = __tls_get_addr_opt;
}
else version (Android_X86) // extra underscore
{
extern(C) void* ___tls_get_addr(tls_index* ti) nothrow @nogc;
alias __tls_get_addr = ___tls_get_addr;
}
else
extern(C) void* __tls_get_addr(tls_index* ti) nothrow @nogc;
}
Expand Down
Loading