从C调用Swift遇链接错误:如何用G++/Clang++链接Swift原生目标文件?
Absolutely, this is 100% feasible. Swift supports cross-compiling to Android targets, and the @_cdecl attribute lets you expose Swift functions with C-compatible symbols—making them callable from C/C++ code (exactly what the Android NDK uses). The linker errors you’re seeing are just the linker complaining it can’t find Swift standard library functions your code depends on (like print, string handling, and runtime memory utilities). Fixing the linking step will resolve these issues.
Let’s walk through getting this working from scratch:
1. Write Swift code with @_cdecl
Create a Swift file (e.g., SwiftCode.swift) with functions exposed via @_cdecl. Use C-compatible types (like Int32 instead of Swift’s native Int) to avoid type mismatches:
@_cdecl("swift_print_hello") func swiftPrintHello() { print("Hello from Swift on Android!") } @_cdecl("swift_add_numbers") func swiftAddNumbers(a: Int32, b: Int32) -> Int32 { return a + b } // Optional: String handling example (requires explicit memory management) @_cdecl("swift_greet") func swiftGreet(name: UnsafePointer<CChar>) -> UnsafePointer<CChar> { let swiftName = String(cString: name) let greeting = "Hello, \(swiftName)!" return strdup(greeting) // Allocate memory via C; caller must free it }
2. Compile Swift to an Android object file
You’ll need a Swift toolchain configured for Android cross-compilation. Tools like Swift Android Build Tools can simplify setup. For x86_64 Android, run:
swiftc --target x86_64-linux-android \ -emit-object \ -o swift_code.o \ SwiftCode.swift
For ARM64 Android, replace the target with aarch64-linux-android.
3. Write a C/C++ wrapper (e.g., main.cpp)
Create a C++ file that declares and calls your exposed Swift functions. Use extern "C" to disable C++ name mangling:
#include <stdio.h> #include <stdlib.h> // Declare Swift-exposed C functions extern "C" { void swift_print_hello(); int32_t swift_add_numbers(int32_t a, int32_t b); const char* swift_greet(const char* name); } int main() { printf("Calling Swift code from C++ on Android...\n"); // Call void Swift function swift_print_hello(); // Call Swift function with return value int32_t sum = swift_add_numbers(15, 25); printf("15 + 25 = %d\n", sum); // Call Swift function with string input/output const char* greeting = swift_greet("Android"); printf("%s\n", greeting); free((void*)greeting); // Free memory allocated by strdup in Swift return 0; }
4. Link with the NDK and Swift libraries
The linker errors happen because you weren’t linking against Swift’s standard library and runtime. Use the NDK’s clang++ to link, pointing it to your Swift Android library path:
# Replace these paths with your actual NDK and Swift Android library locations export NDK_PATH="/path/to/android-ndk-r25c" export SWIFT_ANDROID_LIB="/path/to/swift-android-toolchain/usr/lib/swift/android/x86_64" ${NDK_PATH}/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ \ --target x86_64-linux-android24 \ main.cpp \ swift_code.o \ -o android_swift_demo \ -L${SWIFT_ANDROID_LIB} \ -lswiftCore \ -lswiftStdlib \ -lswiftGlibc \ -ldl \ -lm
--target x86_64-linux-android24specifies the minimum Android API level (24 works for most devices).- The
-lflags link against required Swift runtime libraries, resolving all missing__T0*and_swift_*symbols.
5. Run on an Android device/emulator
Push the executable to your device and run it:
adb push android_swift_demo /data/local/tmp/ adb shell chmod +x /data/local/tmp/android_swift_demo adb shell /data/local/tmp/android_swift_demo
You’ll see output like:
Calling Swift code from C++ on Android... Hello from Swift on Android! 15 + 25 = 40 Hello, Android!
@_cdeclis an unofficial (underscored) attribute, but it’s stable across Swift 5.x and 6.x. Be aware it could change in future versions.- Stick to C-compatible types in exposed functions to minimize bridge complexity.
- If using Swift-specific types (like
String), handle memory explicitly to avoid leaks (as shown in theswift_greetexample).
内容的提问来源于stack exchange,提问作者John Gorter

