diff --git a/CMakeLists.txt b/CMakeLists.txt index e3ac96fde990a..c8ce957023d20 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,6 +137,20 @@ option(SWIFT_ENABLE_LTO # The following only works with the Ninja generator in CMake >= 3.0. set(SWIFT_PARALLEL_LINK_JOBS "" CACHE STRING "Define the maximum number of linker jobs for swift.") +set(SWIFT_ANDROID_NDK_PATH "" CACHE STRING + "Path to the directory that contains the Android NDK tools that are executable on the build machine") +set(SWIFT_ANDROID_NDK_TOOLCHAIN_VERSION "" CACHE STRING + "A version of the toolchain to use when building for Android. Use 4.8 for 32-bit builds, 4.9 for 64-bit builds") +set(SWIFT_ANDROID_SDK_PATH "" CACHE STRING + "Path to the directory that contains the Android SDK tools that will be passed to the swiftc frontend") +set(SWIFT_ANDROID_ICU_UC "" CACHE STRING + "Path to a directory containing libicuuc.so") +set(SWIFT_ANDROID_ICU_UC_INCLUDE "" CACHE STRING + "Path to a directory containing headers for libicuuc") +set(SWIFT_ANDROID_ICU_I18N "" CACHE STRING + "Path to a directory containing libicui18n.so") +set(SWIFT_ANDROID_ICU_I18N_INCLUDE "" CACHE STRING + "Path to a directory containing headers libicui18n") # # User-configurable Darwin-specific options. @@ -421,9 +435,31 @@ if("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") # FIXME: This will not work while trying to cross-compile. if("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64") - configure_sdk_unix(LINUX "Linux" "linux" "linux" "x86_64" "x86_64-unknown-linux-gnu") set(SWIFT_HOST_VARIANT_ARCH "x86_64") set(SWIFT_PRIMARY_VARIANT_ARCH_default "x86_64") + + if("${SWIFT_ANDROID_NDK_PATH}" STREQUAL "") + set(swift_can_crosscompile_stdlib FALSE) + else() + set(swift_can_crosscompile_stdlib TRUE) + endif() + + is_sdk_requested(LINUX swift_build_linux) + if(swift_build_linux) + configure_sdk_unix(LINUX "Linux" "linux" "linux" "x86_64" "x86_64-unknown-linux-gnu") + set(SWIFT_PRIMARY_VARIANT_SDK_default "LINUX") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "x86_64") + endif() + + is_sdk_requested(ANDROID swift_build_android) + if(swift_build_android AND ${swift_can_crosscompile_stdlib}) + configure_sdk_unix(ANDROID "Android" "android" "android" "armv7" "armv7-none-linux-androideabi") + set(SWIFT_SDK_ANDROID_PATH "${SWIFT_ANDROID_SDK_PATH}") + + set(SWIFT_PRIMARY_VARIANT_SDK_default "ANDROID") + set(SWIFT_PRIMARY_VARIANT_ARCH_default "armv7") + endif() + # FIXME: This only matches ARMv6l (by far the most common variant). elseif("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "armv6l") configure_sdk_unix(LINUX "Linux" "linux" "linux" "armv6" "armv6-unknown-linux-gnueabihf") diff --git a/cmake/modules/AddSwift.cmake b/cmake/modules/AddSwift.cmake index 8ad00d0de5cc3..1f33d59048574 100644 --- a/cmake/modules/AddSwift.cmake +++ b/cmake/modules/AddSwift.cmake @@ -73,6 +73,14 @@ function(_add_variant_c_compile_link_flags) list(APPEND result "-isysroot" "${SWIFT_SDK_${CFLAGS_SDK}_PATH}") + if("${CFLAGS_SDK}" STREQUAL "ANDROID") + list(APPEND result + "--sysroot=${SWIFT_ANDROID_SDK_PATH}" + # Use the linker included in the Android NDK. + "-B" "${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_TOOLCHAIN_VERSION}/prebuilt/linux-x86_64/arm-linux-androideabi/bin/") + endif() + + if("${CMAKE_SYSTEM_NAME}" STREQUAL "Darwin") # Check if there's a specific iOS deployment version needed for this invocation @@ -156,6 +164,13 @@ function(_add_variant_c_compile_flags) "-fcoverage-mapping") endif() + if("${CFLAGS_SDK}" STREQUAL "ANDROID") + list(APPEND result + "-I${SWIFT_ANDROID_NDK_PATH}/sources/cxx-stl/llvm-libc++/libcxx/include" + "-I${SWIFT_ANDROID_NDK_PATH}/sources/cxx-stl/llvm-libc++abi/libcxxabi/include" + "-I${SWIFT_ANDROID_NDK_PATH}/sources/android/support/include") + endif() + set("${CFLAGS_RESULT_VAR_NAME}" "${result}" PARENT_SCOPE) endfunction() @@ -224,7 +239,13 @@ function(_add_variant_link_flags) elseif("${LFLAGS_SDK}" STREQUAL "FREEBSD") list(APPEND result "-lpthread") elseif("${LFLAGS_SDK}" STREQUAL "CYGWIN") - # NO extra libraries required. + # No extra libraries required. + elseif("${LFLAGS_SDK}" STREQUAL "ANDROID") + list(APPEND result + "-ldl" + "-L${SWIFT_ANDROID_NDK_PATH}/toolchains/arm-linux-androideabi-${SWIFT_ANDROID_NDK_TOOLCHAIN_VERSION}/prebuilt/linux-x86_64/lib/gcc/arm-linux-androideabi/${SWIFT_ANDROID_NDK_TOOLCHAIN_VERSION}" + "${SWIFT_ANDROID_NDK_PATH}/sources/cxx-stl/llvm-libc++/libs/armeabi-v7a/libc++_shared.so" + "-L${SWIFT_ANDROID_ICU_UC}" "-L${SWIFT_ANDROID_ICU_I18N}") else() list(APPEND result "-lobjc") endif() @@ -997,7 +1018,7 @@ function(_add_swift_library_single target name) set_target_properties("${target}" PROPERTIES INSTALL_NAME_DIR "${install_name_dir}") - elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") + elseif("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux" AND NOT "${SWIFTLIB_SINGLE_SDK}" STREQUAL "ANDROID") set_target_properties("${target}" PROPERTIES INSTALL_RPATH "$ORIGIN:/usr/lib/swift/linux") diff --git a/cmake/modules/FindICU.cmake b/cmake/modules/FindICU.cmake index a1f631c5f1f47..9fb78e3c34b80 100644 --- a/cmake/modules/FindICU.cmake +++ b/cmake/modules/FindICU.cmake @@ -25,5 +25,12 @@ foreach(MODULE ${ICU_FIND_COMPONENTS}) endif() endforeach() +if(NOT "${SWIFT_ANDROID_ICU_UC_INCLUDE}" STREQUAL "") + set(ICU_UC_INCLUDE_DIR "${SWIFT_ANDROID_ICU_UC_INCLUDE}") +endif() +if(NOT "${SWIFT_ANDROID_ICU_I18N_INCLUDE}" STREQUAL "") + set(ICU_I18N_INCLUDE_DIR "${SWIFT_ANDROID_ICU_I18N_INCLUDE}") +endif() + find_package_handle_standard_args(ICU DEFAULT_MSG ${ICU_REQUIRED}) mark_as_advanced(${ICU_REQUIRED}) diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index f15847b71b248..b612cb88d2afb 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -184,7 +184,7 @@ namespace swift { } else if (Target.isWatchOS()) { Target.getOSVersion(major, minor, revision); } else if (Target.isOSLinux() || Target.isOSFreeBSD() || - Target.isOSWindows() || + Target.isAndroid() || Target.isOSWindows() || Target.getTriple().empty()) { major = minor = revision = 0; diff --git a/lib/Basic/LangOptions.cpp b/lib/Basic/LangOptions.cpp index 7a5b80cc379a4..2d157d91a201c 100644 --- a/lib/Basic/LangOptions.cpp +++ b/lib/Basic/LangOptions.cpp @@ -30,7 +30,8 @@ static const StringRef SupportedConditionalCompilationOSs[] = { "iOS", "Linux", "FreeBSD", - "Windows" + "Windows", + "Android" }; static const StringRef SupportedConditionalCompilationArches[] = { @@ -105,6 +106,8 @@ std::pair LangOptions::setTarget(llvm::Triple triple) { addPlatformConditionValue("os", "watchOS"); else if (triple.isiOS()) addPlatformConditionValue("os", "iOS"); + else if (triple.isAndroid()) + addPlatformConditionValue("os", "Android"); else if (triple.isOSLinux()) addPlatformConditionValue("os", "Linux"); else if (triple.isOSFreeBSD()) diff --git a/lib/Basic/Platform.cpp b/lib/Basic/Platform.cpp index 63ace1d688630..c3538e4053e81 100644 --- a/lib/Basic/Platform.cpp +++ b/lib/Basic/Platform.cpp @@ -88,6 +88,9 @@ StringRef swift::getPlatformNameForTriple(const llvm::Triple &triple) { if (triple.isOSDarwin()) return getPlatformNameForDarwin(getDarwinPlatformKind(triple)); + if (triple.isAndroid()) + return "android"; + if (triple.isOSLinux()) return "linux"; diff --git a/lib/ClangImporter/MappedTypes.def b/lib/ClangImporter/MappedTypes.def index 7cdf7afd7ee38..8ab0b558689cd 100644 --- a/lib/ClangImporter/MappedTypes.def +++ b/lib/ClangImporter/MappedTypes.def @@ -127,6 +127,7 @@ MAP_STDLIB_TYPE("u_int64_t", UnsignedInt, 64, "UInt64", false, DoNothing) // FIXME: why does this not catch va_list on x86_64? MAP_STDLIB_TYPE("va_list", VaList, 0, "CVaListPointer", false, DoNothing) MAP_STDLIB_TYPE("__gnuc_va_list", VaList, 0, "CVaListPointer", false, DoNothing) +MAP_STDLIB_TYPE("__va_list", VaList, 0, "CVaListPointer", false, DoNothing) // libkern/OSTypes.h types. MAP_STDLIB_TYPE("UInt", UnsignedInt, 32, "CUnsignedInt", false, DoNothing) diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 8d08afbb6300e..75301b6537603 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -2031,6 +2031,12 @@ const ToolChain *Driver::getToolChain(const ArgList &Args) const { TC = new toolchains::Darwin(*this, Target); break; case llvm::Triple::Linux: + if (Target.isAndroid()) { + TC = new toolchains::Android(*this, Target); + } else { + TC = new toolchains::GenericUnix(*this, Target); + } + break; case llvm::Triple::FreeBSD: TC = new toolchains::GenericUnix(*this, Target); break; diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 2ef7be1778e03..068784040eeae 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1210,11 +1210,11 @@ std::string toolchains::GenericUnix::getDefaultLinker() const { } } -bool toolchains::GenericUnix::shouldProvideRPathToLinker() const { - return true; +std::string toolchains::GenericUnix::getTargetForLinker() const { + return getTriple().str(); } -bool toolchains::GenericUnix::shouldSpecifyTargetTripleToLinker() const { +bool toolchains::GenericUnix::shouldProvideRPathToLinker() const { return true; } @@ -1266,9 +1266,10 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, Arguments.push_back(context.Args.MakeArgString("-fuse-ld=" + Linker)); } - // Explicitly pass the target to the linker - if (shouldSpecifyTargetTripleToLinker()) { - Arguments.push_back(context.Args.MakeArgString("--target=" + getTriple().str())); + std::string Target = getTargetForLinker(); + if (!Target.empty()) { + Arguments.push_back("-target"); + Arguments.push_back(context.Args.MakeArgString(Target)); } // Add the runtime library link path, which is platform-specific and found @@ -1340,13 +1341,29 @@ toolchains::GenericUnix::constructInvocation(const LinkJobAction &job, return {"clang++", Arguments}; } +std::string +toolchains::Android::getTargetForLinker() const { + // Explicitly set the linker target to "androideabi", as opposed to the + // llvm::Triple representation of "armv7-none-linux-android". + // This is the only ABI we currently support for Android. + assert( + getTriple().getArch() == llvm::Triple::arm && + getTriple().getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v7 && + "Only armv7 targets are supported for Android"); + return "armv7-none-linux-androideabi"; +} + +bool toolchains::Android::shouldProvideRPathToLinker() const { + return false; +} + std::string toolchains::Cygwin::getDefaultLinker() const { // Cygwin uses the default BFD linker, even on ARM. return ""; } -bool toolchains::Cygwin::shouldSpecifyTargetTripleToLinker() const { - return false; +std::string toolchains::Cygwin::getTargetForLinker() const { + return ""; } std::string toolchains::Cygwin::getPreInputObjectPath( diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 345a6617517e4..1ba3f18a205cc 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -53,17 +53,17 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { /// and to not provide a specific linker otherwise. virtual std::string getDefaultLinker() const; + /// The target to be passed to the compiler invocation. By default, this + /// is the target triple, but this may be overridden to accomodate some + /// platforms. + virtual std::string getTargetForLinker() const; + /// Whether to specify a linker -rpath to the Swift runtime library path. /// -rpath is not supported on all platforms, and subclasses may override /// this method to return false on platforms that don't support it. The /// default is to return true (and so specify an -rpath). virtual bool shouldProvideRPathToLinker() const; - /// Whether to explicitly specify the target triple as the linker - /// '--target'. This is not desirable on all platforms, and subclasses may - /// override this method to return false in those cases. - virtual bool shouldSpecifyTargetTripleToLinker() const; - /// Provides a path to an object that should be linked first. On platforms /// that use ELF binaries, an object that provides markers and sizes for /// metadata sections must be linked first. Platforms that do not need this @@ -96,11 +96,21 @@ class LLVM_LIBRARY_VISIBILITY GenericUnix : public ToolChain { ~GenericUnix() = default; }; +class LLVM_LIBRARY_VISIBILITY Android : public GenericUnix { +protected: + std::string getTargetForLinker() const override; + + bool shouldProvideRPathToLinker() const override; +public: + Android(const Driver &D, const llvm::Triple &Triple) : GenericUnix(D, Triple) {} + ~Android() = default; +}; + class LLVM_LIBRARY_VISIBILITY Cygwin : public GenericUnix { protected: std::string getDefaultLinker() const override; - bool shouldSpecifyTargetTripleToLinker() const override; + std::string getTargetForLinker() const override; std::string getPreInputObjectPath( StringRef RuntimeLibraryPath) const override; diff --git a/stdlib/private/StdlibUnittest/RaceTest.swift b/stdlib/private/StdlibUnittest/RaceTest.swift index d8c76381ebd30..3e6020da964d7 100644 --- a/stdlib/private/StdlibUnittest/RaceTest.swift +++ b/stdlib/private/StdlibUnittest/RaceTest.swift @@ -40,7 +40,7 @@ import SwiftPrivate import SwiftPrivatePthreadExtras #if os(OSX) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif diff --git a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift index 3f2d5f37b79a1..42e08b42953ae 100644 --- a/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift +++ b/stdlib/private/StdlibUnittest/StdlibCoreExtras.swift @@ -14,7 +14,7 @@ import SwiftPrivate import SwiftPrivateLibcExtras #if os(OSX) || os(iOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif diff --git a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb index 3a5d8e64402d4..f03e0200f9a0f 100644 --- a/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb +++ b/stdlib/private/StdlibUnittest/StdlibUnittest.swift.gyb @@ -16,7 +16,7 @@ import SwiftPrivateLibcExtras #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif @@ -1170,6 +1170,7 @@ public enum OSVersion : CustomStringConvertible { case watchOSSimulator case linux case freeBSD + case android public var description: String { switch self { @@ -1191,6 +1192,8 @@ public enum OSVersion : CustomStringConvertible { return "Linux" case freeBSD: return "FreeBSD" + case android: + return "Android" } } } @@ -1225,6 +1228,8 @@ func _getOSVersion() -> OSVersion { return .linux #elseif os(FreeBSD) return .freeBSD +#elseif os(Android) + return .android #else let productVersion = _stdlib_getSystemVersionPlistProperty("ProductVersion")! let (major, minor, bugFix) = _parseDottedVersionTriple(productVersion) @@ -1299,6 +1304,8 @@ public enum TestRunPredicate : CustomStringConvertible { case freeBSDAny(reason: String) + case androidAny(reason: String) + case objCRuntime(/*reason:*/ String) case nativeRuntime(/*reason:*/ String) @@ -1376,6 +1383,9 @@ public enum TestRunPredicate : CustomStringConvertible { case linuxAny(reason: let reason): return "linuxAny(*, reason: \(reason))" + case androidAny(reason: let reason): + return "androidAny(*, reason: \(reason))" + case freeBSDAny(reason: let reason): return "freeBSDAny(*, reason: \(reason))" @@ -1620,6 +1630,14 @@ public enum TestRunPredicate : CustomStringConvertible { return false } + case androidAny: + switch _getRunningOSVersion() { + case .android: + return true + default: + return false + } + case freeBSDAny: switch _getRunningOSVersion() { case .freeBSD: diff --git a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift index f122e138446f2..2857a936e43d8 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/Subprocess.swift @@ -13,10 +13,16 @@ import SwiftPrivate #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif + +// posix_spawn is not available on Android. +#if !os(Android) +// swift_posix_spawn isn't available in the public watchOS SDK, we sneak by the +// unavailable attribute declaration here of the APIs that we need. + // FIXME: Come up with a better way to deal with APIs that are pointers on some // platforms but not others. #if os(Linux) @@ -25,9 +31,6 @@ typealias swift_posix_spawn_file_actions_t = posix_spawn_file_actions_t typealias swift_posix_spawn_file_actions_t = posix_spawn_file_actions_t? #endif -// posix_spawn isn't available in the public watchOS SDK, we sneak by the -// unavailable attribute declaration here of the APIs that we need. - @_silgen_name("posix_spawn_file_actions_init") func swift_posix_spawn_file_actions_init( _ file_actions: UnsafeMutablePointer @@ -57,6 +60,7 @@ func swift_posix_spawn( _ attrp: UnsafePointer?, _ argv: UnsafePointer?>, _ envp: UnsafePointer?>?) -> CInt +#endif /// Calls POSIX `pipe()`. func posixPipe() -> (readFD: CInt, writeFD: CInt) { @@ -71,12 +75,74 @@ func posixPipe() -> (readFD: CInt, writeFD: CInt) { /// stderr. public func spawnChild(_ args: [String]) -> (pid: pid_t, stdinFD: CInt, stdoutFD: CInt, stderrFD: CInt) { + // The stdout, stdin, and stderr from the child process will be redirected + // to these pipes. + let childStdout = posixPipe() + let childStdin = posixPipe() + let childStderr = posixPipe() + +#if os(Android) + // posix_spawn isn't available on Android. Instead, we fork and exec. + // To correctly communicate the exit status of the child process to this + // (parent) process, we'll use this pipe. + let childToParentPipe = posixPipe() + + let pid = fork() + precondition(pid >= 0, "fork() failed") + if pid == 0 { + // pid of 0 means we are now in the child process. + // Capture the output before executing the program. + dup2(childStdout.writeFD, STDOUT_FILENO) + dup2(childStdin.readFD, STDIN_FILENO) + dup2(childStderr.writeFD, STDERR_FILENO) + + // Set the "close on exec" flag on the parent write pipe. This will + // close the pipe if the execve() below successfully executes a child + // process. + let closeResult = fcntl(childToParentPipe.writeFD, F_SETFD, FD_CLOEXEC) + let closeErrno = errno + precondition( + closeResult == 0, + "Could not set the close behavior of the child-to-parent pipe; " + + "errno: \(closeErrno)") + + // Start the executable. If execve() does not encounter an error, the + // code after this block will never be executed, and the parent write pipe + // will be closed. + withArrayOfCStrings([Process.arguments[0]] + args) { + execve(Process.arguments[0], $0, _getEnviron()) + } + + // If execve() encountered an error, we write the errno encountered to the + // parent write pipe. + let errnoSize = sizeof(errno.dynamicType) + var execveErrno = errno + let writtenBytes = withUnsafePointer(&execveErrno) { + write(childToParentPipe.writeFD, UnsafePointer($0), errnoSize) + } + + let writeErrno = errno + if writtenBytes > 0 && writtenBytes < errnoSize { + // We were able to write some of our error, but not all of it. + // FIXME: Retry in this case. + preconditionFailure("Unable to write entire error to child-to-parent " + + "pipe.") + } else if writtenBytes == 0 { + preconditionFailure("Unable to write error to child-to-parent pipe.") + } else if writtenBytes < 0 { + preconditionFailure("An error occurred when writing error to " + + "child-to-parent pipe; errno: \(writeErrno)") + } + + // Close the pipe when we're done writing the error. + close(childToParentPipe.writeFD) + } +#else var fileActions = _make_posix_spawn_file_actions_t() if swift_posix_spawn_file_actions_init(&fileActions) != 0 { preconditionFailure("swift_posix_spawn_file_actions_init() failed") } - let childStdin = posixPipe() // Close the write end of the pipe on the child side. if swift_posix_spawn_file_actions_addclose( &fileActions, childStdin.writeFD) != 0 { @@ -89,7 +155,6 @@ public func spawnChild(_ args: [String]) preconditionFailure("swift_posix_spawn_file_actions_adddup2() failed") } - let childStdout = posixPipe() // Close the read end of the pipe on the child side. if swift_posix_spawn_file_actions_addclose( &fileActions, childStdout.readFD) != 0 { @@ -102,7 +167,6 @@ public func spawnChild(_ args: [String]) preconditionFailure("swift_posix_spawn_file_actions_adddup2() failed") } - let childStderr = posixPipe() // Close the read end of the pipe on the child side. if swift_posix_spawn_file_actions_addclose( &fileActions, childStderr.readFD) != 0 { @@ -136,6 +200,7 @@ public func spawnChild(_ args: [String]) if swift_posix_spawn_file_actions_destroy(&fileActions) != 0 { preconditionFailure("swift_posix_spawn_file_actions_destroy() failed") } +#endif // Close the read end of the pipe on the parent side. if close(childStdin.readFD) != 0 { @@ -155,6 +220,7 @@ public func spawnChild(_ args: [String]) return (pid, childStdin.writeFD, childStdout.readFD, childStderr.readFD) } +#if !os(Android) #if os(Linux) internal func _make_posix_spawn_file_actions_t() -> swift_posix_spawn_file_actions_t { @@ -166,6 +232,7 @@ internal func _make_posix_spawn_file_actions_t() return nil } #endif +#endif internal func _readAll(_ fd: CInt) -> String { var buffer = [UInt8](repeating: 0, count: 1024) @@ -261,6 +328,8 @@ internal func _getEnviron() -> UnsafeMutablePointer? return _NSGetEnviron().pointee #elseif os(FreeBSD) return environ; +#elseif os(Android) + return environ #else return __environ #endif diff --git a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift index 06b01f0c2db0d..af20d7fbf65b5 100644 --- a/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift +++ b/stdlib/private/SwiftPrivateLibcExtras/SwiftPrivateLibcExtras.swift @@ -13,11 +13,14 @@ import SwiftPrivate #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif public func _stdlib_mkstemps(_ template: inout String, _ suffixlen: CInt) -> CInt { +#if os(Android) + preconditionFailure("mkstemps doesn't work on Android") +#else var utf8 = template.nulTerminatedUTF8 let (fd, fileName) = utf8.withUnsafeMutableBufferPointer { (utf8) -> (CInt, String) in @@ -27,6 +30,7 @@ public func _stdlib_mkstemps(_ template: inout String, _ suffixlen: CInt) -> CIn } template = fileName return fd +#endif } public var _stdlib_FD_SETSIZE: CInt { diff --git a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift index 84fd3e24ce089..02ec2d4dcc269 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/PthreadBarriers.swift @@ -12,7 +12,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif diff --git a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift index 15a259f0a7a37..66f17170c8f24 100644 --- a/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift +++ b/stdlib/private/SwiftPrivatePthreadExtras/SwiftPrivatePthreadExtras.swift @@ -17,7 +17,7 @@ #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) import Darwin -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) import Glibc #endif @@ -81,7 +81,7 @@ public func _stdlib_pthread_create_block( } } -#if os(Linux) +#if os(Linux) || os(Android) internal func _make_pthread_t() -> pthread_t { return pthread_t() } diff --git a/stdlib/public/Platform/CMakeLists.txt b/stdlib/public/Platform/CMakeLists.txt index 26effd62b4017..2485950eecd1b 100644 --- a/stdlib/public/Platform/CMakeLists.txt +++ b/stdlib/public/Platform/CMakeLists.txt @@ -30,22 +30,26 @@ add_swift_library(${swift_platform_name} IS_SDK_OVERLAY set(glibc_modulemap_target_list) foreach(sdk ${SWIFT_SDKS}) - if(${sdk} STREQUAL "LINUX" OR ${sdk} STREQUAL "FREEBSD") + if(${sdk} STREQUAL "LINUX" OR ${sdk} STREQUAL "FREEBSD" OR ${sdk} STREQUAL "ANDROID") foreach(arch ${SWIFT_SDK_${sdk}_ARCHITECTURES}) set(arch_subdir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}") set(module_dir "${SWIFTLIB_DIR}/${arch_subdir}") - # Determine the location of glibc headers based on the target. - set(GLIBC_INCLUDE_PATH "/usr/include") - set(GLIBC_ARCH_INCLUDE_PATH ${GLIBC_INCLUDE_PATH}) - if(CMAKE_LIBRARY_ARCHITECTURE) + # Determine the location of glibc based on the target. + if(${sdk} STREQUAL "ANDROID") + set(GLIBC_INCLUDE_PATH "${SWIFT_ANDROID_SDK_PATH}/usr/include") + set(GLIBC_ARCH_INCLUDE_PATH ${GLIBC_INCLUDE_PATH}) + else() + set(GLIBC_INCLUDE_PATH "/usr/include") + set(GLIBC_ARCH_INCLUDE_PATH ${GLIBC_INCLUDE_PATH}) + if((${sdk} STREQUAL "LINUX" OR ${sdk} STREQUAL "FREEBSD") AND CMAKE_LIBRARY_ARCHITECTURE) # FIXME: Some distributions install headers in # "/usr/include/x86_64-linux-gnu/sys/...". Here we use the host # machine's path, regardless of the SDK target we're building for. # This will break if cross-compiling from a distro that uses the # architecture as part of the path to a distro that does not. - set(GLIBC_ARCH_INCLUDE_PATH - "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}") + set(GLIBC_ARCH_INCLUDE_PATH "${GLIBC_INCLUDE_PATH}/${CMAKE_LIBRARY_ARCHITECTURE}") + endif() endif() # Configure the module map based on the target. Each platform needs to diff --git a/stdlib/public/Platform/Platform.swift b/stdlib/public/Platform/Platform.swift index edf12ede285df..e6582eac5fbee 100644 --- a/stdlib/public/Platform/Platform.swift +++ b/stdlib/public/Platform/Platform.swift @@ -103,6 +103,8 @@ public var errno : Int32 { get { #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) || os(FreeBSD) return __error().pointee +#elseif os(Android) + return __errno().pointee #else return __errno_location().pointee #endif @@ -110,6 +112,8 @@ public var errno : Int32 { set(val) { #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) || os(FreeBSD) return __error().pointee = val +#elseif os(Android) + return __errno().pointee = val #else return __errno_location().pointee = val #endif @@ -313,7 +317,7 @@ public var SIG_DFL: sig_t? { return nil } public var SIG_IGN: sig_t { return unsafeBitCast(1, to: sig_t.self) } public var SIG_ERR: sig_t { return unsafeBitCast(-1, to: sig_t.self) } public var SIG_HOLD: sig_t { return unsafeBitCast(5, to: sig_t.self) } -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) public typealias sighandler_t = __sighandler_t public var SIG_DFL: sighandler_t? { return nil } @@ -339,7 +343,7 @@ public var SEM_FAILED: UnsafeMutablePointer? { #if os(OSX) || os(iOS) || os(watchOS) || os(tvOS) // The value is ABI. Value verified to be correct for OS X, iOS, watchOS, tvOS. return UnsafeMutablePointer(bitPattern: -1) -#elseif os(Linux) || os(FreeBSD) +#elseif os(Linux) || os(FreeBSD) || os(Android) // The value is ABI. Value verified to be correct on Glibc. return UnsafeMutablePointer(bitPattern: 0) #else diff --git a/stdlib/public/Platform/glibc.modulemap.in.gyb b/stdlib/public/Platform/glibc.modulemap.in.gyb index 147f31ea5fb56..50f83f502921a 100644 --- a/stdlib/public/Platform/glibc.modulemap.in.gyb +++ b/stdlib/public/Platform/glibc.modulemap.in.gyb @@ -19,15 +19,28 @@ /// It's not named just Glibc so that it doesn't conflict in the event of a /// future official glibc modulemap. module SwiftGlibc [system] { +% if CMAKE_SDK in ["LINUX", "FREEBSD"]: link "pthread" +% end + link "dl" // C standard library module C { +% if CMAKE_SDK in ["LINUX", "FREEBSD"]: module complex { header "@GLIBC_INCLUDE_PATH@/complex.h" export * } +% end + +% if CMAKE_SDK in ["LINUX", "ANDROID"]: + module features { + header "@GLIBC_INCLUDE_PATH@/features.h" + export * + } +% end + module ctype { header "@GLIBC_INCLUDE_PATH@/ctype.h" export * @@ -37,13 +50,6 @@ module SwiftGlibc [system] { export * } -% if CMAKE_SDK in ["LINUX"]: - module features { - header "@GLIBC_INCLUDE_PATH@/features.h" - export * - } -% end - module fenv { header "@GLIBC_INCLUDE_PATH@/fenv.h" export * @@ -133,10 +139,84 @@ module SwiftGlibc [system] { // POSIX module POSIX { +% if CMAKE_SDK in ["LINUX"]: + module wait { + header "@GLIBC_INCLUDE_PATH@/wait.h" + export * + } +% end + +% if CMAKE_SDK in ["LINUX", "FREEBSD"]: module aio { header "@GLIBC_INCLUDE_PATH@/aio.h" export * } + module cpio { + header "@GLIBC_INCLUDE_PATH@/cpio.h" + export * + } + module fmtmsg { + header "@GLIBC_INCLUDE_PATH@/fmtmsg.h" + export * + } + module ftw { + header "@GLIBC_INCLUDE_PATH@/ftw.h" + export * + } + module glob { + header "@GLIBC_INCLUDE_PATH@/glob.h" + export * + } + module iconv { + header "@GLIBC_INCLUDE_PATH@/iconv.h" + export * + } + module langinfo { + header "@GLIBC_INCLUDE_PATH@/langinfo.h" + export * + } + module monetary { + header "@GLIBC_INCLUDE_PATH@/monetary.h" + export * + } + module netdb { + header "@GLIBC_INCLUDE_PATH@/netdb.h" + export * + } + module nl_types { + header "@GLIBC_INCLUDE_PATH@/nl_types.h" + export * + } + module search { + header "@GLIBC_INCLUDE_PATH@/search.h" + export * + } + module spawn { + header "@GLIBC_INCLUDE_PATH@/spawn.h" + export * + } + module syslog { + header "@GLIBC_INCLUDE_PATH@/syslog.h" + export * + } + module tar { + header "@GLIBC_INCLUDE_PATH@/tar.h" + export * + } + module ulimit { + header "@GLIBC_INCLUDE_PATH@/ulimit.h" + export * + } + module utmpx { + header "@GLIBC_INCLUDE_PATH@/utmpx.h" + export * + } + module wordexp { + header "@GLIBC_INCLUDE_PATH@/wordexp.h" + export * + } +% end + module arpa { module inet { header "@GLIBC_INCLUDE_PATH@/arpa/inet.h" @@ -144,10 +224,6 @@ module SwiftGlibc [system] { } export * } - module cpio { - header "@GLIBC_INCLUDE_PATH@/cpio.h" - export * - } module dirent { header "@GLIBC_INCLUDE_PATH@/dirent.h" export * @@ -160,50 +236,22 @@ module SwiftGlibc [system] { header "@GLIBC_INCLUDE_PATH@/fcntl.h" export * } - module fmtmsg { - header "@GLIBC_INCLUDE_PATH@/fmtmsg.h" - export * - } module fnmatch { header "@GLIBC_INCLUDE_PATH@/fnmatch.h" export * } - module ftw { - header "@GLIBC_INCLUDE_PATH@/ftw.h" - export * - } - module glob { - header "@GLIBC_INCLUDE_PATH@/glob.h" - export * - } module grp { header "@GLIBC_INCLUDE_PATH@/grp.h" export * } - module iconv { - header "@GLIBC_INCLUDE_PATH@/iconv.h" - export * - } module ioctl { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/ioctl.h" export * } - module langinfo { - header "@GLIBC_INCLUDE_PATH@/langinfo.h" - export * - } module libgen { header "@GLIBC_INCLUDE_PATH@/libgen.h" export * } - module monetary { - header "@GLIBC_INCLUDE_PATH@/monetary.h" - export * - } - module netdb { - header "@GLIBC_INCLUDE_PATH@/netdb.h" - export * - } module net { module if { header "@GLIBC_INCLUDE_PATH@/net/if.h" @@ -222,10 +270,6 @@ module SwiftGlibc [system] { export * } } - module nl_types { - header "@GLIBC_INCLUDE_PATH@/nl_types.h" - export * - } module poll { header "@GLIBC_INCLUDE_PATH@/poll.h" export * @@ -246,18 +290,10 @@ module SwiftGlibc [system] { header "@GLIBC_INCLUDE_PATH@/sched.h" export * } - module search { - header "@GLIBC_INCLUDE_PATH@/search.h" - export * - } module semaphore { header "@GLIBC_INCLUDE_PATH@/semaphore.h" export * } - module spawn { - header "@GLIBC_INCLUDE_PATH@/spawn.h" - export * - } module strings { header "@GLIBC_INCLUDE_PATH@/strings.h" export * @@ -266,6 +302,21 @@ module SwiftGlibc [system] { module sys { export * +% if CMAKE_SDK in ["LINUX", "FREEBSD"]: + module sem { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/sem.h" + export * + } + module shm { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/shm.h" + export * + } + module statvfs { + header "@GLIBC_ARCH_INCLUDE_PATH@/sys/statvfs.h" + export * + } +% end + module ipc { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/ipc.h" export * @@ -286,14 +337,6 @@ module SwiftGlibc [system] { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/select.h" export * } - module sem { - header "@GLIBC_ARCH_INCLUDE_PATH@/sys/sem.h" - export * - } - module shm { - header "@GLIBC_ARCH_INCLUDE_PATH@/sys/shm.h" - export * - } module socket { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/socket.h" export * @@ -302,10 +345,6 @@ module SwiftGlibc [system] { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/stat.h" export * } - module statvfs { - header "@GLIBC_ARCH_INCLUDE_PATH@/sys/statvfs.h" - export * - } module time { header "@GLIBC_ARCH_INCLUDE_PATH@/sys/time.h" export * @@ -335,22 +374,10 @@ module SwiftGlibc [system] { export * } } - module syslog { - header "@GLIBC_INCLUDE_PATH@/syslog.h" - export * - } - module tar { - header "@GLIBC_INCLUDE_PATH@/tar.h" - export * - } module termios { header "@GLIBC_INCLUDE_PATH@/termios.h" export * } - module ulimit { - header "@GLIBC_INCLUDE_PATH@/ulimit.h" - export * - } module unistd { header "@GLIBC_INCLUDE_PATH@/unistd.h" export * @@ -359,19 +386,5 @@ module SwiftGlibc [system] { header "@GLIBC_INCLUDE_PATH@/utime.h" export * } - module utmpx { - header "@GLIBC_INCLUDE_PATH@/utmpx.h" - export * - } -% if CMAKE_SDK in ["LINUX"]: - module wait { - header "@GLIBC_INCLUDE_PATH@/wait.h" - export * - } -% end - module wordexp { - header "@GLIBC_INCLUDE_PATH@/wordexp.h" - export * - } } } diff --git a/stdlib/public/Platform/tgmath.swift.gyb b/stdlib/public/Platform/tgmath.swift.gyb index 9bb72ce9771ce..e2c5dac4a609c 100644 --- a/stdlib/public/Platform/tgmath.swift.gyb +++ b/stdlib/public/Platform/tgmath.swift.gyb @@ -282,7 +282,7 @@ public func scalbn(_ x: ${T}, _ n: Int) -> ${T} { % # This is AllFloatTypes not OverlayFloatTypes because of the tuple return. % for T, CT, f in AllFloatTypes(): -#if os(Linux) || os(FreeBSD) +#if os(Linux) || os(FreeBSD) || os(Android) @_transparent @warn_unused_result public func lgamma(_ x: ${T}) -> (${T}, Int) { diff --git a/stdlib/public/SwiftShims/LibcShims.h b/stdlib/public/SwiftShims/LibcShims.h index d0934c3fad02c..747b45169b6ea 100644 --- a/stdlib/public/SwiftShims/LibcShims.h +++ b/stdlib/public/SwiftShims/LibcShims.h @@ -29,7 +29,7 @@ namespace swift { extern "C" { // This declaration is not universally correct. We verify its correctness for // the current platform in the runtime code. -#if defined(__linux__) && defined (__arm__) +#if defined(__linux__) && defined (__arm__) && !defined(__android__) typedef int __swift_ssize_t; #else typedef long int __swift_ssize_t; diff --git a/stdlib/public/runtime/CMakeLists.txt b/stdlib/public/runtime/CMakeLists.txt index 85d3047972060..282cee703573b 100644 --- a/stdlib/public/runtime/CMakeLists.txt +++ b/stdlib/public/runtime/CMakeLists.txt @@ -82,7 +82,7 @@ endif() set(object_target_list) foreach(sdk ${SWIFT_CONFIGURED_SDKS}) - if("${sdk}" STREQUAL "LINUX" OR "${sdk}" STREQUAL "FREEBSD") + if("${sdk}" STREQUAL "LINUX" OR "${sdk}" STREQUAL "FREEBSD" OR "${sdk}" STREQUAL "ANDROID") foreach(arch ${SWIFT_SDK_${sdk}_ARCHITECTURES}) set(arch_subdir "${SWIFT_SDK_${sdk}_LIB_SUBDIR}/${arch}") @@ -109,4 +109,3 @@ foreach(sdk ${SWIFT_CONFIGURED_SDKS}) endforeach() add_custom_target(section_magic ALL DEPENDS ${object_target_list}) - diff --git a/stdlib/public/runtime/Errors.cpp b/stdlib/public/runtime/Errors.cpp index c3dff83d1858a..6e1beb92422d9 100644 --- a/stdlib/public/runtime/Errors.cpp +++ b/stdlib/public/runtime/Errors.cpp @@ -24,7 +24,9 @@ #include "swift/Runtime/Debug.h" #include "swift/Basic/Demangle.h" #include -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && !defined(__ANDROID__) +// execinfo.h is not available on Android. Checks in this file ensure that +// fatalError behaves as expected, but without stack traces. #include #endif @@ -38,7 +40,7 @@ enum: uint32_t { }; } // end namespace FatalErrorFlags -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && !defined(__ANDROID__) LLVM_ATTRIBUTE_ALWAYS_INLINE static bool isIdentifier(char c) @@ -205,7 +207,7 @@ reportNow(uint32_t flags, const char *message) #ifdef __APPLE__ asl_log(NULL, NULL, ASL_LEVEL_ERR, "%s", message); #endif -#if !defined(__CYGWIN__) +#if !defined(__CYGWIN__) && !defined(__ANDROID__) if (flags & FatalErrorFlags::ReportBacktrace) { fputs("Current stack trace:\n", stderr); int count = 0; diff --git a/stdlib/public/runtime/MetadataLookup.cpp b/stdlib/public/runtime/MetadataLookup.cpp index 3c1f610cfc84a..7ebcc3d96ffca 100644 --- a/stdlib/public/runtime/MetadataLookup.cpp +++ b/stdlib/public/runtime/MetadataLookup.cpp @@ -29,7 +29,7 @@ #if defined(__APPLE__) && defined(__MACH__) #include #include -#elif defined(__ELF__) +#elif defined(__ELF__) || defined(__ANDROID__) #include #include #endif diff --git a/stdlib/public/runtime/ProtocolConformance.cpp b/stdlib/public/runtime/ProtocolConformance.cpp index f58ee75eb16d9..0bb0a98d6b637 100644 --- a/stdlib/public/runtime/ProtocolConformance.cpp +++ b/stdlib/public/runtime/ProtocolConformance.cpp @@ -24,7 +24,7 @@ #if defined(__APPLE__) && defined(__MACH__) #include #include -#elif defined(__ELF__) +#elif defined(__ELF__) || defined(__ANDROID__) #include #include #endif @@ -349,7 +349,7 @@ static void _initializeCallbacksToInspectDylib() { _dyld_register_func_for_add_image(_addImageProtocolConformances); } -#elif defined(__ELF__) +#elif defined(__ELF__) || defined(__ANDROID__) static int _addImageProtocolConformances(struct dl_phdr_info *info, size_t size, void *data) { // inspectArgs contains addImage*Block function and the section name @@ -360,6 +360,12 @@ static int _addImageProtocolConformances(struct dl_phdr_info *info, handle = dlopen(nullptr, RTLD_LAZY); } else handle = dlopen(info->dlpi_name, RTLD_LAZY | RTLD_NOLOAD); + + if (!handle) { + // Not a shared library. + return 0; + } + auto conformances = reinterpret_cast( dlsym(handle, inspectArgs->sectionName)); diff --git a/stdlib/public/stubs/LibcShims.cpp b/stdlib/public/stubs/LibcShims.cpp index 1eee2eb20334a..cb750f11235a9 100644 --- a/stdlib/public/stubs/LibcShims.cpp +++ b/stdlib/public/stubs/LibcShims.cpp @@ -19,7 +19,7 @@ #include "../SwiftShims/LibcShims.h" static_assert(std::is_same::value, - "__swift_ssize_t is wrong"); + "__swift_ssize_t must be defined as equivalent to ssize_t"); namespace swift { @@ -62,6 +62,13 @@ size_t _swift_stdlib_malloc_size(const void *ptr) { size_t _swift_stdlib_malloc_size(const void *ptr) { return malloc_usable_size(const_cast(ptr)); } +#elif defined(__ANDROID__) +extern "C" { +extern size_t dlmalloc_usable_size(void*); +} +size_t _swift_stdlib_malloc_size(const void *ptr) { + return dlmalloc_usable_size(const_cast(ptr)); +} #else #error No malloc_size analog known for this platform/libc. #endif diff --git a/stdlib/public/stubs/Stubs.cpp b/stdlib/public/stubs/Stubs.cpp index 0f9d46766fd26..0ac5dabc67b3e 100644 --- a/stdlib/public/stubs/Stubs.cpp +++ b/stdlib/public/stubs/Stubs.cpp @@ -33,6 +33,26 @@ #include #include #define fmodl(lhs, rhs) std::fmod(lhs, rhs) +#elif defined(__ANDROID__) +// Android's libc implementation Bionic currently only supports the "C" locale +// (https://android.googlesource.com/platform/bionic/+/ndk-r11c/libc/bionic/locale.cpp#40). +// As such, we have no choice but to map functions like strtod_l, which should +// respect the given locale_t parameter, to functions like strtod, which do not. +#include +static double swift_strtod_l(const char *nptr, char **endptr, locale_t loc) { + return strtod(nptr, endptr); +} +static float swift_strtof_l(const char *nptr, char **endptr, locale_t loc) { + return strtof(nptr, endptr); +} +static long double swift_strtold_l(const char *nptr, + char **endptr, + locale_t loc) { + return strtod(nptr, endptr); +} +#define strtod_l swift_strtod_l +#define strtof_l swift_strtof_l +#define strtold_l swift_strtold_l #else #include #endif @@ -106,7 +126,7 @@ extern "C" uint64_t swift_uint64ToString(char *Buffer, intptr_t BufferLength, /*Negative=*/false); } -#if defined(__APPLE__) || defined(__FreeBSD__) +#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__ANDROID__) static inline locale_t getCLocale() { // On these platforms convenience functions from xlocale.h interpret nullptr // as C locale. @@ -260,7 +280,8 @@ extern "C" long double _swift_fmodl(long double lhs, long double rhs) { // FIXME: rdar://14883575 Libcompiler_rt omits muloti4 #if (defined(__linux__) && defined(__x86_64__)) || \ (defined(__linux__) && defined(__aarch64__)) || \ - (defined(__linux__) && defined(__powerpc64__)) + (defined(__linux__) && defined(__powerpc64__)) || \ + (defined(__ANDROID__) && defined(__arm64__)) typedef int ti_int __attribute__ ((mode (TI))); SWIFT_RUNTIME_STDLIB_INTERFACE diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 04b8b9bdf9049..4477d146be5ef 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -58,7 +58,8 @@ function(get_test_dependencies SDK result_var_name) ("${SDK}" STREQUAL "WATCHOS_SIMULATOR") OR ("${SDK}" STREQUAL "LINUX") OR ("${SDK}" STREQUAL "CYGWIN") OR - ("${SDK}" STREQUAL "FREEBSD")) + ("${SDK}" STREQUAL "FREEBSD") OR + ("${SDK}" STREQUAL "ANDROID")) # No extra dependencies. else() message(FATAL_ERROR "Unknown SDK: ${SDK}") diff --git a/test/Driver/linker.swift b/test/Driver/linker.swift index ab96ea0e2fab0..acd697f294dd0 100644 --- a/test/Driver/linker.swift +++ b/test/Driver/linker.swift @@ -23,6 +23,13 @@ // RUN: %swiftc_driver -driver-print-jobs -target thumbv7-unknown-linux-gnueabihf -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.linux.txt // RUN: FileCheck -check-prefix LINUX-thumbv7 %s < %t.linux.txt +// RUN: %swiftc_driver -driver-print-jobs -target armv7-none-linux-androideabi -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.android.txt +// RUN: FileCheck -check-prefix ANDROID-armv7 %s < %t.android.txt +// RUN: FileCheck -check-prefix ANDROID-armv7-NEGATIVE %s < %t.android.txt + +// RUN: %swiftc_driver -driver-print-jobs -target x86_64-unknown-windows-cygnus -Ffoo -framework bar -Lbaz -lboo -Xlinker -undefined %s 2>&1 > %t.cygwin.txt +// RUN: FileCheck -check-prefix CYGWIN-x86_64 %s < %t.cygwin.txt + // RUN: %swiftc_driver -driver-print-jobs -emit-library -target x86_64-apple-macosx10.9.1 %s -sdk %S/../Inputs/clang-importer-sdk -lfoo -framework bar -Lbaz -Fgarply -Xlinker -undefined -Xlinker dynamic_lookup -o sdk.out 2>&1 > %t.complex.txt // RUN: FileCheck %s < %t.complex.txt // RUN: FileCheck -check-prefix COMPLEX %s < %t.complex.txt @@ -125,7 +132,7 @@ // LINUX-armv6-DAG: [[OBJECTFILE]] // LINUX-armv6-DAG: -lswiftCore // LINUX-armv6-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] -// LINUX-armv6-DAG: --target=armv6-unknown-linux-gnueabihf +// LINUX-armv6-DAG: -target armv6-unknown-linux-gnueabihf // LINUX-armv6-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] // LINUX-armv6-DAG: -F foo // LINUX-armv6-DAG: -framework bar @@ -141,7 +148,7 @@ // LINUX-armv7-DAG: [[OBJECTFILE]] // LINUX-armv7-DAG: -lswiftCore // LINUX-armv7-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] -// LINUX-armv7-DAG: --target=armv7-unknown-linux-gnueabihf +// LINUX-armv7-DAG: -target armv7-unknown-linux-gnueabihf // LINUX-armv7-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] // LINUX-armv7-DAG: -F foo // LINUX-armv7-DAG: -framework bar @@ -157,7 +164,7 @@ // LINUX-thumbv7-DAG: [[OBJECTFILE]] // LINUX-thumbv7-DAG: -lswiftCore // LINUX-thumbv7-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] -// LINUX-thumbv7-DAG: --target=thumbv7-unknown-linux-gnueabihf +// LINUX-thumbv7-DAG: -target thumbv7-unknown-linux-gnueabihf // LINUX-thumbv7-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] // LINUX-thumbv7-DAG: -F foo // LINUX-thumbv7-DAG: -framework bar @@ -166,6 +173,37 @@ // LINUX-thumbv7-DAG: -Xlinker -undefined // LINUX-thumbv7: -o linker +// ANDROID-armv7: swift +// ANDROID-armv7: -o [[OBJECTFILE:.*]] + +// ANDROID-armv7: clang++{{"? }} +// ANDROID-armv7-DAG: [[OBJECTFILE]] +// ANDROID-armv7-DAG: -lswiftCore +// ANDROID-armv7-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] +// ANDROID-armv7-DAG: -target armv7-none-linux-androideabi +// ANDROID-armv7-DAG: -F foo +// ANDROID-armv7-DAG: -framework bar +// ANDROID-armv7-DAG: -L baz +// ANDROID-armv7-DAG: -lboo +// ANDROID-armv7-DAG: -Xlinker -undefined +// ANDROID-armv7: -o linker +// ANDROID-armv7-NEGATIVE-NOT: -Xlinker -rpath + +// CYGWIN-x86_64: swift +// CYGWIN-x86_64: -o [[OBJECTFILE:.*]] + +// CYGWIN-x86_64: clang++{{"? }} +// CYGWIN-x86_64-DAG: [[OBJECTFILE]] +// CYGWIN-x86_64-DAG: -lswiftCore +// CYGWIN-x86_64-DAG: -L [[STDLIB_PATH:[^ ]+/lib/swift]] +// CYGWIN-x86_64-DAG: -Xlinker -rpath -Xlinker [[STDLIB_PATH]] +// CYGWIN-x86_64-DAG: -F foo +// CYGWIN-x86_64-DAG: -framework bar +// CYGWIN-x86_64-DAG: -L baz +// CYGWIN-x86_64-DAG: -lboo +// CYGWIN-x86_64-DAG: -Xlinker -undefined +// CYGWIN-x86_64: -o linker + // COMPLEX: bin/ld{{"? }} // COMPLEX-DAG: -dylib // COMPLEX-DAG: -syslibroot {{.*}}/Inputs/clang-importer-sdk diff --git a/test/Parse/ConditionalCompilation/armAndroidTarget.swift b/test/Parse/ConditionalCompilation/armAndroidTarget.swift new file mode 100644 index 0000000000000..de4bcb4032946 --- /dev/null +++ b/test/Parse/ConditionalCompilation/armAndroidTarget.swift @@ -0,0 +1,14 @@ +// RUN: %swift -parse %s -verify -D FOO -D BAR -target armv7-none-linux-androideabi -disable-objc-interop -D FOO -parse-stdlib +// RUN: %swift-ide-test -test-input-complete -source-filename=%s -target armv7-none-linux-androideabi + +#if os(Linux) +// This block should not parse. +// os(Android) does not imply os(Linux). +let i: Int = "Hello" +#endif + +#if arch(arm) && os(Android) && _runtime(_Native) +class C {} +var x = C() +#endif +var y = x diff --git a/utils/build-script b/utils/build-script index f1e039f3dd8b8..6cdb9743d1b7a 100755 --- a/utils/build-script +++ b/utils/build-script @@ -646,6 +646,11 @@ also build for tvOS, but disallow tests that require a tvos device""", also build for watchOS, but disallow tests that require an watchOS device""", action="store_true") + parser.add_argument( + "--android", + help="also build for Android", + action="store_true") + parser.add_argument( "--swift-analyze-code-coverage", help="""enable code coverage analysis in Swift (false, not-merged, @@ -700,6 +705,41 @@ the number of parallel build jobs to use""", a '\'"""), action="append", dest="extra_swift_args", default=[]) + android_group = parser.add_argument_group( + title="Build settings for Android") + android_group.add_argument( + "--android-ndk", + help="An absolute path to the NDK that will be used as a libc " + "implementation for Android builds", + metavar="PATH") + android_group.add_argument( + "--android-ndk-version", + help="A version of the NDK to use when building for Android. " + "Currently only 21 or above is supported", + default="21") + android_group.add_argument( + "--android-ndk-toolchain-version", + help="A version of the toolchain to use when building for Android. " + "Use 4.8 for 32-bit builds, 4.9 for 64-bit builds", + choices=["4.8", "4.9"], + default="4.8") + android_group.add_argument( + "--android-icu-uc", + help="Path to a directory containing libicuuc.so", + metavar="PATH") + android_group.add_argument( + "--android-icu-uc-include", + help="Path to a directory containing headers for libicuuc", + metavar="PATH") + android_group.add_argument( + "--android-icu-i18n", + help="Path to a directory containing libicui18n.so", + metavar="PATH") + android_group.add_argument( + "--android-icu-i18n-include", + help="Path to a directory containing headers libicui18n", + metavar="PATH") + parser.add_argument( "--extra-cmake-options", help=textwrap.dedent(""" Pass through extra options to CMake in the form of comma separated options @@ -748,6 +788,20 @@ the number of parallel build jobs to use""", "--symbols-package.") return 1 + if args.android: + if args.android_ndk is None or \ + args.android_ndk_version is None or \ + args.android_icu_uc is None or \ + args.android_icu_uc_include is None or \ + args.android_icu_i18n is None or \ + args.android_icu_i18n_include is None: + print_with_argv0("When building for Android, --android-ndk, " + "--android-ndk-version, --android-icu-uc, " + "--android-icu-uc-include, --android-icu-i18n, " + "and --android-icu-i18n-include must be " + "specified.") + return 1 + # Build cmark if any cmark-related options were specified. if (args.cmark_build_variant is not None): args.build_cmark = True @@ -903,6 +957,11 @@ the number of parallel build jobs to use""", "--skip-test-watchos-host", ] + if not args.android: + build_script_impl_inferred_args += [ + "--skip-build-android", + ] + if not args.build_lldb: build_script_impl_inferred_args += [ "--skip-build-lldb" @@ -956,6 +1015,7 @@ the number of parallel build jobs to use""", "--skip-build-watchos", "--skip-build-watchos-device", "--skip-build-watchos-simulator", + "--skip-build-android", "--skip-build-lldb", "--skip-build-llbuild", "--skip-build-swiftpm", @@ -1080,6 +1140,16 @@ the number of parallel build jobs to use""", if args.cmake_generator == 'Ninja' and \ not swift_build_support.ninja.is_ninja_installed(): build_script_impl_args += ["--build-ninja"] + if args.android: + build_script_impl_args += [ + "--android-ndk", args.android_ndk, + "--android-ndk-version", args.android_ndk_version, + "--android-ndk-toolchain-version", args.android_ndk_toolchain_version, # noqa + "--android-icu-uc", args.android_icu_uc, + "--android-icu-uc-include", args.android_icu_uc_include, + "--android-icu-i18n", args.android_icu_i18n, + "--android-icu-i18n-include", args.android_icu_i18n_include, + ] if args.skip_build_linux: build_script_impl_args += ["--skip-build-linux"] if args.skip_build_freebsd: @@ -1106,6 +1176,18 @@ the number of parallel build jobs to use""", build_script_impl_args += ["--skip-test-watchos-simulator"] if args.build_runtime_with_host_compiler: build_script_impl_args += ["--build-runtime-with-host-compiler"] + + if args.android: + build_script_impl_args += [ + "--android-ndk", args.android_ndk, + "--android-ndk-version", args.android_ndk_version, + "--android-ndk-toolchain-version", args.android_ndk_toolchain_version, + "--android-icu-uc", args.android_icu_uc, + "--android-icu-uc-include", args.android_icu_uc_include, + "--android-icu-i18n", args.android_icu_i18n, + "--android-icu-i18n-include", args.android_icu_i18n_include, + ] + build_script_impl_args += build_script_impl_inferred_args # If we have extra_swift_args, combine all of them together and then add diff --git a/utils/build-script-impl b/utils/build-script-impl index 1951cd4f49238..3bbb231da22e1 100755 --- a/utils/build-script-impl +++ b/utils/build-script-impl @@ -122,6 +122,7 @@ KNOWN_SETTINGS=( skip-build-watchos "" "set to skip building Swift stdlibs for Apple watchOS" skip-build-watchos-device "" "set to skip building Swift stdlibs for Apple watchOS devices (i.e. build simulators only)" skip-build-watchos-simulator "" "set to skip building Swift stdlibs for Apple watchOS simulators (i.e. build devices only)" + skip-build-android "" "set to skip building Swift stdlibs for Android" skip-build-lldb "" "set to skip building LLDB" skip-build-llbuild "" "set to skip building llbuild" skip-build-swiftpm "" "set to skip building swiftpm" @@ -206,6 +207,13 @@ KNOWN_SETTINGS=( darwin-toolchain-installer-package "" "The path to installer pkg" build-jobs "" "The number of parallel build jobs to use" darwin-toolchain-alias "" "Swift alias for toolchain" + android-ndk "" "An absolute path to the NDK that will be used as a libc implementation for Android builds" + android-ndk-version "" "A version of the NDK to use when building for Android. Currently only 21 or above is supported" + android-ndk-toolchain-version "" "A version of the toolchain to use when building for Android. Use 4.8 for 32-bit builds, 4.9 for 64-bit builds" + android-icu-uc "" "Path to a directory containing libicuuc.so" + android-icu-uc-include "" "Path to a directory containing headers for libicuuc" + android-icu-i18n "" "Path to a directory containing libicui18n.so" + android-icu-i18n-include "" "Path to a directory containing headers libicui18n" export-compile-commands "" "set to generate JSON compilation databases for each build product" ) @@ -895,6 +903,7 @@ case "$(uname -s -m)" in Linux\ x86_64) STDLIB_DEPLOYMENT_TARGETS=( "linux-x86_64" + "android-armv7" ) ;; Linux\ armv6*) @@ -1112,6 +1121,12 @@ for deployment_target in "${STDLIB_DEPLOYMENT_TARGETS[@]}"; do build_for_this_target=$(not ${SKIP_BUILD_WATCHOS_SIMULATOR}) test_this_target=$(not ${SKIP_TEST_WATCHOS_SIMULATOR}) ;; + android-*) + build_for_this_target=$(not ${SKIP_BUILD_ANDROID}) + # FIXME: Allow Android host tests to be enabled/disabled by the + # build script. + test_this_target= + ;; *) echo "Unknown compiler deployment target: ${deployment_target}" exit 1 @@ -1370,6 +1385,9 @@ function common_cross_c_flags() { watchos-armv7k) echo "-arch armv7k -mwatchos-version-min=${DARWIN_DEPLOYMENT_VERSION_WATCHOS}" ;; + android-armv7) + echo "-arch armv7" + ;; esac } @@ -1714,6 +1732,19 @@ for deployment_target in "${HOST_TARGET}" "${CROSS_TOOLS_DEPLOYMENT_TARGETS[@]}" ) fi + if [[ ! "${SKIP_BUILD_ANDROID}" ]]; then + cmake_options=( + "${cmake_options[@]}" + -DSWIFT_ANDROID_NDK_PATH:STRING="${ANDROID_NDK}" + -DSWIFT_ANDROID_NDK_TOOLCHAIN_VERSION:STRING="${ANDROID_NDK_TOOLCHAIN_VERSION}" + -DSWIFT_ANDROID_SDK_PATH:STRING="${ANDROID_NDK}/platforms/android-${ANDROID_NDK_VERSION}/arch-arm" + -DSWIFT_ANDROID_ICU_UC:STRING="${ANDROID_ICU_UC}" + -DSWIFT_ANDROID_ICU_UC_INCLUDE:STRING="${ANDROID_ICU_UC_INCLUDE}" + -DSWIFT_ANDROID_ICU_I18N:STRING="${ANDROID_ICU_I18N}" + -DSWIFT_ANDROID_ICU_I18N_INCLUDE:STRING="${ANDROID_ICU_I18N_INCLUDE}" + ) + fi + native_llvm_tools_path="" native_clang_tools_path="" native_swift_tools_path="" @@ -2144,7 +2175,7 @@ for deployment_target in "${STDLIB_DEPLOYMENT_TARGETS[@]}"; do linux-* | freebsd-* | macosx-* | cygwin-*) # OK, we can run tests directly. ;; - iphoneos-* | iphonesimulator-* | appletvos-* | appletvsimulator-* | watchos-* | watchsimulator-*) + iphoneos-* | iphonesimulator-* | appletvos-* | appletvsimulator-* | watchos-* | watchsimulator-* | android-* ) # FIXME: remove this # echo "Don't know how to run tests for ${deployment_target}" continue diff --git a/validation-test/StdlibUnittest/Android.swift b/validation-test/StdlibUnittest/Android.swift new file mode 100644 index 0000000000000..025695293cd6a --- /dev/null +++ b/validation-test/StdlibUnittest/Android.swift @@ -0,0 +1,26 @@ +// RUN: %target-run-stdlib-swift | FileCheck %s +// REQUIRES: executable_test + +import Swift +import StdlibUnittest + + +_setOverrideOSVersion(.android) +_setTestSuiteFailedCallback() { print("abort()") } + +var XFailsAndroid = TestSuite("XFailsAndroid") + +// CHECK: [ UXPASS ] XFailsAndroid.xfail Android passes{{$}} +XFailsAndroid.test("xfail Android passes").xfail(.androidAny(reason: "")).code { + expectEqual(1, 1) +} + +// CHECK: [ XFAIL ] XFailsAndroid.xfail Android fails{{$}} +XFailsAndroid.test("xfail Android fails").xfail(.androidAny(reason: "")).code { + expectEqual(1, 2) +} + +// CHECK: XFailsAndroid: Some tests failed, aborting +// CHECK: abort() + +runAllTests()