diff --git a/.gitignore b/.gitignore
index 5e5d5ce..329e500 100644
--- a/.gitignore
+++ b/.gitignore
@@ -61,3 +61,5 @@ Carthage/Build
fastlane/report.xml
fastlane/screenshots
+.idea
+.DS_Store
diff --git a/Package.swift b/Package.swift
index e5912dc..f3098cd 100644
--- a/Package.swift
+++ b/Package.swift
@@ -19,23 +19,28 @@
import PackageDescription
-#if os(Linux) || os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
+#if os(Linux) || os(macOS) || os(iOS) || os(tvOS) || os(watchOS) || os(Android)
let package = Package(
- name: "Signals",
- products: [
- // Products define the executables and libraries produced by a package, and make them visible to other packages.
- .library(
- name: "Signals",
- targets: ["Signals"]
- )
- ],
- targets: [
- .target(
- name: "Signals",
- exclude: ["Signals.xcodeproj", "README.md", "Sources/Info.plist", "Sources/Signals.h", "Tests"]
- ),
- ]
+ name: "Signals",
+ products: [
+ // Products define the executables and libraries produced by a package, and make them visible to other packages.
+ .library(
+ name: "Signals",
+ type: .dynamic,
+ targets: ["Signals"]
+ )
+ ],
+ targets: [
+ .target(
+ name: "Signals",
+ exclude: ["Signals.xcodeproj", "README.md", "Sources/Info.plist", "Sources/Signals.h", "Tests"]
+ ),
+ .target(
+ name: "Example",
+ dependencies: ["Signals"]
+ ),
+ ]
)
#else
diff --git a/Package@swift-4.swift b/Package@swift-4.swift
index 63f2167..6b06845 100644
--- a/Package@swift-4.swift
+++ b/Package@swift-4.swift
@@ -22,20 +22,25 @@ import PackageDescription
#if os(Linux) || os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
let package = Package(
- name: "Signals",
- products: [
- // Products define the executables and libraries produced by a package, and make them visible to other packages.
- .library(
- name: "Signals",
- targets: ["Signals"]
- )
- ],
- targets: [
- .target(
- name: "Signals",
- exclude: ["Signals.xcodeproj", "README.md", "Sources/Info.plist", "Sources/Signals.h", "Tests"]
- ),
- ]
+ name: "Signals",
+ products: [
+ // Products define the executables and libraries produced by a package, and make them visible to other packages.
+ .library(
+ name: "Signals",
+ type: .dynamic,
+ targets: ["Signals"]
+ )
+ ],
+ targets: [
+ .target(
+ name: "Signals",
+ exclude: ["Signals.xcodeproj", "README.md", "Sources/Info.plist", "Sources/Signals.h", "Tests"]
+ ),
+ .target(
+ name: "Example",
+ dependencies: ["Signals"]
+ ),
+ ]
)
#else
diff --git a/README.md b/README.md
index 1835f9b..8d0d785 100644
--- a/README.md
+++ b/README.md
@@ -5,9 +5,10 @@
-
-
+
+
+
@@ -45,16 +46,64 @@ BlueSignals version 2.0 and above supports Swift 5.1+. See older versions of Bl
* Ubuntu 16.04 (or 16.10 but only tested on 16.04) and 18.04.
* One of the Swift Open Source toolchain listed above.
+### Android
+
+* macOS 10.15.7 (*Catalina*) or higher.
+* Xcode Version 12.4 (12D4e) or higher using the included toolchain (*Recommended*).
+* [Swift-android-toolchain-5.4.2-RELEASE](https://github.com/Guang1234567/swift_android_all_in_one/tree/swift_android_5.4.2_release) (**Recommended**)
+* Android sdk(latest) and ndk(21.4.7075529)
## Build
To build Signals from the command line:
+- other platform
```
% cd
% swift build
```
+- android
+
+```
+#!/usr/bin/env bash
+
+export ANDROID_HOME=$HOME/dev_kit/sdk/android_sdk
+export ANDROID_NDK_HOME=$ANDROID_HOME/ndk/21.4.7075529
+
+# clone from https://github.com/Guang1234567/swift_android_all_in_one/tree/swift_android_5.4.2_release
+export SWIFT_ANDROID_HOME=$HOME/dev_kit/sdk/swift-android-5.4.2-release-ndk21
+
+export SWIFT_ANDROID_ARCH=aarch64
+#export SWIFT_ANDROID_ARCH=armv7
+#export SWIFT_ANDROID_ARCH=x86_64
+#export SWIFT_ANDROID_ARCH=x86
+export SWIFT_ANDROID_API=23
+
+cd Swift_Signals
+
+echo -e "Running on macOS:\n=======================================\n"
+swift run Example
+
+echo -e "Running on androidOS:\n=======================================\n"
+
+${SWIFT_ANDROID_HOME}/build-tools/1.9.7-swift5.4/swift-build --configuration debug -Xswiftc -DDEBUG -Xswiftc -g
+
+echo -e "Copy ELF to real android device :\n"
+
+adb push .build/aarch64-unknown-linux-android/debug/Example /data/local/tmp
+
+echo -e "Copy swift runtime SO to real android device :\n"
+
+adb push ${SWIFT_ANDROID_HOME}/toolchain/usr/lib/swift/android/${SWIFT_ANDROID_ARCH}/*.so /data/local/tmp
+
+echo -e "Running on real android device :\n"
+
+adb shell LD_LIBRARY_PATH=/data/local/tmp /data/local/tmp/Example
+
+cd ..
+```
+
## Using Signals
### Including in your project
diff --git a/Sources/Example/main.swift b/Sources/Example/main.swift
new file mode 100644
index 0000000..31556f9
--- /dev/null
+++ b/Sources/Example/main.swift
@@ -0,0 +1,62 @@
+import Foundation
+import Signals
+
+let reason = CommandLine.arguments.count == 2 ? CommandLine.arguments[1] : "unknown"
+
+func A1() -> Void {
+ A2()
+}
+
+func A2() -> Void {
+ A3()
+}
+
+func A3() -> Void {
+ B1()
+}
+
+func B1() -> Void {
+ B2()
+}
+
+func B2() -> Void {
+ B3()
+}
+
+func B3() -> Void {
+ Van().drive()
+}
+
+class Van {
+ func drive() -> Void {
+
+ print("\n\n\n")
+ print("👇👇👇")
+ fatalError(reason) // raise SIGILL here !!!
+ print("👆👆👆")
+ print("\n\n\n")
+ }
+
+ func oilEmpty() throws -> Void {
+ throw CarError.oilEmpty(message: "!!! oil empty !!!")
+ }
+}
+
+enum CarError: Error {
+ case oilEmpty(message: String)
+}
+
+Signals.trap(signal: Signals.Signal.ill) { signal in
+
+ print("----> \(signal)")
+
+ if (signal == SIGILL) {
+ #if os(macOS)
+ exit(EXIT_FAILURE)
+ #endif
+ }
+}
+
+A1()
+
+
diff --git a/Sources/Signals/Signals.swift b/Sources/Signals/Signals.swift
index 5ba30e5..f0f9366 100644
--- a/Sources/Signals/Signals.swift
+++ b/Sources/Signals/Signals.swift
@@ -19,9 +19,9 @@
//
#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
- import Darwin
-#elseif os(Linux)
- import Glibc
+import Darwin
+#elseif os(Linux) || os(Android)
+import Glibc
#endif
import Foundation
@@ -29,172 +29,191 @@ import Foundation
// MARK: Signals
public class Signals {
-
- // MARK: Enums
-
- ///
- /// Common OS Signals
- ///
- public enum Signal {
- case hup
- case int
- case quit
- case abrt
- case kill
- case alrm
- case term
- case pipe
- case user(Int)
-
- ///
- /// Obtain the OS dependent value of a Signal
- ///
- public var valueOf: Int32 {
-
- switch self {
- case .hup:
- return Int32(SIGHUP)
- case .int:
- return Int32(SIGINT)
- case .quit:
- return Int32(SIGQUIT)
- case .abrt:
- return Int32(SIGABRT)
- case .kill:
- return Int32(SIGKILL)
- case .alrm:
- return Int32(SIGALRM)
- case .term:
- return Int32(SIGTERM)
- case .pipe:
- return Int32(SIGPIPE)
- case .user(let sig):
- return Int32(sig)
-
- }
- }
- }
-
-
- // MARK: Typealiases
-
- ///
- /// Action handler signature.
- ///
- public typealias SigActionHandler = @convention(c)(Int32) -> Void
-
-
- // MARK: Class Methods
-
- ///
- /// Trap an operating system signal.
- ///
- /// - Parameters:
- /// - signal: The signal to catch.
- /// - action: The action handler.
- ///
- public class func trap(signal: Signal, action: @escaping SigActionHandler) {
-
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
-
- var signalAction = sigaction(__sigaction_u: unsafeBitCast(action, to: __sigaction_u.self), sa_mask: 0, sa_flags: 0)
-
- _ = withUnsafePointer(to: &signalAction) { actionPointer in
-
- sigaction(signal.valueOf, actionPointer, nil)
- }
-
- #elseif os(Linux)
-
- var sigAction = sigaction()
-
- sigAction.__sigaction_handler = unsafeBitCast(action, to: sigaction.__Unnamed_union___sigaction_handler.self)
-
- _ = sigaction(signal.valueOf, &sigAction, nil)
-
- #endif
- }
-
- ///
- /// Trap multiple signals to individual handlers
- ///
- /// - Parameter signals: An array of tuples each containing a signal and signal handler.
- ///
- public class func trap(signals: [(signal: Signal, action: SigActionHandler)]) {
-
- for sighandler in signals {
-
- Signals.trap(signal: sighandler.signal, action: sighandler.action)
- }
- }
-
- ///
- /// Trap multiple signals to a single handler
- ///
- /// - Parameters:
- /// - signals: An array of signals to catch.
- /// - action: The action handler that will handle these signals.
- ///
- public class func trap(signals: [Signal], action: @escaping SigActionHandler) {
-
- for signal in signals {
-
- Signals.trap(signal: signal, action: action)
- }
- }
-
- ///
- /// Raise an operating system signal
- ///
- /// - Parameter signal: The signal to raise.
- ///
- public class func raise(signal: Signal) {
-
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
-
- _ = Darwin.raise(signal.valueOf)
-
- #elseif os(Linux)
-
- _ = Glibc.raise(signal.valueOf)
-
- #endif
- }
-
- ///
- /// Ignore a signal
- ///
- /// - Parameter signal: The signal to ignore.
- ///
- public class func ignore(signal: Signal) {
-
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
-
- _ = Darwin.signal(signal.valueOf, SIG_IGN)
-
- #elseif os(Linux)
-
- _ = Glibc.signal(signal.valueOf, SIG_IGN)
-
- #endif
- }
-
- ///
- /// Restore default signal handling
- ///
- /// - Parameter signal: The signal to restore.
- ///
- public class func restore(signal: Signal) {
-
- #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
-
- _ = Darwin.signal(signal.valueOf, SIG_DFL)
-
- #elseif os(Linux)
-
- _ = Glibc.signal(signal.valueOf, SIG_DFL)
-
- #endif
- }
-
+
+ // MARK: Enums
+
+ ///
+ /// Common OS Signals
+ ///
+ public enum Signal {
+ case hup
+ case int
+ case quit
+ case ill
+ case trap
+ case abrt
+ case kill
+ case pipe
+ case alrm
+ case term
+ case user(Int)
+
+ ///
+ /// Obtain the OS dependent value of a Signal
+ ///
+ public var valueOf: CInt {
+
+ switch self {
+ case .hup:
+ return CInt(SIGHUP)
+ case .int:
+ return CInt(SIGINT)
+ case .quit:
+ return CInt(SIGQUIT)
+ case .ill:
+ return CInt(SIGILL)
+ case .trap:
+ return CInt(SIGTRAP)
+ case .abrt:
+ return CInt(SIGABRT)
+ case .kill:
+ return CInt(SIGKILL)
+ case .pipe:
+ return CInt(SIGPIPE)
+ case .alrm:
+ return CInt(SIGALRM)
+ case .term:
+ return CInt(SIGTERM)
+ case .user(let sig):
+ return CInt(sig)
+
+ }
+ }
+ }
+
+
+ // MARK: Typealiases
+
+ ///
+ /// Action handler signature.
+ ///
+ public typealias SigActionHandler = @convention(c) (CInt) -> Void
+
+
+ // MARK: Class Methods
+
+ ///
+ /// Trap an operating system signal.
+ ///
+ /// - Parameters:
+ /// - signal: The signal to catch.
+ /// - action: The action handler.
+ ///
+ public class func trap(signal: Signal, mask: sigset_t = sigset_t(), flags: CInt = 0, action: @escaping SigActionHandler) {
+
+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
+
+ var signalAction = sigaction(
+ __sigaction_u: __sigaction_u(__sa_handler: action),
+ sa_mask: mask,
+ sa_flags: flags
+ )
+
+ #elseif os(Linux)
+
+ var signalAction = sigaction(
+ __sigaction_handler: unsafeBitCast(action, to: sigaction.__Unnamed_union___sigaction_handler.self),
+ sa_flags: flags,
+ sa_mask: mask,
+ sa_restorer: nil
+ )
+
+ #elseif os(Android)
+
+ var signalAction = sigaction(
+ sa_flags: flags,
+ .init(sa_handler: action),
+ sa_mask: mask,
+ sa_restorer: nil)
+
+ #endif
+
+ _ = withUnsafePointer(to: &signalAction) { actionPointer in
+
+ sigaction(signal.valueOf, actionPointer, nil)
+ }
+ }
+
+ ///
+ /// Trap multiple signals to individual handlers
+ ///
+ /// - Parameter signals: An array of tuples each containing a signal and signal handler.
+ ///
+ public class func trap(signals: [(signal: Signal, action: SigActionHandler, mask: sigset_t, flags: CInt)]) {
+
+ for item in signals {
+
+ Signals.trap(signal: item.signal, mask: item.mask, flags: item.flags, action: item.action)
+ }
+ }
+
+ ///
+ /// Trap multiple signals to a single handler
+ ///
+ /// - Parameters:
+ /// - signals: An array of signals to catch.
+ /// - action: The action handler that will handle these signals.
+ ///
+ public class func trap(signals: [Signal], mask: sigset_t = sigset_t(), flags: CInt = 0, action: @escaping SigActionHandler) {
+
+ for signal in signals {
+
+ Signals.trap(signal: signal, mask: mask, flags: flags, action: action)
+ }
+ }
+
+ ///
+ /// Raise an operating system signal
+ ///
+ /// - Parameter signal: The signal to raise.
+ ///
+ public class func raise(signal: Signal) {
+
+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
+
+ _ = Darwin.raise(signal.valueOf)
+
+ #elseif os(Linux) || os(Android)
+
+ _ = Glibc.raise(signal.valueOf)
+
+ #endif
+ }
+
+ ///
+ /// Ignore a signal
+ ///
+ /// - Parameter signal: The signal to ignore.
+ ///
+ public class func ignore(signal: Signal) {
+
+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
+
+ _ = Darwin.signal(signal.valueOf, SIG_IGN)
+
+ #elseif os(Linux) || os(Android)
+
+ _ = Glibc.signal(signal.valueOf, SIG_IGN)
+
+ #endif
+ }
+
+ ///
+ /// Restore default signal handling
+ ///
+ /// - Parameter signal: The signal to restore.
+ ///
+ public class func restore(signal: Signal) {
+
+ #if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
+
+ _ = Darwin.signal(signal.valueOf, SIG_DFL)
+
+ #elseif os(Linux) || os(Android)
+
+ _ = Glibc.signal(signal.valueOf, SIG_DFL)
+
+ #endif
+ }
+
}