Skip to content

Codegen picks the target's CRT, not the host's (Android cross-compile) - #506

Merged
ASDAlexander77 merged 2 commits into
mainfrom
android-target-crt
Oct 5, 2026
Merged

ASDAlexander77 merged 2 commits into
mainfrom
android-target-crt

Conversation

@ASDAlexander77

@ASDAlexander77 ASDAlexander77 commented Oct 5, 2026 •

Copy link
Copy Markdown
Owner

Problem

Three codegen choices were made with #ifdef WIN32, i.e. by the host the compiler was built on, not the target being compiled for. A Windows-hosted tslang -mtriple=aarch64-linux-android… therefore emitted:

  • _assert(msg, file, line) for a failing assert (MSVC CRT only)
  • sprintf_s for number → string (MSVC CRT only)
  • comdat exactmatch on class globals, which ELF cannot represent

Fix

  • AssertLogic.h, LowerToLLVM.cpp (ConvertFOpLowering), MLIRGenClasses.cpp now use compileOptions.isWindows (from the triple) instead of the host macro.
  • Android assert: Bionic exports only __assert(file, line, msg) and __assert2(file, line, func, msg), not glibc's __assert_fail (checked against bionic libc/include/assert.h and libc.map.txt). Without this, an Android object compiles but fails to link as soon as assert is used. Added CompileOptions::isAndroid (Triple::isAndroid()), and AssertLogic calls __assert there, with Bionic's argument order.
  • snprintf and comdat any are correct for Bionic/ELF as is.
target assert number → string class comdat
*-windows-msvc _assert sprintf_s exactmatch
*-linux-gnu (and other non-MSVC) __assert_fail snprintf any
*-linux-android* __assert snprintf any

Side effect: isWindows is the MSVC-environment check, so wasm/emscripten built from a Windows host now gets __assert_fail/snprintf too. Emscripten provides both, so that's a fix as well.

Tests

  • New test-compile-target-crt (test/tester/target-crt.cmake): emits LLVM IR for x86_64-pc-windows-msvc, x86_64-unknown-linux-gnu and x86_64-linux-android, and checks that each declares its own CRT's functions and comdat and none of the others'. IR only, so it's registered for every host. It fails against a pre-fix binary (the linux-gnu triple gets _assert).
  • Full Release suite on Windows: 3853/3853 passed (after both commits).
  • Manually: --emit=obj -mtriple=aarch64-linux-android21 produces an ELF object. Not linked against a real NDK sysroot (no NDK on the dev machine).

Shared-library import naming (2nd commit)

import './x' chose x.dll vs libx.so with WIN_LOADSHAREDLIBS/LINUX_LOADSHAREDLIBS (host #ifdef WIN32 in Config.h). That path is also what the program passes to LoadLibraryPermanently at run time, so a Windows-hosted build for Android baked in ./x.dll, and a Linux-hosted build for Windows looked for libx.so. mlirGen(ImportDeclaration) now follows the target OS (Triple::getOS() == Win32), the same rule --emit=dll already uses for its output name (utils.cpp). Windows gives x.dll; anything else gives libx.so. The lib prefix behaves exactly as before. The two macros are removed.

foreign-target-import (x64 DLL imported by an x86_64-Linux program) now writes the DLL as libshared.so, the name that target looks for (still a PE image inside). The not-PE case writes libfoo.so, and read also checks that the program loads libshared.so. Against a pre-fix binary, read fails (the import falls back to shared.ts as source).

Not testable here: the newly enabled direction, a Linux host compiling for Windows and finding x.dll. A Windows host can't read an ELF .so's declarations for a foreign target either (only PE is supported, as before).

🤖 Generated with Claude Code

ASDAlexander77 and others added 2 commits October 5, 2026 11:55
A failing assert, number-to-string conversion and a class's comdat were
chosen with `#ifdef WIN32`, so a Windows-hosted tslang compiling for
Android or Linux emitted MSVC's `_assert`/`sprintf_s` and an `exactmatch`
comdat, which ELF cannot hold. They now follow the target triple
(compileOptions.isWindows).

Android also gets its own assert: Bionic exports `__assert(file, line,
msg)` and `__assert2`, not glibc's `__assert_fail`, so `isAndroid` is set
from the triple and AssertLogic calls `__assert` there.

test-compile-target-crt emits IR for windows-msvc, linux-gnu and
linux-android and checks each declares its own CRT's functions and comdat.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`import './x'` looked for x.dll or libx.so by the host (WIN_LOADSHAREDLIBS /
LINUX_LOADSHAREDLIBS from `#ifdef WIN32`). The path is also the one the
program loads at run time, so a Windows-hosted build for Android baked in
"./x.dll", and a Linux-hosted build for Windows looked for libx.so. It now
follows the target OS, as --emit=dll's output name does (utils.cpp):
Windows x.dll, otherwise libx.so.

foreign-target-import builds its x64 DLL as libshared.so, the name an
x86_64 Linux importer looks for (still a PE image inside), and checks the
program loads libshared.so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ASDAlexander77
ASDAlexander77 merged commit 8b653fb into main Oct 5, 2026
2 checks passed
@ASDAlexander77
ASDAlexander77 deleted the android-target-crt branch October 5, 2026 11:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant