Merge branch 'development' (SwiftPM & XCTest available)

This commit is contained in:
YOCKOW 2017-09-02 10:40:34 +09:00
commit aa82e622df
10 changed files with 209 additions and 416 deletions

2
.gitignore vendored
View File

@ -1,5 +1,7 @@
.DS_Store
.build/
build/
y-build/
*.xcodeproj/

View File

@ -15,10 +15,3 @@ NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPO
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES
OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
====================================================================================================
Includes swift-tap
https://github.com/dankogai/swift-tap
Copyright (c) 2016 Dan Kogai
Released under the MIT License.
- See "Sources/Test/TAP.swift"

8
Package.swift Normal file
View File

@ -0,0 +1,8 @@
// swift-tools-version:3.1
import PackageDescription
let package = Package(
name: "TimeSpecification",
swiftLanguageVersions:[3]
)

View File

@ -30,7 +30,7 @@ public enum Clock {
Build and install:
`./build-install.rb --install-prefix=/path/to/your/system --install`
Then, you can use it in your project:
`swiftc ./your/project/main.swift -I/path/to/your/system/include -L/path/to/your/system/lib`
`swiftc ./your/project/main.swift -I/path/to/your/system/include -L/path/to/your/system/lib -lSwiftTimeSpecification`
# Sample Code
```

View File

@ -1,149 +0,0 @@
// https://github.com/dankogai/swift-tap/blob/master/tap/tap.swift
//
// tap.swift
// tap
//
// Created by Dan Kogai on 1/21/16.
// Copyright © 2016 Dan Kogai. All rights reserved.
//
/*
The MIT License (MIT)
Copyright (c) 2016 Dan Kogai
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#if os(Linux)
import Glibc
#else
import Darwin
#endif
open class TAP {
var tests = 0, runs = [Bool]()
public init() {}
public init(tests:Int) {
self.plan(tests)
}
/// sets the number of tests to run. call it before the first test
open func plan(_ tests:Int) {
self.tests = tests
print("1..\(tests)")
}
/// ok if `predicate` is true
@discardableResult
open func ok(_ predicate:@autoclosure ()->Bool, _ message:String = "")->Bool {
let ok = predicate()
runs.append(ok)
let ornot = ok ? "" : "not "
print("\(ornot)ok \(runs.count) - \(message)")
return ok
}
/// ok if `actual` == `expected`
@discardableResult
open func eq<T:Equatable>(_ actual:T, _ expected:T, _ message:String = "")->Bool {
if ok(actual == expected, message) { return true }
print("# got: \(actual)")
print("# expected: \(expected)")
return false
}
/// ok if `actual` == `expected`
@discardableResult
open func eq<T:Equatable>(_ actual:T?, _ expected:T?, _ message:String = "")->Bool {
if ok(actual == expected, message) { return true }
print("# got: \(actual as T?)")
print("# expected: \(expected as T?)")
return false
}
/// ok if arrays are `actual` == `expected`
@discardableResult
open func eq<T:Equatable>(_ actual:[T], _ expected:[T], _ message:String = "")->Bool {
if ok(actual == expected, message) { return true }
print("# got: \(actual)")
print("# expected: \(expected)")
return false
}
/// ok if dictionaries are `actual` == `expected`
@discardableResult
open func eq<K:Hashable,V:Equatable>(_ actual:[K:V], _ expected:[K:V], _ message:String = "")->Bool {
if ok(actual == expected, message) { return true }
print("# got: \(actual)")
print("# expected: \(expected)")
return false
}
@discardableResult
/// ok if `actual` != `expected`
open func ne<T:Equatable>(_ actual:T, _ expected:T, _ message:String = "")->Bool {
if ok(actual != expected, message) { return true }
print("# got: \(actual)")
print("# expected: anthing but \(expected)")
return false
}
/// ok if `actual` != `expected`
@discardableResult
open func ne<T:Equatable>(_ actual:T?, _ expected:T?, _ message:String = "")->Bool {
if ok(actual != expected, message) { return true }
print("# got: \(actual as T?)")
print("# expected: anthing but \(expected as T?)")
return false
}
/// ok if arrays are `actual` == `expected`
@discardableResult
open func ne<T:Equatable>(_ actual:[T], _ expected:[T], _ message:String = "")->Bool {
if ok(actual != expected, message) { return true }
print("# got: \(actual)")
print("# expected: anthing but \(expected)")
return false
}
/// ok if dictionaries are `actual` == `expected`
@discardableResult
open func ne<K:Hashable,V:Equatable>(_ actual:[K:V], _ expected:[K:V], _ message:String = "")->Bool {
if ok(actual != expected, message) { return true }
print("# got: \(actual)")
print("# expected: anthing but \(expected)")
return false
}
/// checks the test results, print stuff if neccesary,
/// and `exit()` with code == number of failures
@discardableResult
open func done(dontExit nx:Bool = false)->[Bool] {
if runs.count == 0 && nx != true {
print("# no test run!")
exit(-1)
}
if tests == 0 {
print("1..\(runs.count)")
}
else if runs.count != tests {
print("not ok \(runs.count + 1) - planned to run \(tests) but actually ran \(runs.count)")
runs.append(false)
if nx != true { exit(-1) }
}
if nx != true {
let code = min(254, runs.filter{ $0 == false }.count)
exit(Int32(code))
}
return runs
}
deinit {
done(dontExit:true)
}
}

View File

@ -1,59 +0,0 @@
/***************************************************************************************************
test.swift
© 2016 YOCKOW.
Licensed under MIT License.
See "LICENSE.txt" for more information.
**************************************************************************************************/
// FIXME: These are irresponsible tests below.
#if os(Linux)
import Glibc
#elseif os(OSX) || os(iOS) || os(watchOS) || os(tvOS)
import Darwin
#else
// UNKNOWN OS
#endif
import TimeSpecification
let test = TAP()
// Normalization Tests
let N1 = TimeSpecification(seconds:0, nanoseconds:1_234_567_890)
let N2 = TimeSpecification(seconds:-1, nanoseconds:-1_234_567_890)
test.ok(N1.seconds == 1 && N1.nanoseconds == 234_567_890, "Normalization Test 1")
test.ok(N2.seconds == -3 && N2.nanoseconds == 765_432_110, "Normalization Test 2")
// Comparison Tests
let C1 = TimeSpecification(seconds:100, nanoseconds:100)
let C2 = TimeSpecification(seconds: 98, nanoseconds:2_000_000_100)
let C3 = TimeSpecification(seconds:200, nanoseconds:100)
let C4 = TimeSpecification(seconds:100, nanoseconds:200)
test.eq(C1, C2, "Comparison Test 1")
test.ok(C2 < C3, "Comparison Test 2")
test.ok(C2 < C4, "Comparison Test 3")
// IntegerLiteralConvertible Tests
let I1 = TimeSpecification(integerLiteral:100)
let I2 = TimeSpecification(integerLiteral:-100)
test.eq(I1, TimeSpecification(seconds:100, nanoseconds:0), "Integer Literal Convertible Test 1")
test.eq(I2, TimeSpecification(seconds:-100, nanoseconds:0), "Integer Literal Convertible Test 2")
// FloatLiteralConvertible Tests
let F1 = TimeSpecification(floatLiteral:-1.1)
//// How to test...
// Sum and Difference Tests
let L1 = TimeSpecification(seconds:100, nanoseconds:123_456_789)
let R1 = TimeSpecification(seconds:100, nanoseconds:987_654_321)
test.eq(L1 + R1, TimeSpecification(seconds:201, nanoseconds:111_111_110), "Sum Test 1")
test.eq(L1 - R1, TimeSpecification(seconds:0, nanoseconds:-864_197_532), "Difference Test 1")
test.done(dontExit:true)
// Others
print("\nOTHERS")
print("C time(): \(time(nil))")
print("Calendar Clock: \(Clock.Calendar.timeSpecification()!)")
print("System Clock: \(Clock.System.timeSpecification()!)")

View File

@ -57,7 +57,7 @@ public func <(lhs:TimeSpecification, rhs:TimeSpecification) -> Bool {
return false
}
/* IntegerLiteralConvertible */
/* ExpressibleByIntegerLiteral */
extension TimeSpecification {
public typealias IntegerLiteralType = Int64
public init(integerLiteral value:Int64) {
@ -66,7 +66,7 @@ extension TimeSpecification {
}
}
/* FloatLiteralConvertible */
/* ExpressibleByFloatLiteral */
extension TimeSpecification {
public typealias FloatLiteralType = Double
public init(floatLiteral value:Double) {

6
Tests/LinuxMain.swift Normal file
View File

@ -0,0 +1,6 @@
import XCTest
@testable import TimeSpecificationTests
XCTMain([
testCase(TimeSpecificationTests.allTests),
])

View File

@ -0,0 +1,59 @@
/***************************************************************************************************
SwiftTimeSpecificationTests.swift
© 2016-2017 YOCKOW.
Licensed under MIT License.
See "LICENSE.txt" for more information.
**************************************************************************************************/
// FIXME: These are irresponsible tests below.
import XCTest
@testable import TimeSpecification
class TimeSpecificationTests: XCTestCase {
func testNormalization() {
let N1 = TimeSpecification(seconds:0, nanoseconds:1_234_567_890)
let N2 = TimeSpecification(seconds:-1, nanoseconds:-1_234_567_890)
XCTAssertTrue(N1.seconds == 1 && N1.nanoseconds == 234_567_890, "Normalization Test 1")
XCTAssertTrue(N2.seconds == -3 && N2.nanoseconds == 765_432_110, "Normalization Test 2")
}
func testComparison() {
let C1 = TimeSpecification(seconds:100, nanoseconds:100)
let C2 = TimeSpecification(seconds: 98, nanoseconds:2_000_000_100)
let C3 = TimeSpecification(seconds:200, nanoseconds:100)
let C4 = TimeSpecification(seconds:100, nanoseconds:200)
XCTAssertEqual(C1, C2, "Comparison Test 1")
XCTAssertTrue(C2 < C3, "Comparison Test 2")
XCTAssertTrue(C2 < C4, "Comparison Test 3")
}
func testIntegerLiteral() {
let I1: TimeSpecification = 100
let I2: TimeSpecification = -100
XCTAssertEqual(I1, TimeSpecification(seconds:100, nanoseconds:0), "ExpressibleByIntegerLiteral Test 1")
XCTAssertEqual(I2, TimeSpecification(seconds:-100, nanoseconds:0), "ExpressibleByIntegerLiteral Test 2")
}
func testFloatLiteral() {
let F1: TimeSpecification = 1.1
XCTAssertEqual(F1, TimeSpecification(seconds:1, nanoseconds:100_000_000), "ExpressibleByFloatLiteral Test 1")
}
func testSumAndDifference() {
let L1 = TimeSpecification(seconds:100, nanoseconds:123_456_789)
let R1 = TimeSpecification(seconds:100, nanoseconds:987_654_321)
XCTAssertEqual(L1 + R1, TimeSpecification(seconds:201, nanoseconds:111_111_110), "Sum Test 1")
XCTAssertEqual(L1 - R1, TimeSpecification(seconds:0, nanoseconds:-864_197_532), "Difference Test 1")
}
static var allTests = [
("Normalization", testNormalization),
("Comparison", testComparison),
("ExpressibleByIntegerLiteral", testIntegerLiteral),
("ExpressibleByFloatLiteral", testFloatLiteral),
("+/-", testSumAndDifference)
]
}

View File

@ -2,138 +2,154 @@
=begin
build-install.rb
© 2016 YOCKOW.
© 2016-2017 YOCKOW.
Licensed under MIT License.
See "LICENSE.txt" for more information.
=end
# Requirements #####################################################################################
require 'fileutils'
require 'json'
require 'optparse'
require 'pathname'
require 'open3'
require 'shellwords'
# Constants
# Constants ########################################################################################
OS = case RbConfig::CONFIG['host_os']
when /darwin/i then :OS_X
when /darwin/i then :macOS
when /linux/i then :Linux
else :Other
end
RequiredSwiftVersion = '3.0'
SharedLibraryPrefix = 'lib'
SharedLibrarySuffix = (OS == :OS_X) ? '.dylib' : '.so'
SourcesDirectory = (Pathname(__FILE__).dirname + 'Sources').expand_path
LibrarySources = [
'Library'
].map{|fn| Pathname(fn)}
TestSources = [
'Test'
].map{|fn| Pathname(fn)}
SharedLibrarySuffix = (OS == :macOS) ? '.dylib' : '.so'
ModuleName = 'TimeSpecification'
ModuleLinkName = 'SwiftTimeSpecification'
ModuleLinkName = 'Swift' + ModuleName
RootDirectory = Pathname(__FILE__).dirname.expand_path
## Default Values
## Default Values ##
Defaults = {
:swiftc => Pathname('swiftc'),
:build_directory => Pathname('build'),
:swift => Pathname('swift'),
:build_directory => Pathname('./build'),
:install => false,
:prefix => Pathname('/usr/local'),
:debug => false,
:skip_build => false,
:skip_test => false,
:sdk => 'macosx',
:clean => false
}
## Options
## Options ##
Options = {
:swiftc => nil,
:swift => nil,
:build_directory => nil,
:install => nil,
:prefix => nil,
:debug => nil,
:skip_build => nil,
:skip_test => nil,
:sdk => nil,
:clean => nil
}
## Canceled ##
Canceled = {
:debug => nil,
:skip_build => nil,
:skip_test => nil
}
### Qualifications ###
UnsavableOptions = [:build_directory, :sdk, :clean]
PathnameOptions = [:ninja, :swift, :build_directory, :prefix]
# Functions
# Functions ########################################################################################
## Error ##
def failed(message)
$stderr.puts(message)
exit
$stderr.puts("!!ERROR!! #{message}")
exit(false)
end
def all_files_in_dir(dirname, basedir)
files = []
directory = basedir + dirname
Dir.foreach(directory.to_s) {|filename|
next if filename =~ /\A\.\.?\Z/
path = directory + filename
if path.directory?
files.concat(all_files_in_dir(filename, directory))
else
files.push(path)
end
## Run Shell Script
def try_exec(command, indent = 0)
puts(' ' * indent + "Execute: #{command}")
Open3.popen3(command) {|stdin, stdout, stderr, wait_thread|
stdin.close
stdout.each {|line| $stdout.puts(' ' * indent * 2 + line) }
stderr.each {|line| $stderr.puts(' ' * indent * 2 + line) }
status = wait_thread.value.exitstatus
failed("Command exited with status #{status}") if status != 0
}
return files
end
def all_files(list, rootdir)
files = []
list.each {|filename|
path = rootdir + filename
failed("#{path.to_s}: No such file or directory.") if !path.exist?
if path.directory?
files.concat(all_files_in_dir(filename, rootdir))
elsif
files.push(path)
end
}
return files
end
# Extends class
# Extends Class(es) ################################################################################
## Pathname ##
class Pathname
def escaped
return Shellwords.shellescape(self.to_s)
def escaped(type = :shell)
return Shellwords.shellescape(self.to_s) if type == :shell
return self.to_s.gsub(/\$/, '$$').gsub(/\s/, '$\&') if type == :ninja
return self.to_s
end
def exit_if_i_am_file
failed("#{self.to_s} is not directory.") if self.exist? && !self.directory?
end
end
# Parsing Options
# Parse Options ####################################################################################
OptionParser.new(__FILE__){|parser|
parser.on('--swiftc=PATH',
'Path to the Swift compiler which you want to use.') {|path|
Options[:swiftc] = Pathname(path)
parser.on('--swift=PATH',
'Path to `swift` which you want to use.') {|path|
path = Pathname(path)
path += 'swift' if path.directory?
Options[:swift] = Pathname(path)
}
parser.on('--build-dir=PATH', '--build-directory=PATH',
'Name of the directory where the build products will be placed.') {|path|
'Name of the directory where the build products will be placed. ' +
'Default: ' + Defaults[:build_directory].to_s) {|path|
Options[:build_directory] = Pathname(path)
}
parser.on('--install',
'Whether to install products or not.') {|value|
Options[:install] = value
}
parser.on('--prefix=PATH', '--install-prefix=PATH',
'The installation prefix.') {|path|
'The installation prefix. (Only used when `--install` is specified.) ' +
'Default: ' + Defaults[:prefix].to_s) {|path|
Options[:prefix] = Pathname(path)
Options[:prefix]= Options[:prefix].expand_path if path =~ /\A~\//
if !Options[:prefix].absolute?
failed(%Q[The installation prefix must be absolute path.])
elsif Options[:prefix].exist? && !Options[:prefix].directory?
failed(%Q["#{path}" is not directory.])
end
Options[:prefix].exit_if_i_am_file
Options[:install] = true # install library if prefix is specified.
}
parser.on('--debug',
'Debug builds') {|value|
Options[:debug] = value
}
parser.on('--release',
'Release builds; default is on') {|value|
Canceled[:debug] = value
}
parser.on('--skip-build',
'Whether to skip building or not.') {|value|
Options[:skip_build] = value
}
parser.on('--do-build',
'Cancel skipping building') {|value|
Canceled[:skip_build] = value
}
parser.on('--skip-test',
'Whether to skip testing or not.') {|value|
Options[:skip_test] = value
}
parser.on('--sdk=VALUE',
'(OS X Only) SDK name to be passed to `xcrun`.'){|value|
Options[:sdk] = value
failed("Invalid SDK Name: #{sdk}") if sdk !~ /\A[\.0-9A-Z_a-z]+\Z/
parser.on('--do-test',
'Cancel skipping testing') {|value|
Canceled[:skip_test] = value
}
parser.on('--clean',
'Whether to clean up or not.') {|value|
Options[:clean] = value
@ -146,43 +162,27 @@ OptionParser.new(__FILE__){|parser|
end
}
# Set SDK Name if it's nil
Options[:sdk] = Defaults[:sdk] if OS == :OS_X && Options[:sdk].nil?
# Determine Options ################################################################################
UnsavableOptions.each{|key| Options[key] = Defaults[key] if Options[key].nil?}
# Check SDK Name
if OS == :OS_X && !system(%Q[xcrun --sdk #{Options[:sdk]} --show-sdk-path >/dev/null 2>&1])
if $?.exitstatus == 127
failed("'xcrun' does not exist.")
else
failed("Invalid SDK Name: #{Options[:sdk]}")
end
end
# Build Directory
def exit_if_path_is_not_directory(path)
failed(%Q["#{path.to_s}" is Not Directory]) if path.exist? && !path.directory?
end
## Build Directory
Options[:build_directory] = Defaults[:build_directory] if Options[:build_directory].nil?
Options[:build_directory] = Options[:build_directory].expand_path if Options[:build_directory].relative?
exit_if_path_is_not_directory(Options[:build_directory])
Options[:build_directory] += Options[:sdk] if !Options[:sdk].nil?
exit_if_path_is_not_directory(Options[:build_directory])
Options[:build_directory] = RootDirectory + Options[:build_directory] if Options[:build_directory].relative?
Options[:build_directory].exit_if_i_am_file
FileUtils.rm_r(Options[:build_directory].to_s) if Options[:clean]
FileUtils.mkdir_p(Options[:build_directory].to_s)
# Set Options from defaults
cache_txt = Options[:build_directory] + 'build_options-cache.txt'
## Save/Read Cache
cache_json = Options[:build_directory] + 'build_options-cache.json'
saved_defaults = nil
if cache_txt.exist?
saved_defaults = JSON.parse(File.read(cache_txt.to_s), {:symbolize_names => true})
if cache_json.exist?
saved_defaults = JSON.parse(File.read(cache_json.to_s), {:symbolize_names => true})
saved_defaults.each_key{|key|
if key == :build_directory || key == :swiftc || key == :prefix
saved_defaults[key] = Pathname(saved_defaults[key])
end
saved_defaults[key] = Pathname(saved_defaults[key]) if PathnameOptions.include?(key)
}
end
Defaults.each_pair{|key, value|
next if key == :sdk || key == :build_directory || key == :clean
next if UnsavableOptions.include?(key)
if Options[key].nil?
if !saved_defaults.nil? && !saved_defaults[key].nil?
Options[key] = saved_defaults[key]
@ -191,126 +191,59 @@ Defaults.each_pair{|key, value|
end
end
}
File.write(cache_txt.to_s, JSON.dump(Options))
Canceled.each_pair{|key, value|
Options[key] = false if !value.nil? && value
}
File.write(cache_json.to_s, JSON.dump(Options))
Options.each_pair {|key, value| Options[key] = Defaults[key] if value.nil? }
# Determine Swift Path
if !system(%Q[which #{Options[:swiftc].escaped} >/dev/null])
failed("`swiftc` is not found.")
end
swiftc_command =
(OS == :OS_X) ? "xcrun --sdk #{Options[:sdk]} #{Options[:swiftc].escaped}"
: Options[:swiftc].escaped
# Swift? ###########################################################################################
failed("#{Options[:swift]} is not found.") if !system(%Q[which #{Options[:swift].escaped} >/dev/null])
# Detect Swift Version
swift_version = %x[#{swiftc_command} --version]
if swift_version =~ /^(?:Apple\s+)?Swift\s+version\s+(\d+)((?:\.\d+)*)\s+/
swift_version = Regexp.last_match(1) + Regexp.last_match(2)
if (swift_version.split('.').map(&:to_i) <=> RequiredSwiftVersion.split('.').map(&:to_i)) < 0
failed("The minimum required version of Swift is #{RequiredSwiftVersion}")
end
else
failed("Cannot detect the version of Swift: #{swift_version}")
end
# Build! ###########################################################################################
configuration = Options[:debug] ? 'debug' : 'release'
# Print Options
puts("Options:")
puts(%Q[ Swift Compiler: #{Options[:swiftc].to_s}])
puts(%Q[ Swift Version: #{swift_version}])
puts(%Q[ The Build Directory: "#{Options[:build_directory].to_s}"])
if Options[:install]
puts(%Q[ The Installation Prefix: "#{Options[:prefix].to_s}"])
else
puts(%Q[ No products will be installed.])
end
puts(%Q[ Skip building: #{Options[:skip_build] ? "Yes" : "No"}])
puts(%Q[ Skip testing: #{Options[:skip_test] ? "Yes" : "No"}])
libFilename = Pathname(SharedLibraryPrefix + ModuleLinkName + SharedLibrarySuffix)
libPath = Options[:build_directory] + Pathname(configuration) + libFilename
moduleFilename = Pathname(ModuleName + '.swiftmodule')
modulePath = Options[:build_directory] + Pathname(configuration) + moduleFilename
# Create directories
build_include_directory = Options[:build_directory] + 'include'
build_lib_directory = Options[:build_directory] + 'lib'
if !Options[:skip_build] || !Options[:skip_test]
FileUtils.mkdir_p(Options[:build_directory].to_s) if !File.exists?(Options[:build_directory])
FileUtils.mkdir_p(build_include_directory.to_s) if !File.exists?(build_include_directory)
FileUtils.mkdir_p(build_lib_directory.to_s) if !File.exists?(build_lib_directory)
end
# Let's Start!
def try_exec(command)
puts(" Execute: #{command}")
if !system(command)
failed("Command exited with status #{$?.exitstatus}")
end
end
## BUILD
# Build
if !Options[:skip_build]
puts("===== BUILD =====")
library_sources = all_files(LibrarySources, SourcesDirectory)
create_module =
"#{swiftc_command} " +
library_sources.map{|file| file.escaped}.join(' ') + ' ' +
"-module-name #{ModuleName} " +
"-module-link-name #{ModuleLinkName} " +
"-emit-module-path #{build_include_directory.escaped}/#{ModuleName}.swiftmodule "
try_exec(create_module)
build_library =
"#{swiftc_command} " +
library_sources.map{|file| file.escaped}.join(' ') + ' ' +
"-module-name #{ModuleName} " +
"-emit-library " +
"-o#{build_lib_directory.escaped}/#{SharedLibraryPrefix}#{ModuleLinkName}#{SharedLibrarySuffix}"
try_exec(build_library)
puts("...DONE")
puts("[Start Building...]")
try_exec(["swift build --build-path #{Options[:build_directory].escaped()}",
"--configuration #{configuration}",
"-Xswiftc -emit-library -Xswiftc -o#{libPath.escaped()}",
"-Xswiftc -module-link-name -Xswiftc #{ModuleLinkName}",
"-Xswiftc -module-name -Xswiftc #{ModuleName}",
"-Xswiftc -emit-module-path -Xswiftc #{modulePath.escaped()}"].join(" "),
2)
puts()
end
## TEST
# Test
if !Options[:skip_test]
puts("===== TEST =====")
test_executable = Options[:build_directory] + 'test'
test_sources = all_files(TestSources, SourcesDirectory)
if !test_executable.exist?
puts("Start building an executable")
build_test =
"#{swiftc_command} " +
test_sources.map{|file| file.escaped}.join(' ') + ' ' +
"-o#{test_executable.escaped} " +
"-I#{build_include_directory.escaped} " +
"-L#{build_lib_directory.escaped}"
try_exec(build_test)
if !Options[:debug]
$stderr.puts("** WARNING ** No tests will be executed when `release` mode is specified.\n")
else
puts("[Start Testing...]")
try_exec(["swift test --build-path #{Options[:build_directory].escaped()}",
"--configuration #{configuration}"].join(" "), 2)
end
puts("Start tests")
if !system(%Q[LD_LIBRARY_PATH=#{build_lib_directory.escaped} #{test_executable.escaped}])
failed("TEST FAILED.")
end
puts("..SUCCESSFUL")
end
## INSTALL
if Options[:install]
puts("===== INSTALL =====")
# Install
if !Options[:install]
puts("[Installing...]")
include_directory = Options[:prefix] + 'include'
lib_directory = Options[:prefix] + 'lib'
FileUtils.mkdir_p(include_directory.to_s) if !File.exists?(include_directory)
FileUtils.mkdir_p(lib_directory.to_s) if !File.exists?(lib_directory)
begin
FileUtils.copy_entry(build_include_directory.to_s,
include_directory.to_s)
FileUtils.copy_entry(build_lib_directory.to_s,
lib_directory.to_s)
rescue
failed("Installation Failed.")
if Options[:debug]
$stderr.puts("** WARNING ** DEBUG MODE. Products to be installed may not be optimized.\n")
end
puts("...DONE.")
libInstallPath = Options[:prefix] + Pathname('lib') + libFilename
moduleInstallPath = Options[:prefix] + Pathname('include') + moduleFilename
try_exec("cp #{libPath.escaped()} #{libInstallPath.escaped()} && " +
"cp #{modulePath.escaped()} #{moduleInstallPath.escaped()}", 2)
end