Skip to content

Android: add native platform support #2396

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

Merged
merged 2 commits into from
Nov 8, 2019
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
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#if os(Linux)
#if canImport(Glibc)
import Glibc
#else
import Darwin.C
Expand Down
2 changes: 2 additions & 0 deletions Sources/Build/BuildPlan.swift
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,8 @@ public struct BuildParameters: Encodable {
var currentPlatform: PackageModel.Platform {
if self.triple.isDarwin() {
return .macOS
} else if self.triple.isAndroid() {
return .android
} else {
return .linux
}
Expand Down
19 changes: 18 additions & 1 deletion Sources/Build/Triple.swift
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ public struct Triple: Encodable {
return nil
}

public func isAndroid() -> Bool {
return os == .linux && abi == .android
}

public func isDarwin() -> Bool {
return vendor == .apple || os == .macOS || os == .darwin
}
Expand Down Expand Up @@ -128,7 +132,10 @@ public struct Triple: Encodable {
public static let s390xLinux = try! Triple("s390x-unknown-linux")
public static let arm64Linux = try! Triple("aarch64-unknown-linux")
public static let armLinux = try! Triple("armv7-unknown-linux-gnueabihf")
public static let android = try! Triple("armv7-unknown-linux-androideabi")
public static let armAndroid = try! Triple("armv7a-unknown-linux-androideabi")
public static let arm64Android = try! Triple("aarch64-unknown-linux-android")
public static let x86_64Android = try! Triple("x86_64-unknown-linux-android")
public static let i686Android = try! Triple("i686-unknown-linux-android")
public static let windows = try! Triple("x86_64-unknown-windows-msvc")

#if os(macOS)
Expand All @@ -149,6 +156,16 @@ public struct Triple: Encodable {
#elseif arch(arm)
public static let hostTriple: Triple = .armLinux
#endif
#elseif os(Android)
#if arch(arm)
public static let hostTriple: Triple = .armAndroid
#elseif arch(arm64)
public static let hostTriple: Triple = .arm64Android
#elseif arch(x86_64)
public static let hostTriple: Triple = .x86_64Android
#elseif arch(i386)
public static let hostTriple: Triple = .i686Android
#endif
#endif
}

Expand Down
6 changes: 6 additions & 0 deletions Sources/Commands/SwiftTool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,12 @@ public class SwiftTool<Options: ToolOptions> {
action.__sigaction_u.__sa_handler = SIG_DFL
sigaction(SIGINT, &action, nil)
kill(getpid(), SIGINT)
#elseif os(Android)
// Install the default signal handler.
var action = sigaction()
action.sa_handler = SIG_DFL
sigaction(SIGINT, &action, nil)
kill(getpid(), SIGINT)
#else
var action = sigaction()
action.__sigaction_handler = unsafeBitCast(
Expand Down
2 changes: 1 addition & 1 deletion Sources/PackageDescription4/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

#if os(Linux)
#if canImport(Glibc)
import Glibc
#elseif os(iOS) || os(macOS) || os(tvOS) || os(watchOS)
import Darwin.C
Expand Down
4 changes: 4 additions & 0 deletions Sources/PackageDescription4/SupportedPlatforms.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ public struct Platform: Encodable {
/// The Windows platform
@available(_PackageDescription, introduced: 5.2)
public static let windows: Platform = Platform(name: "windows")

/// The Android platform
@available(_PackageDescription, introduced: 5.2)
public static let android: Platform = Platform(name: "android")
}

/// A platform that the Swift package supports.
Expand Down
3 changes: 2 additions & 1 deletion Sources/PackageModel/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public final class PlatformRegistry {

/// The static list of known platforms.
private static var _knownPlatforms: [Platform] {
return [.macOS, .iOS, .tvOS, .watchOS, .linux]
return [.macOS, .iOS, .tvOS, .watchOS, .linux, .android]
}
}

Expand All @@ -55,6 +55,7 @@ public struct Platform: Equatable, Hashable {
public static let tvOS: Platform = Platform(name: "tvos", oldestSupportedVersion: "9.0")
public static let watchOS: Platform = Platform(name: "watchos", oldestSupportedVersion: "2.0")
public static let linux: Platform = Platform(name: "linux", oldestSupportedVersion: .unknown)
public static let android: Platform = Platform(name: "android", oldestSupportedVersion: .unknown)
}

/// Represents a platform version.
Expand Down
4 changes: 2 additions & 2 deletions Sources/TSCBasic/Process.swift
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ public final class Process: ObjectIdentifierProtocol {
try _process?.run()
#else
// Initialize the spawn attributes.
#if canImport(Darwin)
#if canImport(Darwin) || os(Android)
var attributes: posix_spawnattr_t? = nil
#else
var attributes = posix_spawnattr_t()
Expand Down Expand Up @@ -357,7 +357,7 @@ public final class Process: ObjectIdentifierProtocol {
posix_spawnattr_setflags(&attributes, Int16(flags))

// Setup the file actions.
#if canImport(Darwin)
#if canImport(Darwin) || os(Android)
var fileActions: posix_spawn_file_actions_t? = nil
#else
var fileActions = posix_spawn_file_actions_t()
Expand Down
2 changes: 1 addition & 1 deletion Sources/TSCLibc/libc.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
See http://swift.org/CONTRIBUTORS.txt for Swift project authors
*/

#if os(Linux)
#if canImport(Glibc)
@_exported import Glibc
#elseif os(Windows)
@_exported import MSVCRT
Expand Down
85 changes: 53 additions & 32 deletions Sources/TSCUtility/FSWatch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -428,55 +428,76 @@ public final class Inotify {
// FIXME: <rdar://problem/45794219> Swift should provide shims for FD_ macros

private func FD_ZERO(_ set: inout fd_set) {
#if os(Android)
set.fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#else
set.__fds_bits = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
#endif
}

private func FD_SET(_ fd: Int32, _ set: inout fd_set) {
let intOffset = Int(fd / 16)
let bitOffset = Int(fd % 16)
#if os(Android)
var fd_bits = set.fds_bits
let mask: UInt = 1 << bitOffset
#else
var fd_bits = set.__fds_bits
let mask = 1 << bitOffset
#endif
switch intOffset {
case 0: set.__fds_bits.0 = set.__fds_bits.0 | mask
case 1: set.__fds_bits.1 = set.__fds_bits.1 | mask
case 2: set.__fds_bits.2 = set.__fds_bits.2 | mask
case 3: set.__fds_bits.3 = set.__fds_bits.3 | mask
case 4: set.__fds_bits.4 = set.__fds_bits.4 | mask
case 5: set.__fds_bits.5 = set.__fds_bits.5 | mask
case 6: set.__fds_bits.6 = set.__fds_bits.6 | mask
case 7: set.__fds_bits.7 = set.__fds_bits.7 | mask
case 8: set.__fds_bits.8 = set.__fds_bits.8 | mask
case 9: set.__fds_bits.9 = set.__fds_bits.9 | mask
case 10: set.__fds_bits.10 = set.__fds_bits.10 | mask
case 11: set.__fds_bits.11 = set.__fds_bits.11 | mask
case 12: set.__fds_bits.12 = set.__fds_bits.12 | mask
case 13: set.__fds_bits.13 = set.__fds_bits.13 | mask
case 14: set.__fds_bits.14 = set.__fds_bits.14 | mask
case 15: set.__fds_bits.15 = set.__fds_bits.15 | mask
case 0: fd_bits.0 = fd_bits.0 | mask
case 1: fd_bits.1 = fd_bits.1 | mask
case 2: fd_bits.2 = fd_bits.2 | mask
case 3: fd_bits.3 = fd_bits.3 | mask
case 4: fd_bits.4 = fd_bits.4 | mask
case 5: fd_bits.5 = fd_bits.5 | mask
case 6: fd_bits.6 = fd_bits.6 | mask
case 7: fd_bits.7 = fd_bits.7 | mask
case 8: fd_bits.8 = fd_bits.8 | mask
case 9: fd_bits.9 = fd_bits.9 | mask
case 10: fd_bits.10 = fd_bits.10 | mask
case 11: fd_bits.11 = fd_bits.11 | mask
case 12: fd_bits.12 = fd_bits.12 | mask
case 13: fd_bits.13 = fd_bits.13 | mask
case 14: fd_bits.14 = fd_bits.14 | mask
case 15: fd_bits.15 = fd_bits.15 | mask
default: break
}
#if os(Android)
set.fds_bits = fd_bits
#else
set.__fds_bits = fd_bits
#endif
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'd be nice if I could assign some kind of compile-time symbol reference to each platform's variable name, so that this runtime copying isn't needed.

}

private func FD_ISSET(_ fd: Int32, _ set: inout fd_set) -> Bool {
let intOffset = Int(fd / 32)
let bitOffset = Int(fd % 32)
#if os(Android)
let fd_bits = set.fds_bits
let mask: UInt = 1 << bitOffset
#else
let fd_bits = set.__fds_bits
let mask = 1 << bitOffset
#endif
switch intOffset {
case 0: return set.__fds_bits.0 & mask != 0
case 1: return set.__fds_bits.1 & mask != 0
case 2: return set.__fds_bits.2 & mask != 0
case 3: return set.__fds_bits.3 & mask != 0
case 4: return set.__fds_bits.4 & mask != 0
case 5: return set.__fds_bits.5 & mask != 0
case 6: return set.__fds_bits.6 & mask != 0
case 7: return set.__fds_bits.7 & mask != 0
case 8: return set.__fds_bits.8 & mask != 0
case 9: return set.__fds_bits.9 & mask != 0
case 10: return set.__fds_bits.10 & mask != 0
case 11: return set.__fds_bits.11 & mask != 0
case 12: return set.__fds_bits.12 & mask != 0
case 13: return set.__fds_bits.13 & mask != 0
case 14: return set.__fds_bits.14 & mask != 0
case 15: return set.__fds_bits.15 & mask != 0
case 0: return fd_bits.0 & mask != 0
case 1: return fd_bits.1 & mask != 0
case 2: return fd_bits.2 & mask != 0
case 3: return fd_bits.3 & mask != 0
case 4: return fd_bits.4 & mask != 0
case 5: return fd_bits.5 & mask != 0
case 6: return fd_bits.6 & mask != 0
case 7: return fd_bits.7 & mask != 0
case 8: return fd_bits.8 & mask != 0
case 9: return fd_bits.9 & mask != 0
case 10: return fd_bits.10 & mask != 0
case 11: return fd_bits.11 & mask != 0
case 12: return fd_bits.12 & mask != 0
case 13: return fd_bits.13 & mask != 0
case 14: return fd_bits.14 & mask != 0
case 15: return fd_bits.15 & mask != 0
default: return false
}
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/TSCUtility/IndexStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,8 @@ public final class IndexStoreAPI {
self.path = path
#if os(Windows)
let flags: DLOpenFlags = []
#elseif os(Android)
let flags: DLOpenFlags = [.lazy, .local, .first]
#else
let flags: DLOpenFlags = [.lazy, .local, .first, .deepBind]
#endif
Expand Down
2 changes: 2 additions & 0 deletions Sources/TSCUtility/InterruptHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ public final class InterruptHandler {
var action = sigaction()
#if canImport(Darwin)
action.__sigaction_u.__sa_handler = signalHandler
#elseif os(Android)
action.sa_handler = signalHandler
#else
action.__sigaction_handler = unsafeBitCast(
signalHandler,
Expand Down
5 changes: 5 additions & 0 deletions Sources/TSCUtility/Platform.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import Foundation

/// Recognized Platform types.
public enum Platform {
case android
case darwin
case linux(LinuxFlavor)

Expand All @@ -33,6 +34,10 @@ public enum Platform {
if localFileSystem.isFile(AbsolutePath("/etc/debian_version")) {
return .linux(.debian)
}
if localFileSystem.isFile(AbsolutePath("/system/bin/toolbox")) ||
localFileSystem.isFile(AbsolutePath("/system/bin/toybox")) {
return .android
}
Copy link
Member Author

Choose a reason for hiding this comment

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

This function doesn't seem to be called anywhere, can remove if not needed.

Copy link
Contributor

Choose a reason for hiding this comment

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

yah let's remove it if it's dead code.

Copy link
Member Author

Choose a reason for hiding this comment

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

I was wrong, the variable it's used to initialize, currentPlatform, is used in exactly one place. I suppose this might be useful for TSCUtility and llbuild someday too, for which I've created a Termux package, so I'd like to keep this Android support.

Copy link
Contributor

Choose a reason for hiding this comment

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

Any reason you chose these particular files vs /system/build.prop?

Copy link
Member Author

Choose a reason for hiding this comment

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

No other reason that I'm familiar with toolbox/toybox, as they're sometimes invoked from the Termux command-line, and not build.prop, which is unreadable without root on my device. If there's a better file that signifies Android, glad to use that instead, just let me know.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, that's fine for now, we can always update the check later if we need to.

Thanks for your contribution!

default:
return nil
}
Expand Down
2 changes: 2 additions & 0 deletions Sources/TSCUtility/dlopen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,10 @@ public struct DLOpenFlags: RawRepresentable, OptionSet {
public static let deepBind: DLOpenFlags = DLOpenFlags(rawValue: 0)
#else
public static let first: DLOpenFlags = DLOpenFlags(rawValue: 0)
#if !os(Android)
public static let deepBind: DLOpenFlags = DLOpenFlags(rawValue: RTLD_DEEPBIND)
Copy link
Member Author

Choose a reason for hiding this comment

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

No RTLD_DEEPBIND on Android, so #ifdef it out here and above.

#endif
#endif
#endif

public var rawValue: Int32
Expand Down
2 changes: 1 addition & 1 deletion Tests/FunctionalTests/MiscellaneousTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ class MiscellaneousTestCase: XCTestCase {
}

func testUnicode() {
#if !os(Linux) // TODO: - Linux has trouble with this and needs investigation.
#if !os(Linux) && !os(Android) // TODO: - Linux has trouble with this and needs investigation.
fixture(name: "Miscellaneous/Unicode") { prefix in
// See the fixture manifest for an explanation of this string.
let complicatedString = "πשּׁµ𝄞🇺🇳🇮🇱x̱̱̱̱̱̄̄̄̄̄"
Expand Down
2 changes: 1 addition & 1 deletion Tests/FunctionalTests/ModuleMapTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ModuleMapsTestCase: XCTestCase {
try systemQuietly(["clang", "-shared", input.pathString, "-o", output.pathString])

var Xld = ["-L", outdir.pathString]
#if os(Linux)
#if os(Linux) || os(Android)
Xld += ["-rpath", outdir.pathString]
#endif

Expand Down
2 changes: 2 additions & 0 deletions Tests/PackageLoadingTests/PackageBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,7 @@ class PackageBuilderTests: XCTestCase {
"ios": "8.0",
"tvos": "9.0",
"watchos": "2.0",
"android": "0.0",
]

PackageBuilderTester(manifest, in: fs) { result in
Expand Down Expand Up @@ -1411,6 +1412,7 @@ class PackageBuilderTests: XCTestCase {
"linux": "0.0",
"ios": "8.0",
"watchos": "2.0",
"android": "0.0",
]

PackageBuilderTester(manifest, in: fs) { result in
Expand Down
2 changes: 1 addition & 1 deletion Tests/TSCBasicTests/FileSystemTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -391,7 +391,7 @@ class FileSystemTests: XCTestCase {
}

func testSetAttribute() throws {
#if os(macOS) || os(Linux)
#if os(macOS) || os(Linux) || os(Android)
mktmpdir { path in
let fs = TSCBasic.localFileSystem

Expand Down