From ca8cdbc3d6f0b4f41b1d48ae3e8f4b01ffbaab1b Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Tue, 9 Apr 2019 14:54:14 -0700 Subject: [PATCH 01/67] Make TerminalController compile on Windows --- Sources/Basic/TerminalController.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Basic/TerminalController.swift b/Sources/Basic/TerminalController.swift index 4ba47590153..4001b6233ce 100644 --- a/Sources/Basic/TerminalController.swift +++ b/Sources/Basic/TerminalController.swift @@ -115,7 +115,7 @@ public final class TerminalController { // Following code does not compile on ppc64le well. TIOCGWINSZ is // defined in system ioctl.h file which needs to be used. This is // a temporary arrangement and needs to be fixed. -#if !arch(powerpc64le) +#if !(arch(powerpc64le) || os(Windows)) var ws = winsize() if ioctl(1, UInt(TIOCGWINSZ), &ws) == 0 { return Int(ws.ws_col) From 0a176cae62b0fb66fd88b8a119c0f8801f2361f6 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 12 Apr 2019 10:42:43 -0700 Subject: [PATCH 02/67] [PackageGraph] Bail out as early as possible when there are errors --- Sources/PackageGraph/DependencyResolver.swift | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Sources/PackageGraph/DependencyResolver.swift b/Sources/PackageGraph/DependencyResolver.swift index d307f9a6bf2..ed60eb923b6 100644 --- a/Sources/PackageGraph/DependencyResolver.swift +++ b/Sources/PackageGraph/DependencyResolver.swift @@ -1041,6 +1041,8 @@ public class DependencyResolver { subjectTo allConstraints: PackageContainerConstraintSet, excluding allExclusions: [PackageReference: Set] ) -> AnySequence { + guard self.error == nil else { return AnySequence([]) } + // The key that is used to cache this assignement set. let cacheKey = ResolveSubtreeCacheKey(container: container, allConstraints: allConstraints) @@ -1067,6 +1069,7 @@ public class DependencyResolver { // // FIXME: We must detect recursion here. func merge(constraints: [PackageContainerConstraint], binding: BoundVersion) -> AnySequence { + guard self.error == nil else { return AnySequence([]) } // Diagnose if this container depends on itself. if constraints.contains(where: { $0.identifier == container.identifier }) { @@ -1181,6 +1184,8 @@ public class DependencyResolver { subjectTo allConstraints: PackageContainerConstraintSet, excluding allExclusions: [PackageReference: Set] ) -> AnySequence { + guard self.error == nil else { return AnySequence([]) } + var allConstraints = allConstraints // Never prefetch when running in incomplete mode. From caea53ad329a79fce2ac2b3eadf7c8ba92b903fa Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Sun, 7 Apr 2019 13:23:17 -0700 Subject: [PATCH 03/67] Remove use of fts Replace the use of fts with Foundation's Directory Enumerator, which (on Darwin/Linux), calls fts instead, but is cross platform for Windows. --- Sources/Basic/FileSystem.swift | 111 ++++++++----------------- Sources/clibc/include/clibc.h | 2 - Tests/BasicTests/FileSystemTests.swift | 2 +- 3 files changed, 34 insertions(+), 81 deletions(-) diff --git a/Sources/Basic/FileSystem.swift b/Sources/Basic/FileSystem.swift index 958eaaf4c78..1b9e01a09a9 100644 --- a/Sources/Basic/FileSystem.swift +++ b/Sources/Basic/FileSystem.swift @@ -88,16 +88,18 @@ public enum FileMode { case userUnWritable case userWritable case executable - - /// File mode as it would be passed to `chmod`. - public var cliArgument: String { + + internal var setMode: (Int16) -> Int16 { switch self { case .userUnWritable: - return "u-w" + // r-x rwx rwx + return {$0 & 0o577} case .userWritable: - return "u+w" + // -w- --- --- + return {$0 | 0o200} case .executable: - return "+x" + // --x --x --x + return {$0 | 0o111} } } } @@ -375,86 +377,39 @@ private class LocalFileSystem: FileSystem { } func chmod(_ mode: FileMode, path: AbsolutePath, options: Set) throws { - #if os(macOS) - // Get the mode we need to set. - guard let setMode = setmode(mode.cliArgument) else { - throw FileSystemError(errno: errno) - } - defer { setMode.deallocate() } + guard exists(path) else { return } + func setMode(path: String) throws { + // Skip if only files should be changed. + if options.contains(.onlyFiles) && isDirectory(AbsolutePath(path)) { + return + } - let recursive = options.contains(.recursive) - // If we're in recursive mode, do physical walk otherwise logical. - let ftsOptions = recursive ? FTS_PHYSICAL : FTS_LOGICAL + let attrs = try FileManager.default.attributesOfItem(atPath: path) - // Get handle to the file hierarchy we want to traverse. - let paths = CStringArray([path.pathString]) - guard let ftsp = fts_open(paths.cArray, ftsOptions, nil) else { - throw FileSystemError(errno: errno) + // Compute the new mode for this file. + let currentMode = attrs[.posixPermissions] as! Int16 + let newMode = mode.setMode(currentMode) + guard newMode != currentMode else { return } + try FileManager.default.setAttributes([.posixPermissions : newMode], + ofItemAtPath: path) } - defer { fts_close(ftsp) } - - // Start traversing. - while let p = fts_read(ftsp) { - - switch Int32(p.pointee.fts_info) { - - // A directory being visited in pre-order. - case FTS_D: - // If we're not recursing, skip the contents of the directory. - if !recursive { - fts_set(ftsp, p, FTS_SKIP) - } - continue - - // A directory couldn't be read. - case FTS_DNR: - // FIXME: We should warn here. - break - - // There was an error. - case FTS_ERR: - fallthrough - // No stat(2) information was available. - case FTS_NS: - // FIXME: We should warn here. - continue + try setMode(path: path.pathString) + guard isDirectory(path) else { return } - // A symbolic link. - case FTS_SL: - fallthrough - - // A symbolic link with a non-existent target. - case FTS_SLNONE: - // The only symlinks that end up here are ones that don't point - // to anything and ones that we found doing a physical walk. - continue - - default: - break - } - - // Compute the new mode for this file. - let currentMode = mode_t(p.pointee.fts_statp.pointee.st_mode) - - // Skip if only files should be changed. - if options.contains(.onlyFiles) && (currentMode & S_IFMT) == S_IFDIR { - continue - } + guard let traverse = FileManager.default.enumerator( + at: URL(fileURLWithPath: path.pathString), + includingPropertiesForKeys: nil) else { + throw FileSystemError.noEntry + } - // Compute the new mode. - let newMode = getmode(setMode, currentMode) - if newMode == currentMode { - continue - } + if !options.contains(.recursive) { + traverse.skipDescendants() + } - // Update the mode. - // - // We ignore the errors for now but we should have a way to report back. - _ = SPMLibc.chmod(p.pointee.fts_accpath, newMode) + while let path = traverse.nextObject() { + try setMode(path: (path as! URL).path) } - #endif - // FIXME: We only support macOS right now. } } diff --git a/Sources/clibc/include/clibc.h b/Sources/clibc/include/clibc.h index 7cf808c182a..8a90bffafd1 100644 --- a/Sources/clibc/include/clibc.h +++ b/Sources/clibc/include/clibc.h @@ -1,5 +1,3 @@ -#include - #if defined(__linux__) #include #endif diff --git a/Tests/BasicTests/FileSystemTests.swift b/Tests/BasicTests/FileSystemTests.swift index f440cb7d699..2ea744b67a7 100644 --- a/Tests/BasicTests/FileSystemTests.swift +++ b/Tests/BasicTests/FileSystemTests.swift @@ -388,7 +388,7 @@ class FileSystemTests: XCTestCase { } func testSetAttribute() throws { - #if os(macOS) + #if os(macOS) || os(Linux) mktmpdir { path in let fs = Basic.localFileSystem From dadf766a78199d25d180deaac9f582ec63f41673 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Mon, 8 Apr 2019 17:10:35 -0700 Subject: [PATCH 04/67] Implement Basic/misc.swift on Windows --- Sources/Basic/misc.swift | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/Sources/Basic/misc.swift b/Sources/Basic/misc.swift index bbf9df82dcb..92c8966b87e 100644 --- a/Sources/Basic/misc.swift +++ b/Sources/Basic/misc.swift @@ -18,9 +18,20 @@ import Foundation /// - args: The executable arguments. public func exec(path: String, args: [String]) throws { let cArgs = CStringArray(args) + #if os(Windows) + guard cArgs.cArray.withUnsafeBufferPointer({ + $0.withMemoryRebound(to: UnsafePointer?.self, { + _execv(path, $0.baseAddress) != -1 + }) + }) + else { + throw SystemError.exec(errno, path: path, args: args) + } + #else guard execv(path, cArgs.cArray) != -1 else { throw SystemError.exec(errno, path: path, args: args) } + #endif } // MARK: Utility function for searching for executables @@ -163,13 +174,23 @@ public enum SystemError: Swift.Error { case waitpid(Int32) } +#if os(Windows) +import func SPMLibc.strerror_s +#else import func SPMLibc.strerror_r +#endif import var SPMLibc.EINVAL import var SPMLibc.ERANGE extension SystemError: CustomStringConvertible { public var description: String { func strerror(_ errno: Int32) -> String { + #if os(Windows) + let cap = 128 + var buf = [Int8](repeating: 0, count: cap) + let _ = SPMLibc.strerror_s(&buf, 128, errno) + return "\(String(cString: buf)) (\(errno))" + #else var cap = 64 while cap <= 16 * 1024 { var buf = [Int8](repeating: 0, count: cap) @@ -187,6 +208,7 @@ extension SystemError: CustomStringConvertible { return "\(String(cString: buf)) (\(errno))" } fatalError("strerror_r error: \(ERANGE)") + #endif } switch self { From eb39addde73ec64fd5c6524c6b7ae8bd30a0fe02 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Tue, 9 Apr 2019 14:21:53 -0700 Subject: [PATCH 05/67] Implement ProcessEnv.swift on Windows --- Sources/Basic/ProcessEnv.swift | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/Sources/Basic/ProcessEnv.swift b/Sources/Basic/ProcessEnv.swift index b4f22c7c628..6bf3efecb78 100644 --- a/Sources/Basic/ProcessEnv.swift +++ b/Sources/Basic/ProcessEnv.swift @@ -21,18 +21,34 @@ public enum ProcessEnv { /// Set the given key and value in the process's environment. public static func setVar(_ key: String, value: String) throws { - // FIXME: Need to handle Windows. + #if os(Windows) + guard 0 != key.withCString(encodedAs: UTF16.self, { keyStr in + value.withCString(encodedAs: UTF16.self) { valStr in + SetEnvironmentVariableW(keyStr, valStr) + } + }) else { + throw SystemError.setenv(Int32(GetLastError()), key) + } + #else guard SPMLibc.setenv(key, value, 1) == 0 else { throw SystemError.setenv(errno, key) } + #endif } /// Unset the give key in the process's environment. public static func unsetVar(_ key: String) throws { - // FIXME: Need to handle Windows. + #if os(Windows) + guard 0 != key.withCString(encodedAs: UTF16.self, { keyStr in + SetEnvironmentVariableW(keyStr, nil) + }) else { + throw SystemError.unsetenv(Int32(GetLastError()), key) + } + #else guard SPMLibc.unsetenv(key) == 0 else { throw SystemError.unsetenv(errno, key) } + #endif } /// The current working directory of the process. @@ -42,10 +58,17 @@ public enum ProcessEnv { /// Change the current working directory of the process. public static func chdir(_ path: AbsolutePath) throws { - // FIXME: Need to handle Windows. let path = path.pathString + #if os(Windows) + guard 0 != path.withCString(encodedAs: UTF16.self, { + SetCurrentDirectoryW($0) + }) else { + throw SystemError.chdir(Int32(GetLastError()), path) + } + #else guard SPMLibc.chdir(path) == 0 else { throw SystemError.chdir(errno, path) } + #endif } } From 7b0d17b7de721e2a53fe6ce2071108739fe12e47 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Tue, 9 Apr 2019 14:29:38 -0700 Subject: [PATCH 06/67] Fix Up ProcessSet for Windows Windows doesn't have SIGKILL, we'll use SIGTERM instead --- Sources/Basic/ProcessSet.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Sources/Basic/ProcessSet.swift b/Sources/Basic/ProcessSet.swift index 4d1e6e3a769..66c4ce0b09e 100644 --- a/Sources/Basic/ProcessSet.swift +++ b/Sources/Basic/ProcessSet.swift @@ -89,7 +89,11 @@ public final class ProcessSet { } } // Send kill signal to all processes. + #if os(Windows) + self.signalAll(SIGTERM) + #else self.signalAll(SIGKILL) + #endif } thread.start() From 1d199c3519faa7504f2f8e5267ed7f08915c850a Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Wed, 10 Apr 2019 09:28:34 -0700 Subject: [PATCH 07/67] Implement SignalHandler on Windows --- Sources/SPMUtility/InterruptHandler.swift | 43 ++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/Sources/SPMUtility/InterruptHandler.swift b/Sources/SPMUtility/InterruptHandler.swift index 3eb32a29054..b7dd78b063b 100644 --- a/Sources/SPMUtility/InterruptHandler.swift +++ b/Sources/SPMUtility/InterruptHandler.swift @@ -14,8 +14,12 @@ import Basic /// Interrupt signal handling global variables private var wasInterrupted = false private var wasInterruptedLock = Lock() +#if os(Windows) +private var signalWatchingPipe: [HANDLE] = [INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE] +#else private var signalWatchingPipe: [Int32] = [0, 0] private var oldAction = sigaction() +#endif /// This class can be used by command line tools to install a handler which /// should be called when a interrupt signal is delivered to the process. @@ -23,19 +27,41 @@ public final class InterruptHandler { /// The thread which waits to be notified when a signal is received. let thread: Thread + #if os(Windows) + let signalHandler: @convention(c)(UInt32) -> Int32 + #else + let signalHandler: @convention(c)(Int32) -> Void + #endif /// Start watching for interrupt signal and call the handler whenever the signal is received. public init(_ handler: @escaping () -> Void) throws { // Create a signal handler. - let signalHandler: @convention(c)(Int32) -> Void = { _ in + signalHandler = { _ in // Turn on the interrupt bool. wasInterruptedLock.withLock { wasInterrupted = true } // Write on pipe to notify the watching thread. var byte: UInt8 = 0 + #if os(Windows) + var bytesWritten: DWORD = 0 + WriteFile(signalWatchingPipe[1], &byte, 1, &bytesWritten, nil) + return TRUE + #else write(signalWatchingPipe[1], &byte, 1) + #endif } + #if os(Windows) + SetConsoleCtrlHandler(signalHandler, TRUE) + + var readPipe: HANDLE? + var writePipe: HANDLE? + let rv = CreatePipe(&readPipe, &writePipe, nil, 1) + signalWatchingPipe = [readPipe!, writePipe!] + guard rv != FALSE else { + throw SystemError.pipe(rv) + } + #else var action = sigaction() #if canImport(Darwin) action.__sigaction_u.__sa_handler = signalHandler @@ -51,13 +77,19 @@ public final class InterruptHandler { guard rv == 0 else { throw SystemError.pipe(rv) } + #endif // This thread waits to be notified via pipe. If something is read from pipe, check the interrupt bool // and send termination signal to all spawned processes in the process group. thread = Thread { while true { var buf: Int8 = 0 + #if os(Windows) + var n: DWORD = 0 + ReadFile(signalWatchingPipe[1], &buf, 1, &n, nil) + #else let n = read(signalWatchingPipe[0], &buf, 1) + #endif // Pipe closed, nothing to do. if n == 0 { break } // Read the value of wasInterrupted and set it to false. @@ -71,15 +103,24 @@ public final class InterruptHandler { handler() } } + #if os(Windows) + CloseHandle(signalWatchingPipe[0]) + #else close(signalWatchingPipe[0]) + #endif } thread.start() } deinit { + #if os(Windows) + SetConsoleCtrlHandler(signalHandler, FALSE) + CloseHandle(signalWatchingPipe[1]) + #else // Restore the old action and close the write end of pipe. sigaction(SIGINT, &oldAction, nil) close(signalWatchingPipe[1]) + #endif thread.join() } } From 9e692e40283222c3967693b6af13a2fa531c32d0 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Mon, 8 Apr 2019 18:29:23 -0700 Subject: [PATCH 08/67] Implement Lock.swift on Windows --- Sources/Basic/Lock.swift | 44 ++++++++++++++++++++++++++++++++++++++ Sources/SPMLibc/libc.swift | 3 +++ 2 files changed, 47 insertions(+) diff --git a/Sources/Basic/Lock.swift b/Sources/Basic/Lock.swift index 650f99d9dc4..39d5c80b22e 100644 --- a/Sources/Basic/Lock.swift +++ b/Sources/Basic/Lock.swift @@ -36,7 +36,11 @@ enum ProcessLockError: Swift.Error { /// by mutiple instances of a process. The `FileLock` is not thread-safe. public final class FileLock { /// File descriptor to the lock file. + #if os(Windows) + private var h: HANDLE? + #else private var fd: CInt? + #endif /// Path to the lock file. private let lockFile: AbsolutePath @@ -53,6 +57,32 @@ public final class FileLock { /// /// Note: This method can throw if underlying POSIX methods fail. public func lock() throws { + #if os(Windows) + if h == nil { + let h = lockFile.pathString.withCString(encodedAs: UTF16.self, { + CreateFileW( + $0, + UInt32(GENERIC_READ) | UInt32(GENERIC_WRITE), + 0, + nil, + DWORD(OPEN_ALWAYS), + DWORD(FILE_ATTRIBUTE_NORMAL), + nil + ) + }) + if h == INVALID_HANDLE_VALUE { + throw FileSystemError(errno: Int32(GetLastError())) + } + self.h = h + } + var overlapped = OVERLAPPED() + overlapped.Offset = 0 + overlapped.OffsetHigh = 0 + overlapped.hEvent = nil + if FALSE == LockFileEx(h, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) { + throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError())) + } + #else // Open the lock file. if fd == nil { let fd = SPMLibc.open(lockFile.pathString, O_WRONLY | O_CREAT | O_CLOEXEC, 0o666) @@ -70,17 +100,31 @@ public final class FileLock { if errno == EINTR { continue } throw ProcessLockError.unableToAquireLock(errno: errno) } + #endif } /// Unlock the held lock. public func unlock() { + #if os(Windows) + var overlapped = OVERLAPPED() + overlapped.Offset = 0 + overlapped.OffsetHigh = 0 + overlapped.hEvent = nil + UnlockFileEx(h, 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) + #else guard let fd = fd else { return } flock(fd, LOCK_UN) + #endif } deinit { + #if os(Windows) + guard let h = h else { return } + CloseHandle(h) + #else guard let fd = fd else { return } close(fd) + #endif } /// Execute the given block while holding the lock. diff --git a/Sources/SPMLibc/libc.swift b/Sources/SPMLibc/libc.swift index 4f32b5a40d2..d7d964d5148 100644 --- a/Sources/SPMLibc/libc.swift +++ b/Sources/SPMLibc/libc.swift @@ -10,6 +10,9 @@ #if os(Linux) @_exported import Glibc +#elseif os(Windows) +@_exported import MSVCRT +@_exported import WinSDK #else @_exported import Darwin.C #endif From ee89d1057a5a5d90a01011fb8306cbb95690d72a Mon Sep 17 00:00:00 2001 From: Thiago Holanda Date: Sun, 14 Apr 2019 19:55:34 +0200 Subject: [PATCH 09/67] Rename variables at Lock.swift (#2093) * Rename variables to give more context * Fix the indentation * Fix property name on deinit --- Sources/Basic/Lock.swift | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/Sources/Basic/Lock.swift b/Sources/Basic/Lock.swift index 39d5c80b22e..2094cc2ec2b 100644 --- a/Sources/Basic/Lock.swift +++ b/Sources/Basic/Lock.swift @@ -37,9 +37,9 @@ enum ProcessLockError: Swift.Error { public final class FileLock { /// File descriptor to the lock file. #if os(Windows) - private var h: HANDLE? + private var handle: HANDLE? #else - private var fd: CInt? + private var fileDescriptor: CInt? #endif /// Path to the lock file. @@ -58,7 +58,7 @@ public final class FileLock { /// Note: This method can throw if underlying POSIX methods fail. public func lock() throws { #if os(Windows) - if h == nil { + if handle == nil { let h = lockFile.pathString.withCString(encodedAs: UTF16.self, { CreateFileW( $0, @@ -69,11 +69,11 @@ public final class FileLock { DWORD(FILE_ATTRIBUTE_NORMAL), nil ) - }) - if h == INVALID_HANDLE_VALUE { - throw FileSystemError(errno: Int32(GetLastError())) - } - self.h = h + }) + if h == INVALID_HANDLE_VALUE { + throw FileSystemError(errno: Int32(GetLastError())) + } + self.handle = h } var overlapped = OVERLAPPED() overlapped.Offset = 0 @@ -84,16 +84,16 @@ public final class FileLock { } #else // Open the lock file. - if fd == nil { + if fileDescriptor == nil { let fd = SPMLibc.open(lockFile.pathString, O_WRONLY | O_CREAT | O_CLOEXEC, 0o666) if fd == -1 { throw FileSystemError(errno: errno) } - self.fd = fd + self.fileDescriptor = fd } // Aquire lock on the file. while true { - if flock(fd!, LOCK_EX) == 0 { + if flock(fileDescriptor!, LOCK_EX) == 0 { break } // Retry if interrupted. @@ -112,17 +112,17 @@ public final class FileLock { overlapped.hEvent = nil UnlockFileEx(h, 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) #else - guard let fd = fd else { return } + guard let fd = fileDescriptor else { return } flock(fd, LOCK_UN) #endif } deinit { #if os(Windows) - guard let h = h else { return } - CloseHandle(h) + guard let handle = handle else { return } + CloseHandle(handle) #else - guard let fd = fd else { return } + guard let fd = fileDescriptor else { return } close(fd) #endif } From d5c5b8696372d4d850f6f195dcd95f196f60abeb Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Mon, 15 Apr 2019 12:15:44 -0700 Subject: [PATCH 10/67] Fix Compilation of Lock.swift on Windows Some variables were not changed when being renamed on Windows. --- Sources/Basic/Lock.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/Basic/Lock.swift b/Sources/Basic/Lock.swift index 2094cc2ec2b..4338d4611e9 100644 --- a/Sources/Basic/Lock.swift +++ b/Sources/Basic/Lock.swift @@ -79,7 +79,7 @@ public final class FileLock { overlapped.Offset = 0 overlapped.OffsetHigh = 0 overlapped.hEvent = nil - if FALSE == LockFileEx(h, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) { + if FALSE == LockFileEx(handle, DWORD(LOCKFILE_EXCLUSIVE_LOCK), 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) { throw ProcessLockError.unableToAquireLock(errno: Int32(GetLastError())) } #else @@ -110,7 +110,7 @@ public final class FileLock { overlapped.Offset = 0 overlapped.OffsetHigh = 0 overlapped.hEvent = nil - UnlockFileEx(h, 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) + UnlockFileEx(handle, 0, DWORD(INT_MAX), DWORD(INT_MAX), &overlapped) #else guard let fd = fileDescriptor else { return } flock(fd, LOCK_UN) From 10ac0664bd3347755b9bb3dd8b765c02f950a952 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Wed, 10 Apr 2019 17:06:14 -0700 Subject: [PATCH 11/67] Implement SwiftTool.swift on Windows --- Sources/Commands/SwiftTool.swift | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 71f7965d4a6..42d033333d5 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -387,19 +387,23 @@ public class SwiftTool { // Terminate all processes on receiving an interrupt signal. processSet.terminate() + #if os(Windows) + // Exit as if by signal() + TerminateProcess(GetCurrentProcess(), 3) + #elseif os(macOS) // Install the default signal handler. var action = sigaction() - #if os(macOS) action.__sigaction_u.__sa_handler = SIG_DFL + sigaction(SIGINT, &action, nil) + kill(getpid(), SIGINT) #else + var action = sigaction() action.__sigaction_handler = unsafeBitCast( SIG_DFL, to: sigaction.__Unnamed_union___sigaction_handler.self) - #endif sigaction(SIGINT, &action, nil) - - // Die with sigint. kill(getpid(), SIGINT) + #endif } self.processSet = processSet From b548d703cb4dbadd5808c8d4b1211ce44981960f Mon Sep 17 00:00:00 2001 From: Keith Smiley Date: Thu, 18 Apr 2019 15:39:35 -0700 Subject: [PATCH 12/67] Optionally use non-frontend color-diagnostics flag This fixes Swift doing a full rebuild when you switch between a tty, and non-tty https://bugs.swift.org/browse/SR-7982 --- Sources/Build/BuildPlan.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 5c3bbab4fad..5faeb6a5630 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -519,7 +519,11 @@ public final class SwiftTargetBuildDescription { // Add arguments to colorize output if stdout is tty if buildParameters.isTTY { - args += ["-Xfrontend", "-color-diagnostics"] + if Process.env["SWIFTPM_USE_NEW_COLOR_DIAGNOSTICS"] != nil { + args += ["-color-diagnostics"] + } else { + args += ["-Xfrontend", "-color-diagnostics"] + } } // Add the output for the `.swiftinterface`, if requested. From 20e841f4102c4edb507372ad1aed8b46783c51b9 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Wed, 24 Apr 2019 15:43:30 -0700 Subject: [PATCH 13/67] Add .exe to Windows binaries --- Sources/Workspace/UserToolchain.swift | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/Sources/Workspace/UserToolchain.swift b/Sources/Workspace/UserToolchain.swift index a0736d488e7..ac7e2edbf0d 100644 --- a/Sources/Workspace/UserToolchain.swift +++ b/Sources/Workspace/UserToolchain.swift @@ -19,6 +19,11 @@ private let whichArgs: [String] = ["xcrun", "--find"] #else private let whichArgs = ["which"] #endif +#if os(Windows) +private let hostExecutableSuffix = ".exe" +#else +private let hostExecutableSuffix = "" +#endif /// Concrete object for manifest resource provider. public struct UserManifestResources: ManifestResourceProvider { @@ -56,7 +61,7 @@ public final class UserToolchain: Toolchain { /// Path of the `swift` interpreter. public var swiftInterpreter: AbsolutePath { - return swiftCompiler.parentDirectory.appending(component: "swift") + return swiftCompiler.parentDirectory.appending(component: "swift" + hostExecutableSuffix) } /// Path to the xctest utility. @@ -97,7 +102,7 @@ public final class UserToolchain: Toolchain { func validateCompiler(at path: AbsolutePath?) throws { guard let path = path else { return } guard localFileSystem.isExecutableFile(path) else { - throw InvalidToolchainDiagnostic("could not find the `swiftc` at expected path \(path)") + throw InvalidToolchainDiagnostic("could not find the `swiftc\(hostExecutableSuffix)` at expected path \(path)") } } @@ -112,13 +117,13 @@ public final class UserToolchain: Toolchain { // We require there is at least one valid swift compiler, either in the // bin dir or SWIFT_EXEC. let resolvedBinDirCompiler: AbsolutePath - let binDirCompiler = binDir.appending(component: "swiftc") + let binDirCompiler = binDir.appending(component: "swiftc" + hostExecutableSuffix) if localFileSystem.isExecutableFile(binDirCompiler) { resolvedBinDirCompiler = binDirCompiler } else if let SWIFT_EXEC = SWIFT_EXEC { resolvedBinDirCompiler = SWIFT_EXEC } else { - throw InvalidToolchainDiagnostic("could not find the `swiftc` at expected path \(binDirCompiler)") + throw InvalidToolchainDiagnostic("could not find the `swiftc\(hostExecutableSuffix)` at expected path \(binDirCompiler)") } // The compiler for compilation tasks is SWIFT_EXEC or the bin dir compiler. @@ -207,7 +212,7 @@ public final class UserToolchain: Toolchain { self.swiftCompiler = swiftCompilers.compile // Look for llbuild in bin dir. - llbuild = binDir.appending(component: "swift-build-tool") + llbuild = binDir.appending(component: "swift-build-tool" + hostExecutableSuffix) guard localFileSystem.exists(llbuild) else { throw InvalidToolchainDiagnostic("could not find `llbuild` at expected path \(llbuild)") } From a1c685bec46b2e7fbb6eba9c43a3be7954257f74 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Wed, 24 Apr 2019 15:15:27 -0700 Subject: [PATCH 14/67] Symlinks can be executable On Windows Symlinks aren't marked as regular files, but they can still be executed, so isExecutable should indicate as such. --- Sources/Basic/FileSystem.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Basic/FileSystem.swift b/Sources/Basic/FileSystem.swift index 1b9e01a09a9..23771775bb3 100644 --- a/Sources/Basic/FileSystem.swift +++ b/Sources/Basic/FileSystem.swift @@ -231,7 +231,7 @@ private class LocalFileSystem: FileSystem { func isExecutableFile(_ path: AbsolutePath) -> Bool { // Our semantics doesn't consider directories. - return self.isFile(path) && FileManager.default.isExecutableFile(atPath: path.pathString) + return (self.isFile(path) || self.isSymlink(path)) && FileManager.default.isExecutableFile(atPath: path.pathString) } func exists(_ path: AbsolutePath, followSymlink: Bool) -> Bool { From 6f778c2cf0016c2ef330b72e9cbff232dd7d9411 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 26 Apr 2019 20:04:59 -0700 Subject: [PATCH 15/67] [Basic] Use let instead of var --- Sources/Basic/SortedArray.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Basic/SortedArray.swift b/Sources/Basic/SortedArray.swift index 045c1e017c4..3a9679a20ff 100644 --- a/Sources/Basic/SortedArray.swift +++ b/Sources/Basic/SortedArray.swift @@ -69,7 +69,7 @@ public struct SortedArray: CustomStringConvertible { /// Insert the given sequence, maintaining the sort order. public mutating func insert(contentsOf newElements: S) where S.Iterator.Element == Element { - var newElements: Array = newElements.sorted(by: areInIncreasingOrder) + let newElements = newElements.sorted(by: areInIncreasingOrder) guard !newElements.isEmpty else { return } From 1e512e7029f19f6f450e9a2c1a133e2cddfba713 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Tue, 30 Apr 2019 10:18:47 -0700 Subject: [PATCH 16/67] [Utility] Bump SwiftPM version to 5.1 --- Sources/PackageLoading/ToolsVersionLoader.swift | 2 +- Sources/SPMUtility/Versioning.swift | 2 +- Tests/FunctionalTests/ToolsVersionTests.swift | 4 ++-- Tests/PackageLoadingTests/PackageBuilderTests.swift | 2 +- .../ToolsVersionLoaderTests.swift | 12 ++++++------ 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/PackageLoading/ToolsVersionLoader.swift b/Sources/PackageLoading/ToolsVersionLoader.swift index 59642493ef4..dc3b82a46a8 100644 --- a/Sources/PackageLoading/ToolsVersionLoader.swift +++ b/Sources/PackageLoading/ToolsVersionLoader.swift @@ -64,7 +64,7 @@ extension Manifest { }) let regularManifest = packagePath.appending(component: filename) - let toolsVersionLoader = ToolsVersionLoader() + let toolsVersionLoader = ToolsVersionLoader(currentToolsVersion: currentToolsVersion) // Find the version-specific manifest that statisfies the current tools version. if let versionSpecificCandidate = versionSpecificManifests.keys.sorted(by: >).first(where: { $0 <= currentToolsVersion }) { diff --git a/Sources/SPMUtility/Versioning.swift b/Sources/SPMUtility/Versioning.swift index 97456194b0e..9a7af90ee37 100644 --- a/Sources/SPMUtility/Versioning.swift +++ b/Sources/SPMUtility/Versioning.swift @@ -74,7 +74,7 @@ public struct Versioning { /// The current version of the package manager. public static let currentVersion = SwiftVersion( - version: (5, 0, 0), + version: (5, 1, 0), isDevelopment: false, buildIdentifier: getBuildIdentifier()) diff --git a/Tests/FunctionalTests/ToolsVersionTests.swift b/Tests/FunctionalTests/ToolsVersionTests.swift index ed42ce127da..24487f746ff 100644 --- a/Tests/FunctionalTests/ToolsVersionTests.swift +++ b/Tests/FunctionalTests/ToolsVersionTests.swift @@ -103,7 +103,7 @@ class ToolsVersionTests: XCTestCase { _ = try SwiftPMProduct.SwiftBuild.execute([], packagePath: primaryPath) XCTFail() } catch SwiftPMProductError.executionFailure(_, _, let stderr) { - XCTAssert(stderr.contains("is using Swift tools version 10000.1.0 but the installed version is 5.0.0"), stderr) + XCTAssert(stderr.contains("is using Swift tools version 10000.1.0 but the installed version is \(ToolsVersion.currentToolsVersion)"), stderr) } // Write the manifest with incompatible sources. @@ -124,7 +124,7 @@ class ToolsVersionTests: XCTestCase { _ = try SwiftPMProduct.SwiftBuild.execute([], packagePath: primaryPath) XCTFail() } catch SwiftPMProductError.executionFailure(_, _, let stderr) { - XCTAssertTrue(stderr.contains("package 'Primary' requires minimum Swift language version 1000 which is not supported by the current tools version (5.0.0)"), stderr) + XCTAssertTrue(stderr.contains("package 'Primary' requires minimum Swift language version 1000 which is not supported by the current tools version (\(ToolsVersion.currentToolsVersion))"), stderr) } try fs.writeFileContents(primaryPath.appending(component: "Package.swift")) { diff --git a/Tests/PackageLoadingTests/PackageBuilderTests.swift b/Tests/PackageLoadingTests/PackageBuilderTests.swift index 21df03d7ee9..1a8f0076d5d 100644 --- a/Tests/PackageLoadingTests/PackageBuilderTests.swift +++ b/Tests/PackageLoadingTests/PackageBuilderTests.swift @@ -1037,7 +1037,7 @@ class PackageBuilderTests: XCTestCase { manifest = createManifest( swiftVersions: [SwiftLanguageVersion(string: "6")!, SwiftLanguageVersion(string: "7")!]) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("package \'pkg\' requires minimum Swift language version 6 which is not supported by the current tools version (5.0.0)") + result.checkDiagnostic("package \'pkg\' requires minimum Swift language version 6 which is not supported by the current tools version (\(ToolsVersion.currentToolsVersion))") } } diff --git a/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift b/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift index 4dc35261148..ad68d0d1a81 100644 --- a/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift +++ b/Tests/PackageLoadingTests/ToolsVersionLoaderTests.swift @@ -156,17 +156,17 @@ class ToolsVersionLoaderTests: XCTestCase { try fs.writeFileContents(root.appending(component: "Package.swift"), bytes: "// swift-tools-version:1.0.0\n") try fs.writeFileContents(root.appending(component: "Package@swift-4.2.swift"), bytes: "// swift-tools-version:3.4.5\n") - try fs.writeFileContents(root.appending(component: "Package@swift-5.1.swift"), bytes: "// swift-tools-version:3.4.6\n") - try fs.writeFileContents(root.appending(component: "Package@swift-5.2.swift"), bytes: "// swift-tools-version:3.4.7\n") - try fs.writeFileContents(root.appending(component: "Package@swift-5.3.swift"), bytes: "// swift-tools-version:3.4.8\n") + try fs.writeFileContents(root.appending(component: "Package@swift-15.1.swift"), bytes: "// swift-tools-version:3.4.6\n") + try fs.writeFileContents(root.appending(component: "Package@swift-15.2.swift"), bytes: "// swift-tools-version:3.4.7\n") + try fs.writeFileContents(root.appending(component: "Package@swift-15.3.swift"), bytes: "// swift-tools-version:3.4.8\n") do { - let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "5.1.1")).load(at: root, fileSystem: fs) + let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "15.1.1")).load(at: root, fileSystem: fs) XCTAssertEqual(version.description, "3.4.6") } do { - let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "5.2.5")).load(at: root, fileSystem: fs) + let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "15.2.5")).load(at: root, fileSystem: fs) XCTAssertEqual(version.description, "3.4.7") } @@ -176,7 +176,7 @@ class ToolsVersionLoaderTests: XCTestCase { } do { - let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "5.3.0")).load(at: root, fileSystem: fs) + let version = try ToolsVersionLoader(currentToolsVersion: ToolsVersion(version: "15.3.0")).load(at: root, fileSystem: fs) XCTAssertEqual(version.description, "3.4.8") } } From a8e8a4f0c88f2a14bcfa5e7e5e097b7a3fd484da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20B=C3=BCgling?= Date: Tue, 30 Apr 2019 14:50:03 -0700 Subject: [PATCH 17/67] Add new `manifest` option to `swift package init` (#2106) This will just generate a manifest in the current directory. The contents will be the same as for initializing a library package. That means the contents will likely not match the filesystem layout, but I think that is OK, this will still make it easier to add a manifest to an existing project. We can improve it in the future and make the generated content based on what is actually there on the filesystem. rdar://problem/50347943 --- Sources/Workspace/InitPackage.swift | 18 ++++++++++----- Tests/WorkspaceTests/InitTests.swift | 27 ++++++++++++++++++++++ Tests/WorkspaceTests/XCTestManifests.swift | 1 + 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/Sources/Workspace/InitPackage.swift b/Sources/Workspace/InitPackage.swift index 62fbd287732..42c423802ca 100644 --- a/Sources/Workspace/InitPackage.swift +++ b/Sources/Workspace/InitPackage.swift @@ -22,6 +22,7 @@ public final class InitPackage { case library = "library" case executable = "executable" case systemModule = "system-module" + case manifest = "manifest" public var description: String { return rawValue @@ -63,6 +64,11 @@ public final class InitPackage { // FIXME: We should form everything we want to write, then validate that // none of it exists, and then act. try writeManifestFile() + + if packageType == .manifest { + return + } + try writeREADMEFile() try writeGitIgnore() try writeSources() @@ -96,7 +102,7 @@ public final class InitPackage { name: "\(pkgname)" """) - if packageType == .library { + if packageType == .library || packageType == .manifest { pkgParams.append(""" products: [ // Products define the executables and libraries produced by a package, and make them visible to other packages. @@ -114,7 +120,7 @@ public final class InitPackage { ] """) - if packageType == .library || packageType == .executable { + if packageType == .library || packageType == .executable || packageType == .manifest { pkgParams.append(""" targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. @@ -176,7 +182,7 @@ public final class InitPackage { } private func writeSources() throws { - if packageType == .systemModule { + if packageType == .systemModule || packageType == .manifest { return } let sources = destinationPath.appending(component: "Sources") @@ -210,7 +216,7 @@ public final class InitPackage { print("Hello, world!") """ - case .systemModule, .empty: + case .systemModule, .empty, .manifest: fatalError("invalid") } } @@ -249,7 +255,7 @@ public final class InitPackage { try makeDirectories(tests) switch packageType { - case .systemModule, .empty: break + case .systemModule, .empty, .manifest: break case .library, .executable: try writeLinuxMain(testsPath: tests) try writeTestFileStubs(testsPath: tests) @@ -356,7 +362,7 @@ public final class InitPackage { let testClassFile = testModule.appending(RelativePath("\(moduleName)Tests.swift")) switch packageType { - case .systemModule, .empty: break + case .systemModule, .empty, .manifest: break case .library: try writeLibraryTestsFile(testClassFile) case .executable: diff --git a/Tests/WorkspaceTests/InitTests.swift b/Tests/WorkspaceTests/InitTests.swift index 9f8149a7960..17d9e2bb164 100644 --- a/Tests/WorkspaceTests/InitTests.swift +++ b/Tests/WorkspaceTests/InitTests.swift @@ -164,6 +164,33 @@ class InitTests: XCTestCase { XCTAssert(fs.exists(path.appending(component: "module.modulemap"))) } } + + func testInitManifest() throws { + mktmpdir { tmpPath in + let fs = localFileSystem + let path = tmpPath.appending(component: "Foo") + let name = path.basename + try fs.createDirectory(path) + + // Create the package + let initPackage = try InitPackage(name: name, destinationPath: path, packageType: InitPackage.PackageType.manifest) + var progressMessages = [String]() + initPackage.progressReporter = { message in + progressMessages.append(message) + } + try initPackage.writePackageStructure() + + // Not picky about the specific progress messages, just checking that we got some. + XCTAssert(progressMessages.count > 0) + + // Verify basic file system content that we expect in the package + let manifest = path.appending(component: "Package.swift") + XCTAssertTrue(fs.exists(manifest)) + let manifestContents = try localFileSystem.readFileContents(manifest).description + let version = "\(InitPackage.newPackageToolsVersion.major).\(InitPackage.newPackageToolsVersion.minor)" + XCTAssertTrue(manifestContents.hasPrefix("// swift-tools-version:\(version)\n")) + } + } // MARK: Special case testing diff --git a/Tests/WorkspaceTests/XCTestManifests.swift b/Tests/WorkspaceTests/XCTestManifests.swift index 7da4e7d35b9..5cd272cab85 100644 --- a/Tests/WorkspaceTests/XCTestManifests.swift +++ b/Tests/WorkspaceTests/XCTestManifests.swift @@ -6,6 +6,7 @@ extension InitTests { // `swift test --generate-linuxmain` // to regenerate. static let __allTests__InitTests = [ + ("testInitManifest", testInitManifest), ("testInitPackageEmpty", testInitPackageEmpty), ("testInitPackageExecutable", testInitPackageExecutable), ("testInitPackageLibrary", testInitPackageLibrary), From d001fc6fc431ef30b8e1af211914e10a1cb9725f Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Thu, 18 Apr 2019 08:57:43 -0700 Subject: [PATCH 18/67] [PackageDescription] Adopt @available(_PackageDescription) This adopts the new _PackageDescription availability "platform" to drive the available APIs across different tools versions. Use @available(_PackageDescription) in runtime libraries --- .../LanguageStandardSettings.swift | 20 +++-- .../PackageDescription4/ManifestVersion.swift | 39 -------- Sources/PackageDescription4/Package.swift | 42 +++++++-- .../SupportedPlatforms.swift | 75 ++++++++-------- Sources/PackageDescription4/Target.swift | 89 +++++++++++++++---- Sources/PackageLoading/ManifestLoader.swift | 3 +- .../PackageDescription4Loader.swift | 51 ++--------- Sources/Workspace/Diagnostics.swift | 4 - .../PD4_2LoadingTests.swift | 35 +++++--- .../PackageLoadingTests/PD5LoadingTests.swift | 7 +- 10 files changed, 188 insertions(+), 177 deletions(-) delete mode 100644 Sources/PackageDescription4/ManifestVersion.swift diff --git a/Sources/PackageDescription4/LanguageStandardSettings.swift b/Sources/PackageDescription4/LanguageStandardSettings.swift index c49508f7389..2bf53dc024f 100644 --- a/Sources/PackageDescription4/LanguageStandardSettings.swift +++ b/Sources/PackageDescription4/LanguageStandardSettings.swift @@ -42,9 +42,16 @@ public enum CXXLanguageStandard: String, Encodable { /// Represents the version of the Swift language that should be used for /// compiling Swift sources in the package. public enum SwiftVersion { + @available(_PackageDescription, introduced: 4, obsoleted: 5) case v3 + + @available(_PackageDescription, introduced: 4) case v4 + + @available(_PackageDescription, introduced: 4) case v4_2 + + @available(_PackageDescription, introduced: 5) case v5 /// User-defined value of Swift version. @@ -55,20 +62,19 @@ public enum SwiftVersion { extension SwiftVersion: Encodable { public func encode(to encoder: Encoder) throws { - let value: VersionedValue - let api = String(reflecting: self) + let value: String switch self { case .v3: - value = VersionedValue("3", api: api, versions: [.v4_2]) + value = "3" case .v4: - value = VersionedValue("4", api: api) + value = "4" case .v4_2: - value = VersionedValue("4.2", api: api) + value = "4.2" case .v5: - value = VersionedValue("5", api: api, versions: [.v5]) + value = "5" case .version(let v): - value = VersionedValue(v, api: api) + value = v } var container = encoder.singleValueContainer() diff --git a/Sources/PackageDescription4/ManifestVersion.swift b/Sources/PackageDescription4/ManifestVersion.swift deleted file mode 100644 index 2faf436b120..00000000000 --- a/Sources/PackageDescription4/ManifestVersion.swift +++ /dev/null @@ -1,39 +0,0 @@ -/* - This source file is part of the Swift.org open source project - - Copyright (c) 2018 Apple Inc. and the Swift project authors - Licensed under Apache License v2.0 with Runtime Library Exception - - See http://swift.org/LICENSE.txt for license information - See http://swift.org/CONTRIBUTORS.txt for Swift project authors -*/ - -/// The supported manifest versions. -/// -/// ManifestVersion should never be public type. -enum ManifestVersion: String, Codable, CaseIterable { - case v4 - case v4_2 - case v5 - - // We will need to audit all VersionedValue instances when adding a new - // manifest version. Maybe versioned value should take a range of supported - // manifest versions? -} - -/// A value that is available in a set of manifest version. -/// -/// This is for mimicking something like the availability attribute for -/// PackageDescription APIs. -/// VersionedValue should never be public type. -struct VersionedValue: Encodable { - let supportedVersions: [ManifestVersion] - let value: T - let api: String - - init(_ value: T, api: String, versions: [ManifestVersion] = ManifestVersion.allCases) { - self.api = api - self.supportedVersions = versions - self.value = value - } -} diff --git a/Sources/PackageDescription4/Package.swift b/Sources/PackageDescription4/Package.swift index c6dfef98628..a037c9b5768 100644 --- a/Sources/PackageDescription4/Package.swift +++ b/Sources/PackageDescription4/Package.swift @@ -67,8 +67,13 @@ public final class Package { #if !PACKAGE_DESCRIPTION_4 /// The list of platforms supported by this package. - public var platforms: [SupportedPlatform]? + @available(_PackageDescription, introduced: 5) + public var platforms: [SupportedPlatform]? { + get { return _platforms } + set { _platforms = newValue } + } #endif + private var _platforms: [SupportedPlatform]? /// pkgconfig name to use for C Modules. If present, swiftpm will try to /// search for .pc file to get the additional flags needed for the @@ -126,7 +131,32 @@ public final class Package { registerExitHandler() } #else + @available(_PackageDescription, introduced: 4.2, obsoleted: 5) + public init( + name: String, + pkgConfig: String? = nil, + providers: [SystemPackageProvider]? = nil, + products: [Product] = [], + dependencies: [Dependency] = [], + targets: [Target] = [], + swiftLanguageVersions: [SwiftVersion]? = nil, + cLanguageStandard: CLanguageStandard? = nil, + cxxLanguageStandard: CXXLanguageStandard? = nil + ) { + self.name = name + self.pkgConfig = pkgConfig + self.providers = providers + self.products = products + self.dependencies = dependencies + self.targets = targets + self.swiftLanguageVersions = swiftLanguageVersions + self.cLanguageStandard = cLanguageStandard + self.cxxLanguageStandard = cxxLanguageStandard + registerExitHandler() + } + /// Construct a package. + @available(_PackageDescription, introduced: 5) public init( name: String, platforms: [SupportedPlatform]? = nil, @@ -140,7 +170,7 @@ public final class Package { cxxLanguageStandard: CXXLanguageStandard? = nil ) { self.name = name - self.platforms = platforms + self._platforms = platforms self.pkgConfig = pkgConfig self.providers = providers self.products = products @@ -221,10 +251,8 @@ extension Package: Encodable { try container.encode(name, forKey: .name) #if !PACKAGE_DESCRIPTION_4 - if let platforms = self.platforms { - // The platforms API was introduced in manifest version 5. - let versionedPlatforms = VersionedValue(platforms, api: "platforms", versions: [.v5]) - try container.encode(versionedPlatforms, forKey: .platforms) + if let platforms = self._platforms { + try container.encode(platforms, forKey: .platforms) } #endif @@ -234,7 +262,7 @@ extension Package: Encodable { try container.encode(dependencies, forKey: .dependencies) try container.encode(targets, forKey: .targets) #if PACKAGE_DESCRIPTION_4 - let slv = swiftLanguageVersions?.map({ VersionedValue(String($0), api: "") }) + let slv = swiftLanguageVersions?.map({ String($0) }) try container.encode(slv, forKey: .swiftLanguageVersions) #else try container.encode(swiftLanguageVersions, forKey: .swiftLanguageVersions) diff --git a/Sources/PackageDescription4/SupportedPlatforms.swift b/Sources/PackageDescription4/SupportedPlatforms.swift index b8f34e93e14..f533f5a741f 100644 --- a/Sources/PackageDescription4/SupportedPlatforms.swift +++ b/Sources/PackageDescription4/SupportedPlatforms.swift @@ -32,10 +32,10 @@ public struct SupportedPlatform: Encodable { let platform: Platform /// The platform version. - let version: VersionedValue? + let version: String? /// Creates supported platform instance. - init(platform: Platform, version: VersionedValue? = nil) { + init(platform: Platform, version: String? = nil) { self.platform = platform self.version = version } @@ -49,7 +49,7 @@ public struct SupportedPlatform: Encodable { /// /// The version string must be a series of 2 or 3 dot-separated integers, for example "10.10" or "10.10.1". public static func macOS(_ versionString: String) -> SupportedPlatform { - return SupportedPlatform(platform: .macOS, version: SupportedPlatform.MacOSVersion(versionString).version) + return SupportedPlatform(platform: .macOS, version: SupportedPlatform.MacOSVersion(string: versionString).version) } /// Create iOS supported platform with the given version. @@ -61,7 +61,7 @@ public struct SupportedPlatform: Encodable { /// /// The version string must be a series of 2 or 3 dot-separated integers, for example "8.0" or "8.0.1". public static func iOS(_ versionString: String) -> SupportedPlatform { - return SupportedPlatform(platform: .iOS, version: SupportedPlatform.IOSVersion(versionString).version) + return SupportedPlatform(platform: .iOS, version: SupportedPlatform.IOSVersion(string: versionString).version) } /// Create tvOS supported platform with the given version. @@ -73,7 +73,7 @@ public struct SupportedPlatform: Encodable { /// /// The version string must be a series of 2 or 3 dot-separated integers, for example "9.0" or "9.0.1". public static func tvOS(_ versionString: String) -> SupportedPlatform { - return SupportedPlatform(platform: .tvOS, version: SupportedPlatform.TVOSVersion(versionString).version) + return SupportedPlatform(platform: .tvOS, version: SupportedPlatform.TVOSVersion(string: versionString).version) } /// Create watchOS supported platform with the given version. @@ -85,7 +85,7 @@ public struct SupportedPlatform: Encodable { /// /// The version string must be a series of 2 or 3 dot-separated integers, for example "2.0" or "2.0.1". public static func watchOS(_ versionString: String) -> SupportedPlatform { - return SupportedPlatform(platform: .watchOS, version: SupportedPlatform.WatchOSVersion(versionString).version) + return SupportedPlatform(platform: .watchOS, version: SupportedPlatform.WatchOSVersion(string: versionString).version) } } @@ -96,17 +96,17 @@ extension SupportedPlatform { fileprivate static let minimumMajorVersion = 10 /// The underlying version representation. - let version: VersionedValue + let version: String - fileprivate init(_ version: VersionedValue) { + fileprivate init(uncheckedVersion version: String) { self.version = version } - public static let v10_10: MacOSVersion = .init("10.10", supportedVersions: [.v5]) - public static let v10_11: MacOSVersion = .init("10.11", supportedVersions: [.v5]) - public static let v10_12: MacOSVersion = .init("10.12", supportedVersions: [.v5]) - public static let v10_13: MacOSVersion = .init("10.13", supportedVersions: [.v5]) - public static let v10_14: MacOSVersion = .init("10.14", supportedVersions: [.v5]) + public static let v10_10: MacOSVersion = .init(string: "10.10") + public static let v10_11: MacOSVersion = .init(string: "10.11") + public static let v10_12: MacOSVersion = .init(string: "10.12") + public static let v10_13: MacOSVersion = .init(string: "10.13") + public static let v10_14: MacOSVersion = .init(string: "10.14") } public struct TVOSVersion: Encodable, AppleOSVersion { @@ -114,16 +114,16 @@ extension SupportedPlatform { fileprivate static let minimumMajorVersion = 9 /// The underlying version representation. - let version: VersionedValue + let version: String - fileprivate init(_ version: VersionedValue) { + fileprivate init(uncheckedVersion version: String) { self.version = version } - public static let v9: TVOSVersion = .init("9.0", supportedVersions: [.v5]) - public static let v10: TVOSVersion = .init("10.0", supportedVersions: [.v5]) - public static let v11: TVOSVersion = .init("11.0", supportedVersions: [.v5]) - public static let v12: TVOSVersion = .init("12.0", supportedVersions: [.v5]) + public static let v9: TVOSVersion = .init(string: "9.0") + public static let v10: TVOSVersion = .init(string: "10.0") + public static let v11: TVOSVersion = .init(string: "11.0") + public static let v12: TVOSVersion = .init(string: "12.0") } public struct IOSVersion: Encodable, AppleOSVersion { @@ -131,17 +131,17 @@ extension SupportedPlatform { fileprivate static let minimumMajorVersion = 2 /// The underlying version representation. - let version: VersionedValue + let version: String - fileprivate init(_ version: VersionedValue) { + fileprivate init(uncheckedVersion version: String) { self.version = version } - public static let v8: IOSVersion = .init("8.0", supportedVersions: [.v5]) - public static let v9: IOSVersion = .init("9.0", supportedVersions: [.v5]) - public static let v10: IOSVersion = .init("10.0", supportedVersions: [.v5]) - public static let v11: IOSVersion = .init("11.0", supportedVersions: [.v5]) - public static let v12: IOSVersion = .init("12.0", supportedVersions: [.v5]) + public static let v8: IOSVersion = .init(string: "8.0") + public static let v9: IOSVersion = .init(string: "9.0") + public static let v10: IOSVersion = .init(string: "10.0") + public static let v11: IOSVersion = .init(string: "11.0") + public static let v12: IOSVersion = .init(string: "12.0") } public struct WatchOSVersion: Encodable, AppleOSVersion { @@ -149,32 +149,27 @@ extension SupportedPlatform { fileprivate static let minimumMajorVersion = 2 /// The underlying version representation. - let version: VersionedValue + let version: String - fileprivate init(_ version: VersionedValue) { + fileprivate init(uncheckedVersion version: String) { self.version = version } - public static let v2: WatchOSVersion = .init("2.0", supportedVersions: [.v5]) - public static let v3: WatchOSVersion = .init("3.0", supportedVersions: [.v5]) - public static let v4: WatchOSVersion = .init("4.0", supportedVersions: [.v5]) - public static let v5: WatchOSVersion = .init("5.0", supportedVersions: [.v5]) + public static let v2: WatchOSVersion = .init(string: "2.0") + public static let v3: WatchOSVersion = .init(string: "3.0") + public static let v4: WatchOSVersion = .init(string: "4.0") + public static let v5: WatchOSVersion = .init(string: "5.0") } } fileprivate protocol AppleOSVersion { static var name: String { get } static var minimumMajorVersion: Int { get } - init(_ version: VersionedValue) + init(uncheckedVersion: String) } fileprivate extension AppleOSVersion { - init(_ version: String, supportedVersions: [ManifestVersion]) { - let api = "v" + version.split(separator: ".").reversed().drop(while: { $0 == "0" }).reversed().joined(separator: "_") - self.init(VersionedValue(version, api: api, versions: supportedVersions)) - } - - init(_ string: String) { + init(string: String) { // Perform a quick validation. let components = string.split(separator: ".", omittingEmptySubsequences: false).map({ UInt($0) }) var error = components.compactMap({ $0 }).count != components.count @@ -183,6 +178,6 @@ fileprivate extension AppleOSVersion { errors.append("invalid \(Self.name) version string: \(string)") } - self.init(VersionedValue(string, api: "")) + self.init(uncheckedVersion: string) } } diff --git a/Sources/PackageDescription4/Target.swift b/Sources/PackageDescription4/Target.swift index dee98e6a3d3..ca125b756d5 100644 --- a/Sources/PackageDescription4/Target.swift +++ b/Sources/PackageDescription4/Target.swift @@ -81,16 +81,36 @@ public final class Target { public let providers: [SystemPackageProvider]? /// C build settings. - public var cSettings: [CSetting]? + @available(_PackageDescription, introduced: 5) + public var cSettings: [CSetting]? { + get { return _cSettings } + set { _cSettings = newValue } + } + private var _cSettings: [CSetting]? /// C++ build settings. - public var cxxSettings: [CXXSetting]? + @available(_PackageDescription, introduced: 5) + public var cxxSettings: [CXXSetting]? { + get { return _cxxSettings } + set { _cxxSettings = newValue } + } + private var _cxxSettings: [CXXSetting]? /// Swift build settings. - public var swiftSettings: [SwiftSetting]? + @available(_PackageDescription, introduced: 5) + public var swiftSettings: [SwiftSetting]? { + get { return _swiftSettings } + set { _swiftSettings = newValue } + } + private var _swiftSettings: [SwiftSetting]? /// Linker build settings. - public var linkerSettings: [LinkerSetting]? + @available(_PackageDescription, introduced: 5) + public var linkerSettings: [LinkerSetting]? { + get { return _linkerSettings } + set { _linkerSettings = newValue } + } + private var _linkerSettings: [LinkerSetting]? /// Construct a target. private init( @@ -117,10 +137,10 @@ public final class Target { self.type = type self.pkgConfig = pkgConfig self.providers = providers - self.cSettings = cSettings - self.cxxSettings = cxxSettings - self.swiftSettings = swiftSettings - self.linkerSettings = linkerSettings + self._cSettings = cSettings + self._cxxSettings = cxxSettings + self._swiftSettings = swiftSettings + self._linkerSettings = linkerSettings switch type { case .regular, .test: @@ -129,6 +149,27 @@ public final class Target { } } + @available(_PackageDescription, introduced: 4, obsoleted: 5) + public static func target( + name: String, + dependencies: [Dependency] = [], + path: String? = nil, + exclude: [String] = [], + sources: [String]? = nil, + publicHeadersPath: String? = nil + ) -> Target { + return Target( + name: name, + dependencies: dependencies, + path: path, + exclude: exclude, + sources: sources, + publicHeadersPath: publicHeadersPath, + type: .regular + ) + } + + @available(_PackageDescription, introduced: 5) public static func target( name: String, dependencies: [Dependency] = [], @@ -156,6 +197,26 @@ public final class Target { ) } + @available(_PackageDescription, introduced: 4, obsoleted: 5) + public static func testTarget( + name: String, + dependencies: [Dependency] = [], + path: String? = nil, + exclude: [String] = [], + sources: [String]? = nil + ) -> Target { + return Target( + name: name, + dependencies: dependencies, + path: path, + exclude: exclude, + sources: sources, + publicHeadersPath: nil, + type: .test + ) + } + + @available(_PackageDescription, introduced: 5) public static func testTarget( name: String, dependencies: [Dependency] = [], @@ -233,23 +294,19 @@ extension Target: Encodable { try container.encode(pkgConfig, forKey: .pkgConfig) try container.encode(providers, forKey: .providers) - if let cSettings = self.cSettings { - let cSettings = VersionedValue(cSettings, api: "cSettings", versions: [.v5]) + if let cSettings = self._cSettings { try container.encode(cSettings, forKey: .cSettings) } - if let cxxSettings = self.cxxSettings { - let cxxSettings = VersionedValue(cxxSettings, api: "cxxSettings", versions: [.v5]) + if let cxxSettings = self._cxxSettings { try container.encode(cxxSettings, forKey: .cxxSettings) } - if let swiftSettings = self.swiftSettings { - let swiftSettings = VersionedValue(swiftSettings, api: "swiftSettings", versions: [.v5]) + if let swiftSettings = self._swiftSettings { try container.encode(swiftSettings, forKey: .swiftSettings) } - if let linkerSettings = self.linkerSettings { - let linkerSettings = VersionedValue(linkerSettings, api: "linkerSettings", versions: [.v5]) + if let linkerSettings = self._linkerSettings { try container.encode(linkerSettings, forKey: .linkerSettings) } } diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 02535912bcd..21a9ba5b066 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -23,8 +23,6 @@ public enum ManifestParseError: Swift.Error { case runtimeManifestErrors([String]) case duplicateDependencyDecl([[PackageDependencyDescription]]) - - case unsupportedAPI(api: String, supportedVersions: [ManifestVersion]) } /// Resources required for manifest loading. @@ -512,6 +510,7 @@ public final class ManifestLoader: ManifestLoaderProtocol { if let sdkRoot = resources.sdkRoot ?? self.sdkRoot() { cmd += ["-sdk", sdkRoot.pathString] } + cmd += ["-package-description-version", manifestVersion.description] return cmd } diff --git a/Sources/PackageLoading/PackageDescription4Loader.swift b/Sources/PackageLoading/PackageDescription4Loader.swift index df83cf1a168..10f1bafe964 100644 --- a/Sources/PackageLoading/PackageDescription4Loader.swift +++ b/Sources/PackageLoading/PackageDescription4Loader.swift @@ -37,15 +37,8 @@ extension ManifestBuilder { return nil } - /// Parse the versioned value. - let versionedValues = try versionJSON.map({ try VersionedValue(json: $0) }) - - return try versionedValues.map { versionedValue in - // Validate that this versioned value is supported by the current - // manifest version. - try versionedValue.validate(for: self.manifestVersion) - - return try SwiftLanguageVersion(string: String(json: versionedValue.value))! + return try versionJSON.map { + try SwiftLanguageVersion(string: String(json: $0))! } } @@ -54,12 +47,8 @@ extension ManifestBuilder { return [] } - /// Ensure that platforms API is used in the right manifest version. - let versionedPlatforms = try VersionedValue(json: platformsJSON) - try versionedPlatforms.validate(for: self.manifestVersion) - // Get the declared platform list. - let declaredPlatforms = try versionedPlatforms.value.getArray() + let declaredPlatforms = try platformsJSON.getArray() // Empty list is not supported. if declaredPlatforms.isEmpty { @@ -72,12 +61,7 @@ extension ManifestBuilder { for platformJSON in declaredPlatforms { // Parse the version and validate that it can be used in the current // manifest version. - let versionJSON = try platformJSON.getJSON("version") - let versionedVersion = try VersionedValue(json: versionJSON) - try versionedVersion.validate(for: self.manifestVersion) - - // Get the actual value of the version. - let version = try String(json: versionedVersion.value) + let version: String = try platformJSON.get("version") // Get the platform name. let platformName: String = try platformJSON.getJSON("platform").get("name") @@ -131,10 +115,8 @@ extension ManifestBuilder { } func parseBuildSettings(_ json: JSON, tool: TargetBuildSettingDescription.Tool) throws -> [TargetBuildSettingDescription.Setting] { - let versionedValue = try VersionedValue(json: json) - try versionedValue.validate(for: self.manifestVersion) - let declaredSettings = try versionedValue.value.getArray() + let declaredSettings = try json.getArray() if declaredSettings.isEmpty { throw ManifestParseError.runtimeManifestErrors(["empty list not supported"]) } @@ -169,29 +151,6 @@ extension ManifestBuilder { } } -struct VersionedValue: JSONMappable { - let supportedVersions: [ManifestVersion] - let value: JSON - let api: String - - init(json: JSON) throws { - self.api = try json.get(String.self, forKey: "api") - self.value = try json.getJSON("value") - - let supportedVersionsJSON = try json.get([String].self, forKey: "supportedVersions") - self.supportedVersions = supportedVersionsJSON.map({ ManifestVersion(rawValue: $0)! }) - } - - func validate(for manifestVersion: ManifestVersion) throws { - if !supportedVersions.contains(manifestVersion) { - throw ManifestParseError.unsupportedAPI( - api: api, - supportedVersions: supportedVersions - ) - } - } -} - extension SystemPackageProviderDescription { fileprivate init(v4 json: JSON) throws { let name = try json.get(String.self, forKey: "name") diff --git a/Sources/Workspace/Diagnostics.swift b/Sources/Workspace/Diagnostics.swift index a4ce1cc47ce..0c5ba45596f 100644 --- a/Sources/Workspace/Diagnostics.swift +++ b/Sources/Workspace/Diagnostics.swift @@ -71,10 +71,6 @@ extension ManifestParseError: DiagnosticDataConvertible { return ManifestParseDiagnostic(errors, diagnosticFile: nil) case .duplicateDependencyDecl(let duplicates): return ManifestDuplicateDeclDiagnostic(duplicates) - case .unsupportedAPI(let api, let supportedVersions): - var error = "'\(api)' is only supported by manifest version(s): " - error += supportedVersions.map({ $0.description }).joined(separator: ", ") - return ManifestParseDiagnostic([error], diagnosticFile: nil) } } } diff --git a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift index fa2245596de..30258ccc6cc 100644 --- a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift @@ -175,16 +175,16 @@ class PackageDescription4_2LoadingTests: XCTestCase { try loadManifestThrowing(stream.bytes) { _ in } XCTFail() } catch { - guard case let ManifestParseError.unsupportedAPI(api, supportedVersions) = error else { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { return XCTFail("\(error)") } - XCTAssertEqual(api, "PackageDescription.SwiftVersion.v5") - XCTAssertEqual(supportedVersions, [.v5]) + + XCTAssertMatch(message, .contains("is unavailable")) + XCTAssertMatch(message, .contains("was introduced in PackageDescription 5")) } } func testPlatforms() throws { - // Unfortunately, we can't prevent the nil case. var stream = BufferedOutputByteStream() stream <<< """ import PackageDescription @@ -194,9 +194,16 @@ class PackageDescription4_2LoadingTests: XCTestCase { ) """ - loadManifest(stream.bytes) { manifest in - XCTAssertEqual(manifest.name, "Foo") - XCTAssertEqual(manifest.platforms, [], "\(manifest.platforms)") + do { + try loadManifestThrowing(stream.bytes) { _ in } + XCTFail() + } catch { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { + return XCTFail("\(error)") + } + + XCTAssertMatch(message, .contains("is unavailable")) + XCTAssertMatch(message, .contains("was introduced in PackageDescription 5")) } stream = BufferedOutputByteStream() @@ -212,11 +219,12 @@ class PackageDescription4_2LoadingTests: XCTestCase { try loadManifestThrowing(stream.bytes) { _ in } XCTFail() } catch { - guard case let ManifestParseError.unsupportedAPI(api, supportedVersions) = error else { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { return XCTFail("\(error)") } - XCTAssertEqual(api, "platforms") - XCTAssertEqual(supportedVersions, [.v5]) + + XCTAssertMatch(message, .contains("is unavailable")) + XCTAssertMatch(message, .contains("was introduced in PackageDescription 5")) } } @@ -244,11 +252,12 @@ class PackageDescription4_2LoadingTests: XCTestCase { try loadManifestThrowing(stream.bytes) { _ in } XCTFail() } catch { - guard case let ManifestParseError.unsupportedAPI(api, supportedVersions) = error else { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { return XCTFail("\(error)") } - XCTAssertEqual(api, "swiftSettings") - XCTAssertEqual(supportedVersions, [.v5]) + + XCTAssertMatch(message, .contains("is unavailable")) + XCTAssertMatch(message, .contains("was introduced in PackageDescription 5")) } } diff --git a/Tests/PackageLoadingTests/PD5LoadingTests.swift b/Tests/PackageLoadingTests/PD5LoadingTests.swift index d0c5a60bd5e..1e73b6e2d69 100644 --- a/Tests/PackageLoadingTests/PD5LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD5LoadingTests.swift @@ -140,11 +140,12 @@ class PackageDescription5LoadingTests: XCTestCase { try loadManifestThrowing(stream.bytes) { _ in } XCTFail() } catch { - guard case let ManifestParseError.unsupportedAPI(api, supportedVersions) = error else { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { return XCTFail("\(error)") } - XCTAssertEqual(api, "PackageDescription.SwiftVersion.v3") - XCTAssertEqual(supportedVersions, [.v4_2]) + + XCTAssertMatch(message, .contains("'v3' is unavailable")) + XCTAssertMatch(message, .contains("'v3' was obsoleted in PackageDescription 5")) } } From 933288ecb05704016f9d3f8d557597a7937a4ecd Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Wed, 24 Apr 2019 14:50:31 -0700 Subject: [PATCH 19/67] Port Process.swift to Windows --- Sources/Basic/Process.swift | 74 ++++++++++++++++++++++++++++++++++++- 1 file changed, 73 insertions(+), 1 deletion(-) diff --git a/Sources/Basic/Process.swift b/Sources/Basic/Process.swift index f388c769d95..7ed628aa93c 100644 --- a/Sources/Basic/Process.swift +++ b/Sources/Basic/Process.swift @@ -10,6 +10,10 @@ import class Foundation.ProcessInfo +#if os(Windows) +import Foundation +#endif + import SPMLibc import Dispatch @@ -56,12 +60,16 @@ public struct ProcessResult: CustomStringConvertible { stderrOutput: Result<[UInt8], AnyError> ) { let exitStatus: ExitStatus + #if os(Windows) + exitStatus = .terminated(code: exitStatusCode) + #else if WIFSIGNALED(exitStatusCode) { exitStatus = .signalled(signal: WTERMSIG(exitStatusCode)) } else { precondition(WIFEXITED(exitStatusCode), "unexpected exit status \(exitStatusCode)") exitStatus = .terminated(code: WEXITSTATUS(exitStatusCode)) } + #endif self.init(arguments: arguments, exitStatus: exitStatus, output: output, stderrOutput: stderrOutput) } @@ -137,8 +145,10 @@ public final class Process: ObjectIdentifierProtocol { } /// Typealias for process id type. + #if !os(Windows) public typealias ProcessID = pid_t - + #endif + /// Typealias for stdout/stderr output closure. public typealias OutputClosure = ([UInt8]) -> Void @@ -160,7 +170,11 @@ public final class Process: ObjectIdentifierProtocol { public let environment: [String: String] /// The process id of the spawned process, available after the process is launched. + #if os(Windows) + private var _process: Foundation.Process? + #else public private(set) var processID = ProcessID() + #endif /// If the subprocess has launched. /// Note: This property is not protected by the serial queue because it is only mutated in `launch()`, which will be @@ -180,6 +194,11 @@ public final class Process: ObjectIdentifierProtocol { /// The result of the process execution. Available after process is terminated. private var _result: ProcessResult? + #if os(Windows) + private var stdoutData: [UInt8] = [] + private var stderrData: [UInt8] = [] + #endif + /// If redirected, stdout result and reference to the thread reading the output. private var stdout: (result: Result<[UInt8], AnyError>, thread: Thread?) = (Result([]), nil) @@ -267,6 +286,30 @@ public final class Process: ObjectIdentifierProtocol { throw Process.Error.missingExecutableProgram(program: arguments[0]) } + #if os(Windows) + _process = Foundation.Process() + _process?.arguments = arguments + _process?.executableURL = URL(fileURLWithPath: arguments[0]) + + if outputRedirection.redirectsOutput { + let stdoutPipe = Pipe() + let stderrPipe = Pipe() + stdoutPipe.fileHandleForReading.readabilityHandler = { (fh : FileHandle) -> Void in + let contents = fh.readDataToEndOfFile() + self.outputRedirection.outputClosures?.stdoutClosure([UInt8](contents)) + self.stdoutData += contents + } + stderrPipe.fileHandleForReading.readabilityHandler = { (fh : FileHandle) -> Void in + let contents = fh.readDataToEndOfFile() + self.outputRedirection.outputClosures?.stderrClosure([UInt8](contents)) + self.stderrData += contents + } + _process?.standardOutput = stdoutPipe + _process?.standardError = stderrPipe + } + + try _process?.run() + #else // Initialize the spawn attributes. #if canImport(Darwin) var attributes: posix_spawnattr_t? = nil @@ -381,11 +424,27 @@ public final class Process: ObjectIdentifierProtocol { thread.start() self.stderr.thread = thread } + #endif // POSIX implementation } /// Blocks the calling process until the subprocess finishes execution. @discardableResult public func waitUntilExit() throws -> ProcessResult { + #if os(Windows) + precondition(_process != nil, "The process is not yet launched.") + let p = _process! + p.waitUntilExit() + stdout.thread?.join() + stderr.thread?.join() + + let executionResult = ProcessResult( + arguments: arguments, + exitStatusCode: p.terminationStatus, + output: stdout.result, + stderrOutput: stderr.result + ) + return executionResult + #else return try serialQueue.sync { precondition(launched, "The process is not yet launched.") @@ -418,8 +477,10 @@ public final class Process: ObjectIdentifierProtocol { self._result = executionResult return executionResult } + #endif } + #if !os(Windows) /// Reads the given fd and returns its result. /// /// Closes the fd before returning. @@ -456,13 +517,22 @@ public final class Process: ObjectIdentifierProtocol { // Construct the output result. return error.map(Result.init) ?? Result(out) } + #endif /// Send a signal to the process. /// /// Note: This will signal all processes in the process group. public func signal(_ signal: Int32) { + #if os(Windows) + if signal == SIGINT { + _process?.interrupt() + } else { + _process?.terminate() + } + #else assert(launched, "The process is not yet launched.") _ = SPMLibc.kill(startNewProcessGroup ? -processID : processID, signal) + #endif } } @@ -517,6 +587,7 @@ extension Process { // MARK: - Private helpers +#if !os(Windows) #if os(macOS) private typealias swiftpm_posix_spawn_file_actions_t = posix_spawn_file_actions_t? #else @@ -605,3 +676,4 @@ extension ProcessResult.Error: CustomStringConvertible { } } } +#endif From a02da00e2e47bf104997b7067b8200e5c5d6aa5b Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 3 May 2019 13:47:30 -0700 Subject: [PATCH 20/67] Improve some diagnostics messages --- .../Version+StringLiteralConvertible.swift | 2 +- Sources/PackageGraph/DependencyResolver.swift | 6 +++--- Sources/PackageGraph/PackageGraphLoader.swift | 8 ++++---- Sources/PackageLoading/Diagnostics.swift | 9 ++++----- Sources/PackageLoading/PackageBuilder.swift | 17 ++++++++--------- Sources/PackageModel/Package.swift | 2 +- Sources/Workspace/Diagnostics.swift | 9 ++------- Tests/PackageGraphTests/PackageGraphTests.swift | 4 ++-- .../PackageLoadingTests/PD4_2LoadingTests.swift | 2 +- .../PackageBuilderTests.swift | 12 ++++++------ Tests/WorkspaceTests/WorkspaceTests.swift | 2 +- 11 files changed, 33 insertions(+), 40 deletions(-) diff --git a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift index 7766af63331..8c35f1ebb63 100644 --- a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift +++ b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift @@ -18,7 +18,7 @@ extension Version: ExpressibleByStringLiteral { // the error and initialize with a dummy value. This is done to // report error to the invoking tool (like swift build) gracefully // rather than just crashing. - errors.append("Invalid version string: \(value)") + errors.append("Invalid semantic version string '\(value)'") self.init(0, 0, 0) } } diff --git a/Sources/PackageGraph/DependencyResolver.swift b/Sources/PackageGraph/DependencyResolver.swift index ed60eb923b6..62978609eb4 100644 --- a/Sources/PackageGraph/DependencyResolver.swift +++ b/Sources/PackageGraph/DependencyResolver.swift @@ -60,9 +60,9 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible { public var description: String { switch self { case .cancelled: - return "the dependency resolution was cancelled" + return "the package resolution operation was cancelled" case .unsatisfiable: - return "unable to resolve dependencies" + return "the package dependency graph could not be resolved due to an unknown conflict" case .cycle(let package): return "the package \(package) depends on itself" case let .incompatibleConstraints(dependency, revisions): @@ -79,7 +79,7 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible { case let .missingVersions(constraints): let stream = BufferedOutputByteStream() - stream <<< "the package dependency graph is unresolvable; unable find any available tag for the following requirements:\n" + stream <<< "the package dependency graph could not be resolved; unable find any available tag for the following requirements:\n" for (i, constraint) in constraints.enumerated() { stream <<< " " stream <<< "\(constraint.identifier.path)" <<< " @ " diff --git a/Sources/PackageGraph/PackageGraphLoader.swift b/Sources/PackageGraph/PackageGraphLoader.swift index 8cd15dbbfc6..098b0257c12 100644 --- a/Sources/PackageGraph/PackageGraphLoader.swift +++ b/Sources/PackageGraph/PackageGraphLoader.swift @@ -54,7 +54,7 @@ enum PackageGraphError: Swift.Error { case cycleDetected((path: [Manifest], cycle: [Manifest])) /// The product dependency not found. - case productDependencyNotFound(name: String, package: String?) + case productDependencyNotFound(name: String, target: String) /// The product dependency was found but the package name did not match. case productDependencyIncorrectPackage(name: String, package: String) @@ -74,8 +74,8 @@ extension PackageGraphError: CustomStringConvertible { (cycle.path + cycle.cycle).map({ $0.name }).joined(separator: " -> ") + " -> " + cycle.cycle[0].name - case .productDependencyNotFound(let name, _): - return "product dependency '\(name)' not found" + case .productDependencyNotFound(let name, let target): + return "Product '\(name)' not found. It is required by target '\(target)'." case .productDependencyIncorrectPackage(let name, let package): return "product dependency '\(name)' in package '\(package)' not found" @@ -346,7 +346,7 @@ private func createResolvedPackages( // found errors when there are more important errors to // resolve (like authentication issues). if !diagnostics.hasErrors { - let error = PackageGraphError.productDependencyNotFound(name: productRef.name, package: productRef.package) + let error = PackageGraphError.productDependencyNotFound(name: productRef.name, target: targetBuilder.target.name) diagnostics.emit(error, location: diagnosticLocation()) } continue diff --git a/Sources/PackageLoading/Diagnostics.swift b/Sources/PackageLoading/Diagnostics.swift index 8dc61d745ef..e2bf78c174a 100644 --- a/Sources/PackageLoading/Diagnostics.swift +++ b/Sources/PackageLoading/Diagnostics.swift @@ -21,14 +21,13 @@ public enum PackageBuilderDiagnostics { name: "org.swift.diags.pkg-builder.nosources", defaultBehavior: .warning, description: { - $0 <<< "target" <<< { "'\($0.target)'" } - $0 <<< "in package" <<< { "'\($0.package)'" } - $0 <<< "contains no valid source files" + $0 <<< "Source files for target" <<< { "\($0.target)" } + $0 <<< "should be located under" <<< { "\($0.targetPath)" } } ) - /// The name of the package. - public let package: String + /// The path of the target. + public let targetPath: String /// The name of the target which has no sources. public let target: String diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 409e302993f..317266067b6 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -24,8 +24,8 @@ public enum ModuleError: Swift.Error { /// Indicates two targets with the same name and their corresponding packages. case duplicateModule(String, [String]) - /// One or more referenced targets could not be found. - case modulesNotFound([String]) + /// The eferenced target could not be found. + case moduleNotFound(String) /// Invalid custom path. case invalidCustomPath(target: String, path: String) @@ -67,9 +67,8 @@ extension ModuleError: CustomStringConvertible { case .duplicateModule(let name, let packages): let packages = packages.joined(separator: ", ") return "multiple targets named '\(name)' in: \(packages)" - case .modulesNotFound(let targets): - let targets = targets.joined(separator: ", ") - return "could not find source files for target(s): \(targets); use the 'path' property in the Swift 4 manifest to set a custom target path" + case .moduleNotFound(let target): + return "Source files for target \(target) should be located under 'Sources/\(target)', or a custom sources path can be set with the 'path' property in Package.swift" case .invalidLayout(let type): return "package has unsupported layout; \(type)" case .invalidManifestConfig(let package, let message): @@ -456,7 +455,7 @@ public final class PackageBuilder { if fileSystem.isDirectory(path) { return path } - throw ModuleError.modulesNotFound([target.name]) + throw ModuleError.moduleNotFound(target.name) } // Create potential targets. @@ -474,8 +473,8 @@ public final class PackageBuilder { let allReferencedModules = manifest.allReferencedModules() let potentialModulesName = Set(potentialModules.map({ $0.name })) let missingModules = allReferencedModules.subtracting(potentialModulesName).intersection(allReferencedModules) - guard missingModules.isEmpty else { - throw ModuleError.modulesNotFound(missingModules.map({ $0 })) + if let missingModule = missingModules.first { + throw ModuleError.moduleNotFound(missingModule) } let targetItems = manifest.targets.map({ ($0.name, $0 as TargetDescription) }) @@ -562,7 +561,7 @@ public final class PackageBuilder { targets[createdTarget.name] = createdTarget } else { emptyModules.insert(potentialModule.name) - diagnostics.emit(data: PackageBuilderDiagnostics.NoSources(package: manifest.name, target: potentialModule.name)) + diagnostics.emit(data: PackageBuilderDiagnostics.NoSources(targetPath: potentialModule.path.pathString, target: potentialModule.name)) } } return targets.values.map({ $0 }) diff --git a/Sources/PackageModel/Package.swift b/Sources/PackageModel/Package.swift index 69fb7660a32..bab1e4376c3 100644 --- a/Sources/PackageModel/Package.swift +++ b/Sources/PackageModel/Package.swift @@ -94,7 +94,7 @@ extension Package.Error: CustomStringConvertible { public var description: String { switch self { case .noManifest(let baseURL, let version): - var string = "\(baseURL) has no manifest" + var string = "\(baseURL) has no Package.swift manifest" if let version = version { string += " for version \(version)" } diff --git a/Sources/Workspace/Diagnostics.swift b/Sources/Workspace/Diagnostics.swift index 0c5ba45596f..bbf28f1fc65 100644 --- a/Sources/Workspace/Diagnostics.swift +++ b/Sources/Workspace/Diagnostics.swift @@ -82,7 +82,7 @@ public enum ResolverDiagnostics { type: Unsatisfiable.self, name: "org.swift.diags.resolver.unsatisfiable", description: { - $0 <<< "dependency graph is unresolvable;" + $0 <<< "the package dependency graph could not be resolved;" $0 <<< .substitution({ let `self` = $0 as! Unsatisfiable @@ -90,18 +90,13 @@ public enum ResolverDiagnostics { if self.dependencies.isEmpty && self.pins.isEmpty { return "" } - var diag = "found these conflicting requirements:" + var diag = "possibly because of these requirements:" let indent = " " if !self.dependencies.isEmpty { - diag += "\n\nDependencies: \n" diag += self.dependencies.map({ indent + Unsatisfiable.toString($0) }).joined(separator: "\n") } - if !self.pins.isEmpty { - diag += "\n\nPins: \n" - diag += self.pins.map({ indent + Unsatisfiable.toString($0) }).joined(separator: "\n") - } return diag }, preference: .default) } diff --git a/Tests/PackageGraphTests/PackageGraphTests.swift b/Tests/PackageGraphTests/PackageGraphTests.swift index d696b2381e1..4dbdfce7fac 100644 --- a/Tests/PackageGraphTests/PackageGraphTests.swift +++ b/Tests/PackageGraphTests/PackageGraphTests.swift @@ -497,7 +497,7 @@ class PackageGraphTests: XCTestCase { ) DiagnosticsEngineTester(diagnostics) { result in - result.check(diagnostic: "target 'Bar' in package 'Bar' contains no valid source files", behavior: .warning) + result.check(diagnostic: "Source files for target Bar should be located under /Bar/Sources/Bar", behavior: .warning) result.check(diagnostic: "target 'Bar' referenced in product 'Bar' could not be found", behavior: .error, location: "'Bar' /Bar") } } @@ -521,7 +521,7 @@ class PackageGraphTests: XCTestCase { ) DiagnosticsEngineTester(diagnostics) { result in - result.check(diagnostic: "product dependency 'Barx' not found", behavior: .error, location: "'Foo' /Foo") + result.check(diagnostic: "Product 'Barx' not found. It is required by target 'Foo'.", behavior: .error, location: "'Foo' /Foo") } } diff --git a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift index 30258ccc6cc..df96e97c2e5 100644 --- a/Tests/PackageLoadingTests/PD4_2LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD4_2LoadingTests.swift @@ -420,7 +420,7 @@ class PackageDescription4_2LoadingTests: XCTestCase { try loadManifestThrowing(stream.bytes) { _ in } XCTFail("Unexpected success") } catch ManifestParseError.runtimeManifestErrors(let errors) { - XCTAssertEqual(errors, ["Invalid version string: 1.0,0"]) + XCTAssertEqual(errors, ["Invalid semantic version string '1.0,0'"]) } } diff --git a/Tests/PackageLoadingTests/PackageBuilderTests.swift b/Tests/PackageLoadingTests/PackageBuilderTests.swift index 1a8f0076d5d..5c8f492df48 100644 --- a/Tests/PackageLoadingTests/PackageBuilderTests.swift +++ b/Tests/PackageLoadingTests/PackageBuilderTests.swift @@ -734,7 +734,7 @@ class PackageBuilderTests: XCTestCase { ] ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("could not find source files for target(s): Random; use the 'path' property in the Swift 4 manifest to set a custom target path") + result.checkDiagnostic("Source files for target Random should be located under 'Sources/Random', or a custom sources path can be set with the 'path' property in Package.swift") } } @@ -749,7 +749,7 @@ class PackageBuilderTests: XCTestCase { ] ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("could not find source files for target(s): Foo; use the 'path' property in the Swift 4 manifest to set a custom target path") + result.checkDiagnostic("Source files for target Foo should be located under 'Sources/Foo', or a custom sources path can be set with the 'path' property in Package.swift") } } @@ -779,7 +779,7 @@ class PackageBuilderTests: XCTestCase { ] ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("could not find source files for target(s): foo; use the 'path' property in the Swift 4 manifest to set a custom target path") + result.checkDiagnostic("Source files for target foo should be located under 'Sources/foo', or a custom sources path can be set with the 'path' property in Package.swift") } } @@ -829,7 +829,7 @@ class PackageBuilderTests: XCTestCase { ] ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("target 'pkg2' in package 'pkg' contains no valid source files") + result.checkDiagnostic("Source files for target pkg2 should be located under /Sources/pkg2") result.checkModule("pkg1") { moduleResult in moduleResult.check(c99name: "pkg1", type: .library) moduleResult.checkSources(root: "/Sources/pkg1", paths: "Foo.swift") @@ -1058,7 +1058,7 @@ class PackageBuilderTests: XCTestCase { ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("could not find source files for target(s): Bar; use the 'path' property in the Swift 4 manifest to set a custom target path") + result.checkDiagnostic("Source files for target Bar should be located under 'Sources/Bar', or a custom sources path can be set with the 'path' property in Package.swift") } } @@ -1077,7 +1077,7 @@ class PackageBuilderTests: XCTestCase { ] ) PackageBuilderTester(manifest, in: fs) { result in - result.checkDiagnostic("could not find source files for target(s): BarTests; use the 'path' property in the Swift 4 manifest to set a custom target path") + result.checkDiagnostic("Source files for target BarTests should be located under 'Sources/BarTests', or a custom sources path can be set with the 'path' property in Package.swift") } // We should be able to fix this by using custom paths. diff --git a/Tests/WorkspaceTests/WorkspaceTests.swift b/Tests/WorkspaceTests/WorkspaceTests.swift index 8bdb0bb4cf2..f97ef3f4653 100644 --- a/Tests/WorkspaceTests/WorkspaceTests.swift +++ b/Tests/WorkspaceTests/WorkspaceTests.swift @@ -743,7 +743,7 @@ final class WorkspaceTests: XCTestCase { ] workspace.checkPackageGraph(deps: deps) { (_, diagnostics) in DiagnosticsEngineTester(diagnostics) { result in - result.check(diagnostic: .contains("dependency graph is unresolvable;"), behavior: .error) + result.check(diagnostic: .contains("the package dependency graph could not be resolved; possibly because of these requirements"), behavior: .error) } } // There should be no extra fetches. From 85cfe06bccf39b35b000ddb11520b70e695d9a87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Boris=20B=C3=BCgling?= Date: Fri, 3 May 2019 15:36:35 -0700 Subject: [PATCH 21/67] Move code for finding test targets into `PackageGraph` (#2109) Other clients might also want to know which test targets are relevant for a particular executable target. rdar://problem/47648572 --- Sources/PackageGraph/PackageGraph.swift | 32 ++++++++++++++++++++++++ Sources/Xcodeproj/SchemesGenerator.swift | 21 +++------------- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/Sources/PackageGraph/PackageGraph.swift b/Sources/PackageGraph/PackageGraph.swift index 5487dfbbe07..13941826004 100644 --- a/Sources/PackageGraph/PackageGraph.swift +++ b/Sources/PackageGraph/PackageGraph.swift @@ -101,4 +101,36 @@ public struct PackageGraph { self.reachableTargets = reachableTargets self.reachableProducts = reachableProducts } + + /// Computes a map from each executable target in any of the root packages to the corresponding test targets. + public func computeTestTargetsForExecutableTargets() -> [ResolvedTarget: [ResolvedTarget]] { + var result = [ResolvedTarget: [ResolvedTarget]]() + + let rootTargets = rootPackages.map({ $0.targets }).flatMap({ $0 }) + + // Create map of test target to set of its direct dependencies. + let testTargetDepMap: [ResolvedTarget: Set] = { + let testTargetDeps = rootTargets.filter({ $0.type == .test }).map({ + ($0, Set($0.dependencies.compactMap({ $0.target }))) + }) + return Dictionary(uniqueKeysWithValues: testTargetDeps) + }() + + for target in rootTargets where target.type == .executable { + // Find all dependencies of this target within its package. + let dependencies = try! topologicalSort(target.dependencies, successors: { + $0.dependencies.compactMap({ $0.target }).map(ResolvedTarget.Dependency.target) + }).compactMap({ $0.target }) + + // Include the test targets whose dependencies intersect with the + // current target's (recursive) dependencies. + let testTargets = testTargetDepMap.filter({ (testTarget, deps) in + !deps.intersection(dependencies + [target]).isEmpty + }).map({ $0.key }) + + result[target] = testTargets + } + + return result + } } diff --git a/Sources/Xcodeproj/SchemesGenerator.swift b/Sources/Xcodeproj/SchemesGenerator.swift index 7eeaaeebe35..10ebd02dc6b 100644 --- a/Sources/Xcodeproj/SchemesGenerator.swift +++ b/Sources/Xcodeproj/SchemesGenerator.swift @@ -63,31 +63,16 @@ final class SchemesGenerator { var schemes: [Scheme] = [] - // Create map of test target to set of its direct dependencies. - let testTargetDepMap: [ResolvedTarget: Set] = { - let testTargetDeps = rootPackage.targets.filter({ $0.type == .test }).map({ - ($0, Set($0.dependencies.compactMap({ $0.target }))) - }) - return Dictionary(uniqueKeysWithValues: testTargetDeps) - }() + let testTargetsMap = graph.computeTestTargetsForExecutableTargets() // Create one scheme per executable target. for target in rootPackage.targets where target.type == .executable { - // Find all dependencies of this target within its package. - let dependencies = try! topologicalSort(target.dependencies, successors: { - $0.dependencies.compactMap({ $0.target }).map(ResolvedTarget.Dependency.target) - }).compactMap({ $0.target }) - - // Include the test targets whose dependencies intersect with the - // current target's (recursive) dependencies. - let testTargets = testTargetDepMap.filter({ (testTarget, deps) in - !deps.intersection(dependencies + [target]).isEmpty - }).map({ $0.key }) + let testTargets = testTargetsMap[target] schemes.append(Scheme( name: target.name, regularTargets: [target], - testTargets: testTargets + testTargets: testTargets ?? [] )) } From 760f985e03d764c93c4e148cab9a65741a727f93 Mon Sep 17 00:00:00 2001 From: "Benjamin Scholtysik (Reimold)" Date: Mon, 6 May 2019 18:17:06 -0700 Subject: [PATCH 22/67] Use the plural form instead of the singular. --- Documentation/PackageDescriptionV4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/PackageDescriptionV4.md b/Documentation/PackageDescriptionV4.md index 67f15c2e5dc..2613981225b 100644 --- a/Documentation/PackageDescriptionV4.md +++ b/Documentation/PackageDescriptionV4.md @@ -239,7 +239,7 @@ let package = Package( ) ``` -The above manifest declares two target, `Foo` and `Bar`. `Bar` is a test target +The above manifest declares two targets, `Foo` and `Bar`. `Bar` is a test target which depends on `Foo`. The Package Manager will automatically search for the targets inside package in the [predefined search paths](#target-format-reference). From c82d593ea3e44622dbf7776c21d77620848653cb Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Tue, 7 May 2019 14:23:52 -0700 Subject: [PATCH 23/67] [bootstrap] Don't use global module cache when bootstrapping --- Utilities/bootstrap | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Utilities/bootstrap b/Utilities/bootstrap index 4d66ddd56c0..f78977d865a 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -228,6 +228,7 @@ class Target(object): link_input_nodes.append(compile_swift_node) other_args.extend(["-swift-version", "4"]) + other_args.extend(["-module-cache-path", os.path.join(args.sandbox_path, "ModuleCache")]) print(" %s:" % json.dumps(compile_swift_node), file=output) print(" tool: swift-compiler", file=output) @@ -285,6 +286,8 @@ class Target(object): link_input_nodes, predecessor_node): common_args = ["-fobjc-arc", "-fmodule-name=%s" % self.module_name()] + common_args.extend(["-fmodules-cache-path=%s" % os.path.join(args.sandbox_path, "ModuleCache")]) + if platform.system() == 'Darwin': common_args.extend(["-arch", "x86_64", "-mmacosx-version-min=10.10"]) @@ -1028,6 +1031,7 @@ def main(): build_path = os.path.join(g_project_root, args.build_path) sandbox_path = os.path.join(build_path, ".bootstrap") + args.sandbox_path = sandbox_path target_path = os.path.join(build_path, build_target) libdir = os.path.join(target_path, "lib") From 462ffa2afab2be983d7486efaff7a7c973a87497 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sat, 11 May 2019 10:55:53 -0700 Subject: [PATCH 24/67] Update the doc comments for the PackageDescription API --- .../PackageDescription4/BuildSettings.swift | 189 ++++++++++++++++-- Sources/PackageDescription4/Package.swift | 95 ++++++++- .../PackageDependency.swift | 60 +++++- .../PackageRequirement.swift | 56 +++++- Sources/PackageDescription4/Product.swift | 68 ++++++- .../SupportedPlatforms.swift | 154 ++++++++++++-- Sources/PackageDescription4/Target.swift | 95 ++++++++- .../Version+StringLiteralConvertible.swift | 2 +- Sources/PackageDescription4/Version.swift | 29 ++- 9 files changed, 697 insertions(+), 51 deletions(-) diff --git a/Sources/PackageDescription4/BuildSettings.swift b/Sources/PackageDescription4/BuildSettings.swift index 7d32602e65f..5cdcd490e1b 100644 --- a/Sources/PackageDescription4/BuildSettings.swift +++ b/Sources/PackageDescription4/BuildSettings.swift @@ -24,6 +24,30 @@ public struct BuildConfiguration: Encodable { } /// A build setting condition. +/// +/// By default, build settings will be applicable for all platforms and build +/// configurations. The `.when` modifier can be used to conditionalize a build +/// setting. Invalid usage of `.when` will cause an error to be emitted during +/// manifest parsing. For example, it is invalid to specify a `.when` condition with +/// both parameters as `nil`. +/// +/// Here is an example usage of build setting conditions with various APIs: +/// +/// ... +/// .target( +/// name: "MyTool", +/// dependencies: ["Utility"], +/// cSettings: [ +/// .headerSearchPath("path/relative/to/my/target"), +/// .define("DISABLE_SOMETHING", .when(platforms: [.iOS], configuration: .release)), +/// ], +/// swiftSettings: [ +/// .define("ENABLE_SOMETHING", .when(configuration: .release)), +/// ], +/// linkerSettings: [ +/// .linkLibrary("openssl", .when(platforms: [.linux])), +/// ] +/// ), public struct BuildSettingCondition: Encodable { private let platforms: [Platform]? @@ -37,11 +61,15 @@ public struct BuildSettingCondition: Encodable { /// Create a build setting condition. /// /// At least one parameter is mandatory. + /// + /// - Parameters: + /// - platforms: The platforms for which this condition will be applied. + /// - configuration: The build configuration for which this condition will be applied. public static func when( platforms: [Platform]? = nil, configuration: BuildConfiguration? = nil ) -> BuildSettingCondition { - // FIXME: This should be an error not a precondition. + // FIXME: This should be an error, not a precondition. precondition(!(platforms == nil && configuration == nil)) return BuildSettingCondition(platforms: platforms, config: configuration) } @@ -56,7 +84,7 @@ fileprivate struct BuildSettingData: Encodable { /// The value of the build setting. let value: [String] - /// The condition at which the build setting should be applied. + /// A condition which will restrict when the build setting applies. let condition: BuildSettingCondition? } @@ -68,14 +96,32 @@ public struct CSetting: Encodable { self.data = BuildSettingData(name: name, value: value, condition: condition) } - /// Provide a header search path relative to the target's root directory. + /// Provide a header search path relative to the target's directory. + /// + /// Use this setting to add a search path for headers within your target. + /// Absolute paths are disallowed and this setting can't be used to provide + /// headers that are visible to other targets. + /// + /// The path must be a directory inside the package. + /// + /// - Since: First available in PackageDescription 5.0 /// - /// The path must not escape the package boundary. + /// - Parameters: + /// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. + /// - condition: A condition which will restrict when the build setting applies. public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CSetting { return CSetting(name: "headerSearchPath", value: [path], condition: condition) } - /// Define macro to a value (or 1 if the value is omitted). + /// Defines a value for a macro. If no value is specified, the macro value will + /// be defined as 1. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - name: The name of the macro. + /// - value: The value of the macro. + /// - condition: A condition which will restrict when the build setting applies. public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CSetting { var settingValue = name if let value = value { @@ -84,7 +130,22 @@ public struct CSetting: Encodable { return CSetting(name: "define", value: [settingValue], condition: condition) } - /// Set the given unsafe flags. + /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. + /// + /// As the usage of the word "unsafe" implies, the Swift Package Manager + /// can't safely determine if the build flags will have any negative + /// side-effect to the build since certain flags can change the behavior of + /// how a build is performed. + /// + /// As some build flags could be exploited for unsupported or malicious + /// behavior, the use of unsafe flags make the products containing this + /// target ineligible to be used by other packages. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - flags: The flags to set. + /// - condition: A condition which will restrict when the build setting applies. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CSetting { return CSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -100,12 +161,30 @@ public struct CXXSetting: Encodable { /// Provide a header search path relative to the target's root directory. /// - /// The path must not escape the package boundary. + /// Use this setting to add a search path for headers within your target. + /// Absolute paths are disallowed and this setting can't be used to provide + /// headers that are visible to other targets. + /// + /// The path must be a directory inside the package. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. + /// - condition: A condition which will restrict when the build setting applies. public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CXXSetting { return CXXSetting(name: "headerSearchPath", value: [path], condition: condition) } - /// Define macro to a value (or 1 if the value is omitted). + /// Defines a value for a macro. If no value is specified, the macro value will + /// be defined as 1. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - name: The name of the macro. + /// - value: The value of the macro. + /// - condition: A condition which will restrict when the build setting applies. public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CXXSetting { var settingValue = name if let value = value { @@ -114,7 +193,22 @@ public struct CXXSetting: Encodable { return CXXSetting(name: "define", value: [settingValue], condition: condition) } - /// Set the given unsafe flags. + /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. + /// + /// As the usage of the word "unsafe" implies, the Swift Package Manager + /// can't safely determine if the build flags will have any negative + /// side-effect to the build since certain flags can change the behavior of + /// how a build is performed. + /// + /// As some build flags could be exploited for unsupported or malicious + /// behavior, the use of unsafe flags make the products containing this + /// target ineligible to be used by other packages. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - flags: The flags to set. + /// - condition: A condition which will restrict when the build setting applies. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CXXSetting { return CXXSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -128,12 +222,44 @@ public struct SwiftSetting: Encodable { self.data = BuildSettingData(name: name, value: value, condition: condition) } - /// Marks the given conditional compilation flag as true. + /// Define a compilation condition. + /// + /// Compilation conditons are used inside to conditionally compile + /// statements. For example, the Swift compiler will only compile the + /// statements inside the `#if` block when `ENABLE_SOMETHING` is defined: + /// + /// #if ENABLE_SOMETHING + /// ... + /// #endif + /// + /// Unlike macros in C/C++, compilation conditions don't have an + /// associated value. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - name: The name of the macro. + /// - condition: A condition which will restrict when the build setting applies. public static func define(_ name: String, _ condition: BuildSettingCondition? = nil) -> SwiftSetting { return SwiftSetting(name: "define", value: [name], condition: condition) } - /// Set the given unsafe flags. + /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. + /// + /// As the usage of the word "unsafe" implies, the Swift Package Manager + /// can't safely determine if the build flags will have any negative + /// side-effect to the build since certain flags can change the behavior of + /// how a build is performed. + /// + /// As some build flags could be exploited for unsupported or malicious + /// behavior, the use of unsafe flags make the products containing this + /// target ineligible to be used by other packages. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - flags: The flags to set. + /// - condition: A condition which will restrict when the build setting applies. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> SwiftSetting { return SwiftSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -147,17 +273,52 @@ public struct LinkerSetting: Encodable { self.data = BuildSettingData(name: name, value: value, condition: condition) } - /// Link a system library. + /// Declare linkage to a system library. + /// + /// This setting is most useful when the library can't be linked + /// automatically (for example, C++ based libraries and non-modular + /// libraries). + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - library: The library name. + /// - condition: A condition which will restrict when the build setting applies. public static func linkedLibrary(_ library: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "linkedLibrary", value: [library], condition: condition) } - /// Link a system framework. + /// Declare linkage to a framework. + /// + /// This setting is most useful when the framework can't be linked + /// automatically (for example, C++ based frameworks and non-modular + /// frameworks). + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - framework: The framework name. + /// - condition: A condition which will restrict when the build setting applies. public static func linkedFramework(_ framework: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "linkedFramework", value: [framework], condition: condition) } - /// Set the given unsafe flags. + /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. + /// + /// As the usage of the word "unsafe" implies, the Swift Package Manager + /// can't safely determine if the build flags will have any negative + /// side-effect to the build since certain flags can change the behavior of + /// how a build is performed. + /// + /// As some build flags could be exploited for unsupported or malicious + /// behavior, the use of unsafe flags make the products containing this + /// target ineligible to be used by other packages. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameters: + /// - flags: The flags to set. + /// - condition: A condition which will restrict when the build setting applies. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "unsafeFlags", value: flags, condition: condition) } diff --git a/Sources/PackageDescription4/Package.swift b/Sources/PackageDescription4/Package.swift index a037c9b5768..76bae326531 100644 --- a/Sources/PackageDescription4/Package.swift +++ b/Sources/PackageDescription4/Package.swift @@ -17,13 +17,98 @@ import ucrt #endif import Foundation -/// The description for a complete package. +/// The `Package` type is used to configure the name, products, targets, +/// dependencies and various other parts of the package. +/// +/// By convention, the properties of a `Package` are defined in a single nested +/// initializer statement, and not modified after initialization. For example: +/// +/// // swift-tools-version:5.0 +/// import PackageDesc ription +/// +/// let package = Package( +/// name: "MyLibrary", +/// platforms: [ +/// .macOS(.v10_14), +/// ], +/// products: [ +/// .library(name: "MyLibrary", targets: ["MyLibrary"]), +/// ], +/// dependencies: [ +/// .package(url: "https://url/of/another/package/named/Utility", from: "1.0.0"), +/// ], +/// targets: [ +/// .target(name: "MyLibrary", dependencies: ["Utility"]), +/// .testTarget(name: "MyLibraryTests", dependencies: ["MyLibrary"]), +/// ] +/// ) +/// +/// # About the Swift Tools Version +/// +/// A Package.swift manifest file must begin with the string `// +/// swift-tools-version:` followed by a version number specifier. +/// +/// Examples: +/// +/// // swift-tools-version:3.0.2 +/// // swift-tools-version:3.1 +/// // swift-tools-version:4.0 +/// // swift-tools-version:5.0 +/// +/// The Swift tools version declares the version of the `PackageDescription` +/// library, the minimum version of the Swift tools and Swift language +/// compatibility version to process the manifest, and the minimum version of the +/// Swift tools that are needed to use the Swift package. Each version of Swift +/// can introduce updates to the `PackageDescription` library, but the previous +/// API version will continue to be available to packages which declare a prior +/// tools version. This behavior lets you take advantage of new releases of +/// Swift, the Swift tools, and the `PackageDescription` library, without having +/// to update your package's manifest or losing access to existing packages. public final class Package { - /// Represents a package dependency. - public class Dependency: Encodable { - - /// The dependency requirement. + /// A package dependency consists of a Git URL to the source of the package, + /// and a requirement for the version of the package that can be used. + /// + /// The Swift Package Manager performs a process called dependency resolution to + /// figure out the exact version of the package dependencies that can be used in + /// your package. The results of the dependency resolution are recorded in the + /// `Package.resolved` file which will be placed in the top-level directory of + /// your package. + public class Dependency: Encodable { + + /// The dependency requirement can be defined as one of three different version requirements. + /// + /// 1. Version-based Requirement + /// + /// A requirement which restricts what version of a dependency your + /// package can use based on its available versions. When a new package + /// version is published, it should increment the major version component + /// if it has backwards-incompatible changes. It should increment the + /// minor version component if it adds new functionality in + /// a backwards-compatible manner. And it should increment the patch + /// version if it makes backwards-compatible bugfixes. To learn more about + /// the syntax of semantic versioning syntax, see `Version` or visit + /// https://semver.org (https://semver.org/). + /// + /// 2. Branch-based Requirement + /// + /// Specify the name of a branch that a dependency will follow. This is + /// useful when developing multiple packages which are closely related, + /// allowing you to keep them in sync during development. Note that + /// packages which use branch-based dependency requirements cannot be + /// depended-upon by packages which use version-based dependency + /// requirements; you should remove branch-based dependency requirements + /// before publishing a version of your package. + /// + /// 3. Commit-based Requirement + /// + /// A requirement that restricts a dependency to a specific commit + /// hash. This is useful if you want to pin your package to a specific + /// commit hash of a dependency. Note that packages which use + /// commit-based dependency requirements cannot be depended-upon by + /// packages which use version-based dependency requirements; you + /// should remove commit-based dependency requirements before + /// publishing a version of your package. public enum Requirement { #if PACKAGE_DESCRIPTION_4 case exactItem(Version) diff --git a/Sources/PackageDescription4/PackageDependency.swift b/Sources/PackageDescription4/PackageDependency.swift index a1028b34cce..5c8a64fbdd6 100644 --- a/Sources/PackageDescription4/PackageDependency.swift +++ b/Sources/PackageDescription4/PackageDependency.swift @@ -10,8 +10,25 @@ extension Package.Dependency { - // Add a dependency starting from a minimum version, going upto the next - // major version. + /// Add a package dependency that is required from the given minimum version, + /// going up to the next major version. + /// + /// This is the recommend way to specify a remote package dependency because + /// it allows you to specify the minimum version you require and gives + /// explicit opt-in for new major versions, but otherwise provides maximal + /// flexibility on which version is used. This helps to prevent conflicts in + /// your package dependency graph. + /// + /// For example, specifying + /// + /// .package(url: "https://example.com/example-package.git", from: "1.2.3"), + /// + /// will allow the Swift package manager to select a version like a "1.2.3", + /// "1.2.4" or "1.3.0" but not "2.0.0". + /// + /// - Parameters: + /// - url: The valid Git URL of the package. + /// - version: The minimum version requirement. public static func package( url: String, from version: Version @@ -19,7 +36,11 @@ extension Package.Dependency { return .package(url: url, .upToNextMajor(from: version)) } - // Add a dependency given a requirement. + /// Add a remote package dependency given a version requirement. + /// + /// - Parameters: + /// - url: The valid Git URL of the package. + /// - requirement: A dependency requirement. See static methods on `Package.Dependency.Requirement` for available options. public static func package( url: String, _ requirement: Package.Dependency.Requirement @@ -28,7 +49,18 @@ extension Package.Dependency { return .init(url: url, requirement: requirement) } - // Add a dependency given a range requirement. + /// Add a package dependency starting with a specific minimum version, up to + // but not including a specific maximum version. + /// + /// For example + /// + /// .package(url: "https://example.com/example-package.git", "1.2.3"..<"1.2.6"), + /// + /// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, but not 1.2.6. + /// + /// - Parameters: + /// - url: The valid Git URL of the package. + /// - range: The custom version range requirement. public static func package( url: String, _ range: Range @@ -40,7 +72,18 @@ extension Package.Dependency { #endif } - // Add a dependency given a closed range requirement. + /// Add a package dependency starting with a specific minimum version, going + /// up to and including a specific maximum version. + /// + /// For example + /// + /// .package(url: "https://example.com/example-package.git", "1.2.3"..."1.2.6"), + /// + /// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, as well as 1.2.6. + /// + /// - Parameters: + /// - url: The valid Git URL of the package. + /// - range: The closed version range requirement. public static func package( url: String, _ range: ClosedRange @@ -56,6 +99,13 @@ extension Package.Dependency { #if !PACKAGE_DESCRIPTION_4 /// Add a dependency to a local package on the filesystem. + /// + /// The package dependency is used as-is and no source control access is + /// performed. Local package dependencies are especially useful during + /// development of a new package or when working on multiple tightly-coupled + /// packages. + /// + /// - Parameter path: The path of the package. public static func package( path: String ) -> Package.Dependency { diff --git a/Sources/PackageDescription4/PackageRequirement.swift b/Sources/PackageDescription4/PackageRequirement.swift index d1e0826b523..1e96a29a2c9 100644 --- a/Sources/PackageDescription4/PackageRequirement.swift +++ b/Sources/PackageDescription4/PackageRequirement.swift @@ -10,7 +10,18 @@ extension Package.Dependency.Requirement: Encodable { - /// The requirement is specified by an exact version. + /// Returns a requirement for the given exact version. + /// + /// Specifying exact version requirements are usually not recommended, as + /// they can cause conflicts in your package dependency graph when a package + /// is depended on by multiple other packages. + /// + /// Example: + /// + /// .exact("1.2.3") + /// + /// - Parameters: + /// - version: The exact version to be specified. public static func exact(_ version: Version) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .exactItem(version) @@ -19,7 +30,20 @@ extension Package.Dependency.Requirement: Encodable { #endif } - /// The requirement is specified by a source control revision. + /// Returns a requirement for a source control revision. This is usually + /// specified with the hash of a commit. + /// + /// Note that packages which use commit-based dependency requirements + /// cannot be depended-upon by packages which use version-based dependency + /// requirements; you should remove commit-based dependency requirements + /// before publishing a version of your package. + /// + /// Example: + /// + /// .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021") + /// + /// - Parameters: + /// - ref: The Git revision, usually a hash of the commit. public static func revision(_ ref: String) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .revisionItem(ref) @@ -28,7 +52,19 @@ extension Package.Dependency.Requirement: Encodable { #endif } - /// The requirement is specified by a source control branch. + /// Returns a requirement for a source control branch. + /// + /// Note that packages which use branch-based dependency requirements + /// cannot be depended-upon by packages which use version-based dependency + /// requirements; you should remove branch-based dependency requirements + /// before publishing a version of your package. + /// + /// Example: + /// + /// .branch("develop") + /// + /// - Parameters: + /// - name: The name of the branch. public static func branch(_ name: String) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .branchItem(name) @@ -37,8 +73,11 @@ extension Package.Dependency.Requirement: Encodable { #endif } - /// Creates a specified for a range starting at the given lower bound - /// and going upto next major version. + /// Returns a requirement for a version range, starting at the given minimum + /// version and going up to the next major version. + /// + /// - Parameters: + /// - version: The minimum version for the version range. public static func upToNextMajor(from version: Version) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .rangeItem(version.. Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .rangeItem(version.. SupportedPlatform { return SupportedPlatform(platform: .macOS, version: version.version) } - /// Create macOS supported platform with the given version string. + /// Configure the minimum deployment target version for the macOS platform + /// using a custom version string. + /// + /// The version string must be a series of 2 or 3 dot-separated integers, for + /// example "10.10" or "10.10.1". + /// + /// - Since: First available in PackageDescription 5.0 /// - /// The version string must be a series of 2 or 3 dot-separated integers, for example "10.10" or "10.10.1". + /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "10.10.1". public static func macOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .macOS, version: SupportedPlatform.MacOSVersion(string: versionString).version) } - /// Create iOS supported platform with the given version. + /// Configure the minimum deployment target version for the iOS platform. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameter version: The minimum deployment target that the package supports. public static func iOS(_ version: SupportedPlatform.IOSVersion) -> SupportedPlatform { return SupportedPlatform(platform: .iOS, version: version.version) } - /// Create iOS supported platform with the given version string. + /// Configure the minimum deployment target version for the iOS platform + /// using a custom version string. + /// + /// The version string must be a series of 2 or 3 dot-separated integers, for + /// example "8.0" or "8.0.1". + /// + /// - Since: First available in PackageDescription 5.0 /// - /// The version string must be a series of 2 or 3 dot-separated integers, for example "8.0" or "8.0.1". + /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "8.0.1". public static func iOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .iOS, version: SupportedPlatform.IOSVersion(string: versionString).version) } - /// Create tvOS supported platform with the given version. + /// Configure the minimum deployment target version for the tvOS platform. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameter version: The minimum deployment target that the package supports. public static func tvOS(_ version: SupportedPlatform.TVOSVersion) -> SupportedPlatform { return SupportedPlatform(platform: .tvOS, version: version.version) } - /// Create tvOS supported platform with the given version string. + /// Configure the minimum deployment target version for the tvOS platform + /// using a custom version string. + /// + /// The version string must be a series of 2 or 3 dot-separated integers, for + /// example "9.0" or "9.0.1". + /// + /// - Since: First available in PackageDescription 5.0 /// - /// The version string must be a series of 2 or 3 dot-separated integers, for example "9.0" or "9.0.1". + /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "9.0.1". public static func tvOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .tvOS, version: SupportedPlatform.TVOSVersion(string: versionString).version) } - /// Create watchOS supported platform with the given version. + /// Configure the minimum deployment target version for the watchOS platform. + /// + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameter version: The minimum deployment target that the package supports. public static func watchOS(_ version: SupportedPlatform.WatchOSVersion) -> SupportedPlatform { return SupportedPlatform(platform: .watchOS, version: version.version) } - /// Create watchOS supported platform with the given version string. + /// Configure the minimum deployment target version for the watchOS platform + /// using a custom version string. + /// + /// The version string must be a series of 2 or 3 dot-separated integers, for + /// example "2.0" or "2.0.1". /// - /// The version string must be a series of 2 or 3 dot-separated integers, for example "2.0" or "2.0.1". + /// - Since: First available in PackageDescription 5.0 + /// + /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "3.0.1". public static func watchOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .watchOS, version: SupportedPlatform.WatchOSVersion(string: versionString).version) } } +/// Extension to SupportedPlaftorm to define major platform versions. extension SupportedPlatform { /// The macOS version. public struct MacOSVersion: Encodable, AppleOSVersion { @@ -102,10 +162,29 @@ extension SupportedPlatform { self.version = version } + /// macOS 10.10 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10_10: MacOSVersion = .init(string: "10.10") + + /// macOS 10.11 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10_11: MacOSVersion = .init(string: "10.11") + + /// macOS 10.12 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10_12: MacOSVersion = .init(string: "10.12") + + /// macOS 10.13 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10_13: MacOSVersion = .init(string: "10.13") + + /// macOS 10.14 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10_14: MacOSVersion = .init(string: "10.14") } @@ -120,9 +199,24 @@ extension SupportedPlatform { self.version = version } + /// tvOS 9.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v9: TVOSVersion = .init(string: "9.0") + + /// tvOS 10.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10: TVOSVersion = .init(string: "10.0") + + /// tvOS 11.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v11: TVOSVersion = .init(string: "11.0") + + /// tvOS 12.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v12: TVOSVersion = .init(string: "12.0") } @@ -137,10 +231,29 @@ extension SupportedPlatform { self.version = version } + /// iOS 8.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v8: IOSVersion = .init(string: "8.0") + + /// iOS 9.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v9: IOSVersion = .init(string: "9.0") + + /// iOS 10.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v10: IOSVersion = .init(string: "10.0") + + /// iOS 11.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v11: IOSVersion = .init(string: "11.0") + + /// iOS 12.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v12: IOSVersion = .init(string: "12.0") } @@ -155,9 +268,24 @@ extension SupportedPlatform { self.version = version } + /// watchOS 2.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v2: WatchOSVersion = .init(string: "2.0") + + /// watchOS 3.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v3: WatchOSVersion = .init(string: "3.0") + + /// watchOS 4.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v4: WatchOSVersion = .init(string: "4.0") + + /// watchOS 5.0 + /// + /// - Since: First available in PackageDescription 5.0 public static let v5: WatchOSVersion = .init(string: "5.0") } } diff --git a/Sources/PackageDescription4/Target.swift b/Sources/PackageDescription4/Target.swift index ca125b756d5..53688b13d2f 100644 --- a/Sources/PackageDescription4/Target.swift +++ b/Sources/PackageDescription4/Target.swift @@ -8,7 +8,14 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// The description for an individual target. +/// Targets are the basic building blocks of a package. +/// +/// Each target contains a set of source files that are compiled into a module or +/// test suite. Targets can be vended to other packages by defining products that +/// include them. +/// +/// Targets may depend on targets within the same package and on products vended +/// by its package dependencies. public final class Target { /// The type of this target. @@ -36,8 +43,11 @@ public final class Target { /// The path of the target, relative to the package root. /// - /// If nil, package manager will search the predefined paths to look - /// for this target. + /// If nil, a directory with the target's name will be searched in the + /// predefined search paths. The predefined search paths are the following + /// directories under the package root: + /// - for regular targets: Sources, Source, src, srcs + /// - for test targets: Tests, Sources, Source, src, srcs public var path: String? /// The source files in this target. @@ -149,6 +159,22 @@ public final class Target { } } + /// Create a library or executable target. + // + /// A target can either contain Swift or C-family source files. You cannot + /// mix Swift and C-family source files within a target. A target is + /// considered to be an executable target if there is a `main.swift`, + /// `main.m`, `main.c` or `main.cpp` file in the target's directory. All + /// other targets are considered to be library targets. + /// + /// - Parameters: + /// - name: The name of the target. + /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from package dependencies. + /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. + /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. + /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. + /// - sources: An explicit list of source files. + /// - publicHeadersPath: The directory containing public headers of a C-family family library target. @available(_PackageDescription, introduced: 4, obsoleted: 5) public static func target( name: String, @@ -169,6 +195,26 @@ public final class Target { ) } + /// Create a library or executable target. + // + /// A target can either contain Swift or C-family source files. You cannot + /// mix Swift and C-family source files within a target. A target is + /// considered to be an executable target if there is a `main.swift`, + /// `main.m`, `main.c` or `main.cpp` file in the target's directory. All + /// other targets are considered to be library targets. + /// + /// - Parameters: + /// - name: The name of the target. + /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from package dependencies. + /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. + /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. + /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. + /// - sources: An explicit list of source files. + /// - publicHeadersPath: The directory containing public headers of a C-family family library target. + /// - cSettings: The C settings for this target. + /// - cxxSettings: The C++ settings for this target. + /// - swiftSettings: The Swift settings for this target. + /// - linkerSettings: The linker settings for this target. @available(_PackageDescription, introduced: 5) public static func target( name: String, @@ -197,6 +243,18 @@ public final class Target { ) } + /// Create a test target. + /// + /// Test targets are written using the XCTest testing framework. Test targets + /// generally declare target dependency on the targets they test. + /// + /// - Parameters: + /// - name: The name of the target. + /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from other packages. + /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. + /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. + /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. + /// - sources: An explicit list of source files. @available(_PackageDescription, introduced: 4, obsoleted: 5) public static func testTarget( name: String, @@ -216,6 +274,22 @@ public final class Target { ) } + /// Create a test target. + /// + /// Test targets are written using the XCTest testing framework. Test targets + /// generally declare target dependency on the targets they test. + /// + /// - Parameters: + /// - name: The name of the target. + /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from other packages. + /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. + /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. + /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. + /// - sources: An explicit list of source files. + /// - cSettings: The C settings for this target. + /// - cxxSettings: The C++ settings for this target. + /// - swiftSettings: The Swift settings for this target. + /// - linkerSettings: The linker settings for this target. @available(_PackageDescription, introduced: 5) public static func testTarget( name: String, @@ -243,7 +317,22 @@ public final class Target { ) } + #if !PACKAGE_DESCRIPTION_4 + /// Create a system library target. + /// + /// System library targets are used to adapt a library installed on the system to + /// work with Swift packages. Such libraries are generally installed by system + /// package managers (such as Homebrew and APT) and exposed to Swift packages by + /// providing a modulemap file along with other metadata such as the library's + /// pkg-config name. + /// + /// - Parameters: + /// - name: The name of the target. + /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. + /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. + /// - pkgConfig: The name of the pkg-config file for this system library. + /// - providers: The providers for this system library. public static func systemLibrary( name: String, path: String? = nil, diff --git a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift index 8c35f1ebb63..7aeecee4784 100644 --- a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift +++ b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift @@ -15,7 +15,7 @@ extension Version: ExpressibleByStringLiteral { self.init(version) } else { // If version can't be initialized using the string literal, report - // the error and initialize with a dummy value. This is done to + // the error and initialize with a dummy value. This is done to // report error to the invoking tool (like swift build) gracefully // rather than just crashing. errors.append("Invalid semantic version string '\(value)'") diff --git a/Sources/PackageDescription4/Version.swift b/Sources/PackageDescription4/Version.swift index 563df5f0e1a..293bb8a68c4 100644 --- a/Sources/PackageDescription4/Version.swift +++ b/Sources/PackageDescription4/Version.swift @@ -8,7 +8,34 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// A struct representing a semver version. +/// A struct representing a Semantic Version. +/// +/// Semantic versioning is a specification that proposes a set of rules and +/// requirements that dictate how version numbers are assigned and incremented. +/// To learn more about the semantic versioning specification, visit +/// www.semver.org. +/// +/// # Semantic Versioning (SemVer) 2.0.0 +/// +/// ## The Major Version +/// +/// The major version signifies breaking changes to the API which requires +/// updating existing clients. For example, renaming an existing type, removing +/// a method or changing a method’s signature are considered breaking changes. +/// This also includes any backwards incompatible bugfixes or behaviour changes +/// of existing API. +/// +/// ## The Minor Version +/// +/// Update the minor version if functionality is added in a backward compatible +/// manner. For example, adding a new method or type without changing any other +/// API is considered backward-compatible. +/// +/// ## The Patch Version +/// +/// Increase the patch version if you are making a backward-compatible bugfix. +/// This allows clients to benefit from bugfixes to your package without +/// incurring any maintenance burden. public struct Version { /// The major version. From 1d90d1ac992602c3edf50e57389d9afce675ee9d Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sun, 12 May 2019 16:29:20 -0700 Subject: [PATCH 25/67] [Documentation] Update to latest API documentation This moves all of the API documentation to the PackageDescription.md file. --- Documentation/PackageDescription.md | 837 ++++++++++++++++++++++++ Documentation/PackageDescriptionV3.md | 18 +- Documentation/PackageDescriptionV4.md | 14 +- Documentation/PackageDescriptionV4_2.md | 14 +- Documentation/README.md | 4 +- Documentation/Resources.md | 4 +- Documentation/Usage.md | 4 +- 7 files changed, 847 insertions(+), 48 deletions(-) create mode 100644 Documentation/PackageDescription.md diff --git a/Documentation/PackageDescription.md b/Documentation/PackageDescription.md new file mode 100644 index 00000000000..668cf1bd6eb --- /dev/null +++ b/Documentation/PackageDescription.md @@ -0,0 +1,837 @@ +# Package + +The `Package` type is used to configure the name, products, targets, +dependencies and various other parts of the package. + +By convention, the properties of a `Package` are defined in a single nested +initializer statement, and not modified after initialization. For example: + +```swift +// swift-tools-version:5.0 +import PackageDescription + +let package = Package( + name: "MyLibrary", + platforms: [ + .macOS(.v10_14), + ], + products: [ + .library(name: "MyLibrary", targets: ["MyLibrary"]), + ], + dependencies: [ + .package(url: "https://url/of/another/package/named/Utility", from: "1.0.0"), + ], + targets: [ + .target(name: "MyLibrary", dependencies: ["Utility"]), + .testTarget(name: "MyLibraryTests", dependencies: ["MyLibrary"]), + ] +) +``` + +### Methods +
+Package(
+    name: String,
+    platforms: [SupportedPlatform]? = nil,
+    products: [Product] = [],
+    dependencies: [Package.Dependency] = [],
+    targets: [Target] = [],
+    swiftLanguageVersions: [SwiftVersion]? = nil,
+    cLanguageStandard: CLanguageStandard? = nil,
+    cxxLanguageStandard: CXXLanguageStandard? = nil
+)
+
+ +### About the Swift Tools Version + +A Package.swift manifest file must begin with the string `// +swift-tools-version:` followed by a version number specifier. + +Examples: + + // swift-tools-version:3.0.2 + // swift-tools-version:3.1 + // swift-tools-version:4.0 + // swift-tools-version:5.0 + +The Swift tools version declares the version of the `PackageDescription` +library, the minimum version of the Swift tools and Swift language +compatibility version to process the manifest, and the minimum version of the +Swift tools that are needed to use the Swift package. Each version of Swift +can introduce updates to the `PackageDescription` library, but the previous +API version will continue to be available to packages which declare a prior +tools version. This behavior lets you take advantage of new releases of +Swift, the Swift tools, and the `PackageDescription` library, without having +to update your package's manifest or losing access to existing packages. + +# SupportedPlatform + +Represents a platform supported by the package. + +By default, the Swift Package Manager assigns a predefined minimum deployment +version for each supported platforms unless configured using the `platforms` +API. This predefined deployment version will be the oldest deployment target +version supported by the installed SDK for a given platform. One exception +to this rule is macOS, for which the minimum deployment target version will +start from 10.10. Packages can choose to configure the minimum deployment +target version for a platform by using the APIs defined in this struct. The +Swift Package Manager will emit appropriate errors when an invalid value is +provided for supported platforms, i.e., an empty array, multiple declarations +for the same platform or an invalid version specification. + +The Swift Package Manager will emit an error if a dependency is not +compatible with the top-level package's deployment version; the deployment +target of dependencies must be lower than or equal to top-level package's +deployment target version for a particular platform. + +### Methods + +```swift +/// Configure the minimum deployment target version for the macOS platform. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter version: The minimum deployment target that the package supports. +static func macOS(_ version: SupportedPlatform.MacOSVersion) -> SupportedPlatform + +/// Configure the minimum deployment target version for the macOS platform +/// using a custom version string. +/// +/// The version string must be a series of 2 or 3 dot-separated integers, for +/// example "10.10" or "10.10.1". +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "10.10.1". +static func macOS(_ versionString: String) -> SupportedPlatform + +/// Configure the minimum deployment target version for the iOS platform. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter version: The minimum deployment target that the package supports. +static func iOS(_ version: SupportedPlatform.IOSVersion) -> SupportedPlatform + +/// Configure the minimum deployment target version for the iOS platform +/// using a custom version string. +/// +/// The version string must be a series of 2 or 3 dot-separated integers, for +/// example "8.0" or "8.0.1". +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "8.0.1". +static func iOS(_ versionString: String) -> SupportedPlatform + +/// Configure the minimum deployment target version for the tvOS platform. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter version: The minimum deployment target that the package supports. +static func tvOS(_ version: SupportedPlatform.TVOSVersion) -> SupportedPlatform + +/// Configure the minimum deployment target version for the tvOS platform +/// using a custom version string. +/// +/// The version string must be a series of 2 or 3 dot-separated integers, for +/// example "9.0" or "9.0.1". +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "9.0.1". +static func tvOS(_ versionString: String) -> SupportedPlatform + +/// Configure the minimum deployment target version for the watchOS platform. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter version: The minimum deployment target that the package supports. +static func watchOS(_ version: SupportedPlatform.WatchOSVersion) -> SupportedPlatform + +/// Configure the minimum deployment target version for the watchOS platform +/// using a custom version string. +/// +/// The version string must be a series of 2 or 3 dot-separated integers, for +/// example "2.0" or "2.0.1". +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "3.0.1". +static func watchOS(_ versionString: String) -> SupportedPlatform +``` + +# Product + +Defines a package product. + +A package product defines an externally visible build artifact that is +available to clients of a package. The product is assembled from the build +artifacts of one or more of the package's targets. + +A package product can be one of two types: + +1. Library + + A library product is used to vend library targets containing the public + APIs that will be available to clients. + +2. Executable + + An executable product is used to vend an executable target. This should + only be used if the executable needs to be made available to clients. + +The following example shows a package manifest for a library called "Paper" +that defines multiple products: + +```swift +let package = Package( + name: "Paper", + products: [ + .executable(name: "tool", targets: ["tool"]), + .library(name: "Paper", targets: ["Paper"]), + .library(name: "PaperStatic", type: .static, targets: ["Paper"]), + .library(name: "PaperDynamic", type: .dynamic, targets: ["Paper"]), + ], + dependencies: [ + .package(url: "http://example.com.com/ExamplePackage/ExamplePackage", from: "1.2.3"), + .package(url: "http://some/other/lib", .exact("1.2.3")), + ], + targets: [ + .target( + name: "tool", + dependencies: [ + "Paper", + "ExamplePackage" + ]), + .target( + name: "Paper", + dependencies: [ + "Basic", + .target(name: "Utility"), + .product(name: "AnotherExamplePackage"), + ]) + ] +) +``` + +### Methods + +```swift +/// Create a library product that can be used by clients that depend on this package. +/// +/// A library's product can either be statically or dynamically linked. It +/// is recommended to not declare the type of library explicitly to let the +/// Swift Package Manager choose between static or dynamic linking depending +/// on the consumer of the package. +/// +/// - Parameters: +/// - name: The name of the library product. +/// - type: The optional type of the library that is used to determine how to link to the library. +/// Leave this parameter unspecified to let to let the Swift Package Manager choose between static or dynamic linking (recommended). +/// If you do not support both linkage types, use `.static` or `.dynamic` for this parameter. +/// - targets: The targets that are bundled into a library product. +public static func library( + name: String, + type: Product.Library.LibraryType? = nil, + targets: [String] +) -> Product + +/// Create an executable product. +/// +/// - Parameters: +/// - name: The name of the executable product. +/// - targets: The targets that are bundled into an executable product. +public static func executable(name: String, targets: [String]) -> Product +``` + +# Package Dependency + +A package dependency consists of a Git URL to the source of the package, +and a requirement for the version of the package that can be used. + +The Swift Package Manager performs a process called dependency resolution to +figure out the exact version of the package dependencies that can be used in +your package. The results of the dependency resolution are recorded in the +`Package.resolved` file which will be placed in the top-level directory of +your package. + +### Methods + +```swift +/// Add a package dependency that is required from the given minimum version, +/// going up to the next major version. +/// +/// This is the recommend way to specify a remote package dependency because +/// it allows you to specify the minimum version you require and gives +/// explicit opt-in for new major versions, but otherwise provides maximal +/// flexibility on which version is used. This helps to prevent conflicts in +/// your package dependency graph. +/// +/// For example, specifying +/// +/// .package(url: "https://example.com/example-package.git", from: "1.2.3"), +/// +/// will allow the Swift package manager to select a version like a "1.2.3", +/// "1.2.4" or "1.3.0" but not "2.0.0". +/// +/// - Parameters: +/// - url: The valid Git URL of the package. +/// - version: The minimum version requirement. +public static func package(url: String, from version: Version) -> Package.Dependency + +/// Add a remote package dependency given a version requirement. +/// +/// - Parameters: +/// - url: The valid Git URL of the package. +/// - requirement: A dependency requirement. See static methods on `Package.Dependency.Requirement` for available options. +public static func package(url: String, _ requirement: Package.Dependency.Requirement) -> Package.Dependency + +/// +/// For example +/// +/// .package(url: "https://example.com/example-package.git", "1.2.3"..<"1.2.6"), +/// +/// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, but not 1.2.6. +/// +/// - Parameters: +/// - url: The valid Git URL of the package. +/// - range: The custom version range requirement. +public static func package(url: String, _ range: Range) -> Package.Dependency + +/// Add a package dependency starting with a specific minimum version, going +/// up to and including a specific maximum version. +/// +/// For example +/// +/// .package(url: "https://example.com/example-package.git", "1.2.3"..."1.2.6"), +/// +/// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, as well as 1.2.6. +/// +/// - Parameters: +/// - url: The valid Git URL of the package. +/// - range: The closed version range requirement. +public static func package(url: String, _ range: ClosedRange) -> Package.Dependency + +/// Add a dependency to a local package on the filesystem. +/// +/// The package dependency is used as-is and no source control access is +/// performed. Local package dependencies are especially useful during +/// development of a new package or when working on multiple tightly-coupled +/// packages. +/// +/// - Parameter path: The path of the package. +public static func package(path: String) -> Package.Dependency +``` + +# Package Dependency Requirement +`enum Package.Dependency.Requirement` + +The dependency requirement can be defined as one of three different version requirements: + +1. Version-based Requirement + + A requirement which restricts what version of a dependency your + package can use based on its available versions. When a new package + version is published, it should increment the major version component + if it has backwards-incompatible changes. It should increment the + minor version component if it adds new functionality in + a backwards-compatible manner. And it should increment the patch + version if it makes backwards-compatible bugfixes. To learn more about + the syntax of semantic versioning syntax, see `Version` or visit + https://semver.org (https://semver.org/). + +2. Branch-based Requirement + + Specify the name of a branch that a dependency will follow. This is + useful when developing multiple packages which are closely related, + allowing you to keep them in sync during development. Note that + packages which use branch-based dependency requirements cannot be + depended-upon by packages which use version-based dependency + requirements; you should remove branch-based dependency requirements + before publishing a version of your package. + +3. Commit-based Requirement + + A requirement that restricts a dependency to a specific commit + hash. This is useful if you want to pin your package to a specific + commit hash of a dependency. Note that packages which use + commit-based dependency requirements cannot be depended-upon by + packages which use version-based dependency requirements; you + should remove commit-based dependency requirements before + publishing a version of your package. + +### Methods + +```swift +/// Returns a requirement for the given exact version. +/// +/// Specifying exact version requirements are usually not recommended, as +/// they can cause conflicts in your package dependency graph when a package +/// is depended on by multiple other packages. +/// +/// Example: +/// +/// .exact("1.2.3") +/// +/// - Parameters: +/// - version: The exact version to be specified. +public static func exact(_ version: Version) -> Package.Dependency.Requirement + +/// Returns a requirement for a source control revision. This is usually +/// specified with the hash of a commit. +/// +/// Note that packages which use commit-based dependency requirements +/// cannot be depended-upon by packages which use version-based dependency +/// requirements; you should remove commit-based dependency requirements +/// before publishing a version of your package. +/// +/// Example: +/// +/// .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021") +/// +/// - Parameters: +/// - ref: The Git revision, usually a hash of the commit. +public static func revision(_ ref: String) -> Package.Dependency.Requirement + +/// Returns a requirement for a source control branch. +/// +/// Note that packages which use branch-based dependency requirements +/// cannot be depended-upon by packages which use version-based dependency +/// requirements; you should remove branch-based dependency requirements +/// before publishing a version of your package. +/// +/// Example: +/// +/// .branch("develop") +/// +/// - Parameters: +/// - name: The name of the branch. +public static func branch(_ name: String) -> Package.Dependency.Requirement + +/// Returns a requirement for a version range, starting at the given minimum +/// version and going up to the next major version. +/// +/// - Parameters: +/// - version: The minimum version for the version range. +public static func upToNextMajor(from version: Version) -> Package.Dependency.Requirement + +/// Returns a requirement for a version range, starting at the given minimum +/// version and going up to the next minor version. +/// +/// - Parameters: +/// - version: The minimum version for the version range. +public static func upToNextMinor(from version: Version) -> Package.Dependency.Requirement +``` + +# Version + +A struct representing a Semantic Version. + +Semantic versioning is a specification that proposes a set of rules and +requirements that dictate how version numbers are assigned and incremented. +To learn more about the semantic versioning specification, visit +www.semver.org. + +### Semantic Versioning (SemVer) 2.0.0 + +#### The Major Version + +The major version signifies breaking changes to the API which requires +updating existing clients. For example, renaming an existing type, removing +a method or changing a method’s signature are considered breaking changes. +This also includes any backwards incompatible bugfixes or behaviour changes +of existing API. + +#### The Minor Version + +Update the minor version if functionality is added in a backward compatible +manner. For example, adding a new method or type without changing any other +API is considered backward-compatible. + +#### The Patch Version + +Increase the patch version if you are making a backward-compatible bugfix. +This allows clients to benefit from bugfixes to your package without +incurring any maintenance burden. + +# Target + +Targets are the basic building blocks of a package. + +Each target contains a set of source files that are compiled into a module or +test suite. Targets can be vended to other packages by defining products that +include them. + +Targets may depend on targets within the same package and on products vended +by its package dependencies. + +### Methods + +```swift +/// Create a library or executable target. +/// +/// A target can either contain Swift or C-family source files. You cannot +/// mix Swift and C-family source files within a target. A target is +/// considered to be an executable target if there is a `main.swift`, +/// `main.m`, `main.c` or `main.cpp` file in the target's directory. All +/// other targets are considered to be library targets. +/// +/// - Parameters: +/// - name: The name of the target. +/// - dependencies: The dependencies of the target. These can either be other targets in the package or products from package dependencies. +/// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. +/// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. +/// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. +/// - sources: An explicit list of source files. +/// - publicHeadersPath: The directory containing public headers of a C-family family library target. +/// - cSettings: The C settings for this target. +/// - cxxSettings: The C++ settings for this target. +/// - swiftSettings: The Swift settings for this target. +/// - linkerSettings: The linker settings for this target. +public static func target( + name: String, + dependencies: [Target.Dependency] = [], + path: String? = nil, + exclude: [String] = [], + sources: [String]? = nil, + publicHeadersPath: String? = nil, + cSettings: [CSetting]? = nil, + cxxSettings: [CXXSetting]? = nil, + swiftSettings: [SwiftSetting]? = nil, + linkerSettings: [LinkerSetting]? = nil +) -> Target + +/// Create a test target. +/// +/// Test targets are written using the XCTest testing framework. Test targets +/// generally declare target dependency on the targets they test. +/// +/// - Parameters: +/// - name: The name of the target. +/// - dependencies: The dependencies of the target. These can either be other targets in the package or products from other packages. +/// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. +/// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. +/// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. +/// - sources: An explicit list of source files. +/// - cSettings: The C settings for this target. +/// - cxxSettings: The C++ settings for this target. +/// - swiftSettings: The Swift settings for this target. +/// - linkerSettings: The linker settings for this target. +public static func testTarget( + name: String, + dependencies: [Target.Dependency] = [], + path: String? = nil, + exclude: [String] = [], + sources: [String]? = nil, + cSettings: [CSetting]? = nil, + cxxSettings: [CXXSetting]? = nil, + swiftSettings: [SwiftSetting]? = nil, + linkerSettings: [LinkerSetting]? = nil +) -> Target + +/// Create a system library target. +/// +/// System library targets are used to adapt a library installed on the system to +/// work with Swift packages. Such libraries are generally installed by system +/// package managers (such as Homebrew and APT) and exposed to Swift packages by +/// providing a modulemap file along with other metadata such as the library's +/// pkg-config name. +/// +/// - Parameters: +/// - name: The name of the target. +/// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. +/// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. +/// - pkgConfig: The name of the pkg-config file for this system library. +/// - providers: The providers for this system library. +public static func systemLibrary( + name: String, + path: String? = nil, + pkgConfig: String? = nil, + providers: [SystemPackageProvider]? = nil +) -> Target +``` + +# Target Dependency +`class Target.Dependency` + +Represents dependency on other targets in the package or products from other packages. + +```swift +/// A dependency on a target in the same package. +public static func target(name: String) -> Target.Dependency + +/// A dependency on a product from a package dependency. +public static func product(name: String, package: String? = nil) -> Target.Dependency + +// A by-name dependency that resolves to either a target or a product, +// as above, after the package graph has been loaded. +public static func byName(name: String) -> Target.Dependency +``` + +# CSetting + +A C-language build setting. + +### Methods + +```swift +/// Provide a header search path relative to the target's directory. +/// +/// Use this setting to add a search path for headers within your target. +/// Absolute paths are disallowed and this setting can't be used to provide +/// headers that are visible to other targets. +/// +/// The path must be a directory inside the package. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. +/// - condition: A condition which will restrict when the build setting applies. +public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CSetting + +/// Defines a value for a macro. If no value is specified, the macro value will +/// be defined as 1. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - name: The name of the macro. +/// - value: The value of the macro. +/// - condition: A condition which will restrict when the build setting applies. +public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CSetting + +/// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. +/// +/// As the usage of the word "unsafe" implies, the Swift Package Manager +/// can't safely determine if the build flags will have any negative +/// side-effect to the build since certain flags can change the behavior of +/// how a build is performed. +/// +/// As some build flags could be exploited for unsupported or malicious +/// behavior, the use of unsafe flags make the products containing this +/// target ineligible to be used by other packages. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - flags: The flags to set. +/// - condition: A condition which will restrict when the build setting applies. +public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CSetting +``` + +# CXXSetting + +A CXX-language build setting. + +### Methods + +```swift +/// Provide a header search path relative to the target's root directory. +/// +/// Use this setting to add a search path for headers within your target. +/// Absolute paths are disallowed and this setting can't be used to provide +/// headers that are visible to other targets. +/// +/// The path must be a directory inside the package. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. +/// - condition: A condition which will restrict when the build setting applies. +public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CXXSetting + +/// Defines a value for a macro. If no value is specified, the macro value will +/// be defined as 1. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - name: The name of the macro. +/// - value: The value of the macro. +/// - condition: A condition which will restrict when the build setting applies. +public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CXXSetting + +/// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. +/// +/// As the usage of the word "unsafe" implies, the Swift Package Manager +/// can't safely determine if the build flags will have any negative +/// side-effect to the build since certain flags can change the behavior of +/// how a build is performed. +/// +/// As some build flags could be exploited for unsupported or malicious +/// behavior, the use of unsafe flags make the products containing this +/// target ineligible to be used by other packages. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - flags: The flags to set. +/// - condition: A condition which will restrict when the build setting applies. +public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CXXSetting +``` + +# SwiftSetting + +A Swift language build setting. + +### Methods + +```swift +/// Define a compilation condition. +/// +/// Compilation conditons are used inside to conditionally compile +/// statements. For example, the Swift compiler will only compile the +/// statements inside the `#if` block when `ENABLE_SOMETHING` is defined: +/// +/// #if ENABLE_SOMETHING +/// ... +/// #endif +/// +/// Unlike macros in C/C++, compilation conditions don't have an +/// associated value. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - name: The name of the macro. +/// - condition: A condition which will restrict when the build setting applies. +public static func define(_ name: String, _ condition: BuildSettingCondition? = nil) -> SwiftSetting + +/// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. +/// +/// As the usage of the word "unsafe" implies, the Swift Package Manager +/// can't safely determine if the build flags will have any negative +/// side-effect to the build since certain flags can change the behavior of +/// how a build is performed. +/// +/// As some build flags could be exploited for unsupported or malicious +/// behavior, the use of unsafe flags make the products containing this +/// target ineligible to be used by other packages. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - flags: The flags to set. +/// - condition: A condition which will restrict when the build setting applies. +public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> SwiftSetting +``` + +# LinkerSetting + +A linker build setting. + +### Methods + +```swift +/// Declare linkage to a system library. +/// +/// This setting is most useful when the library can't be linked +/// automatically (for example, C++ based libraries and non-modular +/// libraries). +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - library: The library name. +/// - condition: A condition which will restrict when the build setting applies. +public static func linkedLibrary(_ library: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting + +/// Declare linkage to a framework. +/// +/// This setting is most useful when the framework can't be linked +/// automatically (for example, C++ based frameworks and non-modular +/// frameworks). +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - framework: The framework name. +/// - condition: A condition which will restrict when the build setting applies. +public static func linkedFramework(_ framework: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting + +/// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. +/// +/// As the usage of the word "unsafe" implies, the Swift Package Manager +/// can't safely determine if the build flags will have any negative +/// side-effect to the build since certain flags can change the behavior of +/// how a build is performed. +/// +/// As some build flags could be exploited for unsupported or malicious +/// behavior, the use of unsafe flags make the products containing this +/// target ineligible to be used by other packages. +/// +/// - Since: First available in PackageDescription 5.0 +/// +/// - Parameters: +/// - flags: The flags to set. +/// - condition: A condition which will restrict when the build setting applies. +public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> LinkerSetting +``` + +# SwiftVersion + +Represents the version of the Swift language that should be used for compiling +Swift sources in the package. + +```swift +public enum SwiftVersion { + + @available(_PackageDescription, introduced: 4, obsoleted: 5) + case v3 + + @available(_PackageDescription, introduced: 4) + case v4 + + @available(_PackageDescription, introduced: 4) + case v4_2 + + @available(_PackageDescription, introduced: 5) + case v5 + + /// User-defined value of Swift version. + /// + /// The value is passed as-is to Swift compiler's `-swift-version` flag. + case version(String) +} +``` + +# CLanguageStandard + +Supported C language standards. + +```swift +public enum CLanguageStandard { + case c89 + case c90 + case iso9899_1990 + case iso9899_199409 + case gnu89 + case gnu90 + case c99 + case iso9899_1999 + case gnu99 + case c11 + case iso9899_2011 + case gnu11 +} +``` +# CXXLanguageStandard + +Supported C++ language standards. + +```swift +public enum CXXLanguageStandard { + case cxx98 = "c++98" + case cxx03 = "c++03" + case gnucxx98 = "gnu++98" + case gnucxx03 = "gnu++03" + case cxx11 = "c++11" + case gnucxx11 = "gnu++11" + case cxx14 = "c++14" + case gnucxx14 = "gnu++14" + case cxx1z = "c++1z" + case gnucxx1z = "gnu++1z" +} +``` diff --git a/Documentation/PackageDescriptionV3.md b/Documentation/PackageDescriptionV3.md index c43c1757413..ee4a86fe3f6 100644 --- a/Documentation/PackageDescriptionV3.md +++ b/Documentation/PackageDescriptionV3.md @@ -1,22 +1,6 @@ # PackageDescription API Version 3 -## Table of Contents - -* [Overview](README.md) -* [Usage](Usage.md) -* [**PackageDescription API Version 3**](PackageDescriptionV3.md) - * [Target Format Reference](#target-format-reference) - * [Source Layouts](#source-layouts) - * [Test Target Layouts](#test-target-layouts) - * [Other Rules](#other-rules) - * [Package Manifest File Format Reference](#package-manifest-file-format-reference) - * [Package Declaration](#package-declaration) - * [Package](#package) - * [Package Dependency](#package-dependency) - * [Version](#version) -* [PackageDescription API Version 4](PackageDescriptionV4.md) -* [PackageDescription API Version 4.2](PackageDescriptionV4_2.md) -* [Resources](Resources.md) +⚠️ This version is no longer supported ⚠️ --- diff --git a/Documentation/PackageDescriptionV4.md b/Documentation/PackageDescriptionV4.md index 2613981225b..20387c2299c 100644 --- a/Documentation/PackageDescriptionV4.md +++ b/Documentation/PackageDescriptionV4.md @@ -1,16 +1,8 @@ # PackageDescription API Version 4 -## Table of Contents - -* [Overview](README.md) -* [Usage](Usage.md) -* [PackageDescription API Version 3](PackageDescriptionV3.md) -* [**PackageDescription API Version 4**](PackageDescriptionV4.md) - * [Target Format Reference](#target-format-reference) - * [Package Manifest File Format Reference](#package-manifest-file-format-reference) - * [Version](#version) -* [PackageDescription API Version 4.2](PackageDescriptionV4_2.md) -* [Resources](Resources.md) +⚠️ This document is no longer maintained ⚠️ + +See [this](PackageDescription.md) document instead. --- diff --git a/Documentation/PackageDescriptionV4_2.md b/Documentation/PackageDescriptionV4_2.md index 0346526f995..aa912d27aef 100644 --- a/Documentation/PackageDescriptionV4_2.md +++ b/Documentation/PackageDescriptionV4_2.md @@ -1,16 +1,8 @@ # PackageDescription API Version 4.2 -## Table of Contents - -* [Overview](README.md) -* [Usage](Usage.md) -* [PackageDescription API Version 3](PackageDescriptionV3.md) -* [PackageDescription API Version 4](PackageDescriptionV4.md) -* [**PackageDescription API Version 4.2**](PackageDescriptionV4_2.md) - * [Swift Language Version](#swift-language-version) - * [Local Dependencies](#local-dependencies) - * [System Library Targets](#system-library-targets) -* [Resources](Resources.md) +⚠️ This document is no longer maintained ⚠️ + +See [this](PackageDescription.md) document instead. --- diff --git a/Documentation/README.md b/Documentation/README.md index 79325f15aa5..2c8f9e88633 100644 --- a/Documentation/README.md +++ b/Documentation/README.md @@ -16,9 +16,7 @@ We’ve designed the system to make it really easy to share packages on services * [About Dependencies](#about-dependencies) * [Dependency Hell](#dependency-hell) * [Usage](Usage.md) -* [PackageDescription API Version 3](PackageDescriptionV3.md) -* [PackageDescription API Version 4](PackageDescriptionV4.md) -* [PackageDescription API Version 4.2](PackageDescriptionV4_2.md) +* [PackageDescription API](PackageDescription.md) * [libSwiftPM](libSwiftPM.md) * [Resources](Resources.md) diff --git a/Documentation/Resources.md b/Documentation/Resources.md index cb8186687c6..21e8bdbc67c 100644 --- a/Documentation/Resources.md +++ b/Documentation/Resources.md @@ -4,9 +4,7 @@ * [Overview](README.md) * [Usage](Usage.md) -* [PackageDescription API Version 3](PackageDescriptionV3.md) -* [PackageDescription API Version 4](PackageDescriptionV4.md) -* [PackageDescription API Version 4.2](PackageDescriptionV4_2.md) +* [PackageDescription API](PackageDescription.md) * [**Resources**](Resources.md) * [Support](#support) * [Reporting a good SwiftPM Bug](#reporting-a-good-swiftpm-bug) diff --git a/Documentation/Usage.md b/Documentation/Usage.md index d1f69b18ae6..8cb858ba157 100644 --- a/Documentation/Usage.md +++ b/Documentation/Usage.md @@ -24,9 +24,7 @@ * [Depending on Apple Modules](#depending-on-apple-modules) * [C language targets](#c-language-targets) * [Shell completion scripts](#shell-completion-scripts) -* [PackageDescription API Version 3](PackageDescriptionV3.md) -* [PackageDescription API Version 4](PackageDescriptionV4.md) -* [PackageDescription API Version 4.2](PackageDescriptionV4_2.md) +* [PackageDescription API](PackageDescription.md) * [Resources](Resources.md) --- From 0a7621dcc1df00cc344058423a2dfc4c0ecd71c4 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sun, 12 May 2019 16:14:31 -0700 Subject: [PATCH 26/67] [Workspace] New packages should use tools version 5.1 --- Sources/Workspace/InitPackage.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Workspace/InitPackage.swift b/Sources/Workspace/InitPackage.swift index 42c423802ca..41e781b5655 100644 --- a/Sources/Workspace/InitPackage.swift +++ b/Sources/Workspace/InitPackage.swift @@ -14,7 +14,7 @@ import PackageModel /// Create an initial template package. public final class InitPackage { /// The tool version to be used for new packages. - public static let newPackageToolsVersion = ToolsVersion(version: "5.0.0") + public static let newPackageToolsVersion = ToolsVersion(version: "5.1.0") /// Represents a package type for the purposes of initialization. public enum PackageType: String, CustomStringConvertible { From e14b29be75db226f9c19ed79b850b3dc5fc02ee5 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sun, 12 May 2019 17:16:19 -0700 Subject: [PATCH 27/67] [Documentation] Add missing forward slash in two places --- Sources/PackageDescription4/PackageDependency.swift | 2 +- Sources/PackageDescription4/Target.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/PackageDescription4/PackageDependency.swift b/Sources/PackageDescription4/PackageDependency.swift index 5c8a64fbdd6..d854309663d 100644 --- a/Sources/PackageDescription4/PackageDependency.swift +++ b/Sources/PackageDescription4/PackageDependency.swift @@ -50,7 +50,7 @@ extension Package.Dependency { } /// Add a package dependency starting with a specific minimum version, up to - // but not including a specific maximum version. + /// but not including a specific maximum version. /// /// For example /// diff --git a/Sources/PackageDescription4/Target.swift b/Sources/PackageDescription4/Target.swift index 53688b13d2f..f60df6d235e 100644 --- a/Sources/PackageDescription4/Target.swift +++ b/Sources/PackageDescription4/Target.swift @@ -160,7 +160,7 @@ public final class Target { } /// Create a library or executable target. - // + /// /// A target can either contain Swift or C-family source files. You cannot /// mix Swift and C-family source files within a target. A target is /// considered to be an executable target if there is a `main.swift`, @@ -196,7 +196,7 @@ public final class Target { } /// Create a library or executable target. - // + /// /// A target can either contain Swift or C-family source files. You cannot /// mix Swift and C-family source files within a target. A target is /// considered to be an executable target if there is a `main.swift`, From ecfd7a98879012df7430cf9d5b5f3961e05a613f Mon Sep 17 00:00:00 2001 From: Brent Royal-Gordon Date: Thu, 16 May 2019 16:43:45 -0700 Subject: [PATCH 28/67] Bootstrap PackageDescription with -module-cache-path --- Utilities/bootstrap | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Utilities/bootstrap b/Utilities/bootstrap index f78977d865a..daca4f806e3 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -682,6 +682,8 @@ def process_runtime_libraries(build, args, lib_path): tf = tempfile.NamedTemporaryFile(suffix=".swift") cmd += [tf.name] + cmd.extend(["-module-cache-path", os.path.join(args.sandbox_path, "ModuleCache")]) + subprocess.check_call(cmd) return (runtime_module_path, runtime_swiftdoc_path, runtime_lib_path) From c79e22b0958da2823652727720b6e5759372bad6 Mon Sep 17 00:00:00 2001 From: Saleem Abdulrasool Date: Mon, 20 May 2019 12:19:16 -0700 Subject: [PATCH 29/67] build: clean up the legacy paths The new XCTest build has been CMake based for ages. This places the Swift contents in a directory named swift in the build tree. Update the search path. --- Utilities/bootstrap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utilities/bootstrap b/Utilities/bootstrap index daca4f806e3..3b0278b1ba6 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -1171,7 +1171,7 @@ def main(): # Add XCTest. for module_file in ["XCTest.swiftmodule", "XCTest.swiftdoc"]: - symlink_force(os.path.join(args.xctest_path, module_file), libincludedir) + symlink_force(os.path.join(args.xctest_path, 'swift', module_file), libincludedir) symlink_force(os.path.join(args.xctest_path, "libXCTest.so"), libswiftdir) return (libswiftdir, libincludedir) From cb132b13a03c5d3fcb2bd39ca8630bbdf12f70d7 Mon Sep 17 00:00:00 2001 From: Benjamin Scholtysik Date: Mon, 20 May 2019 16:58:56 -0700 Subject: [PATCH 30/67] Remove unnecessary heading source docs Affected file: - supportedPlatforms.swift --- Sources/PackageDescription4/SupportedPlatforms.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/Sources/PackageDescription4/SupportedPlatforms.swift b/Sources/PackageDescription4/SupportedPlatforms.swift index b89029c8a7c..b71a85650c8 100644 --- a/Sources/PackageDescription4/SupportedPlatforms.swift +++ b/Sources/PackageDescription4/SupportedPlatforms.swift @@ -28,8 +28,6 @@ public struct Platform: Encodable { /// Represents a platform supported by the package. /// -/// # The Supported Platform -/// /// By default, the Swift Package Manager assigns a predefined minimum deployment /// version for each supported platforms unless configured using the `platforms` /// API. This predefined deployment version will be the oldest deployment target From 330de050285c822ff9df4f11a069721a5541b3a6 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sun, 26 May 2019 16:56:01 -0700 Subject: [PATCH 31/67] [PerfTests] Fix two perf tests --- .../PackageLoadingPerformanceTests/ManifestLoadingTests.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Tests/PackageLoadingPerformanceTests/ManifestLoadingTests.swift b/Tests/PackageLoadingPerformanceTests/ManifestLoadingTests.swift index 6a53010bb08..f4fbb4b52b1 100644 --- a/Tests/PackageLoadingPerformanceTests/ManifestLoadingTests.swift +++ b/Tests/PackageLoadingPerformanceTests/ManifestLoadingTests.swift @@ -34,7 +34,7 @@ class ManifestLoadingPerfTests: XCTestCasePerf { write(trivialManifest) { path in measure { for _ in 0.. Date: Tue, 28 May 2019 14:18:48 -0700 Subject: [PATCH 32/67] Don't link runtime compatibility library in pure Clang targets. apple/swift#25030 introduces a compatibility library that can be statically linked into binaries in order to back-deploy runtime fixes and new features to OSes that shipped with older Swift runtimes. This library depends on the Swift runtime being linked into the executable, so it will cause link errors for pure Clang products (and even if it didn't, it would be a waste of code size). When building a product without any Swift in it, ask Swift to drive the linker without introducing any runtime compatibility libraries (and shake out a few other unnecessary linker flags while we're here). rdar://problem/50057445 --- Sources/Build/BuildPlan.swift | 31 +++++++++++++++-------- Sources/PackageModel/ResolvedModels.swift | 12 +++++++++ Tests/BuildTests/BuildPlanTests.swift | 14 +++++----- 3 files changed, 41 insertions(+), 16 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 5faeb6a5630..181976bcc78 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -709,11 +709,13 @@ public final class ProductBuildDescription { args += ["-module-name", product.name.spm_mangledToC99ExtendedIdentifier()] args += dylibs.map({ "-l" + $0.product.name }) - // Add arguements needed for code coverage if it is enabled. + // Add arguments needed for code coverage if it is enabled. if buildParameters.enableCodeCoverage { args += ["-profile-coverage-mapping", "-profile-generate"] } + let containsSwiftTargets = product.containsSwiftTargets + switch product.type { case .library(.automatic): fatalError() @@ -731,7 +733,8 @@ public final class ProductBuildDescription { args += ["-emit-library"] case .executable: // Link the Swift stdlib statically if requested. - if buildParameters.shouldLinkStaticSwiftStdlib { + if containsSwiftTargets, + buildParameters.shouldLinkStaticSwiftStdlib { // FIXME: This does not work for linux yet (SR-648). if !buildParameters.triple.isLinux() { args += ["-static-stdlib"] @@ -748,16 +751,24 @@ public final class ProductBuildDescription { args += ["@\(linkFileListPath.pathString)"] // Embed the swift stdlib library path inside tests and executables on Darwin. - switch product.type { - case .library: break - case .test, .executable: - if buildParameters.triple.isDarwin() { - let stdlib = buildParameters.toolchain.macosSwiftStdlib - args += ["-Xlinker", "-rpath", "-Xlinker", stdlib.pathString] - } + if containsSwiftTargets { + switch product.type { + case .library: break + case .test, .executable: + if buildParameters.triple.isDarwin() { + let stdlib = buildParameters.toolchain.macosSwiftStdlib + args += ["-Xlinker", "-rpath", "-Xlinker", stdlib.pathString] + } + } } - // Add agruments from declared build settings. + // Don't link runtime compatibility patch libraries if there are no + // Swift sources in the target. + if !containsSwiftTargets { + args += ["-runtime-compatibility-version", "none"] + } + + // Add arguments from declared build settings. args += self.buildSettingsFlags() // User arguments (from -Xlinker and -Xswiftc) should follow generated arguments to allow user overrides diff --git a/Sources/PackageModel/ResolvedModels.swift b/Sources/PackageModel/ResolvedModels.swift index 608ef6e9efe..91d970bff6f 100644 --- a/Sources/PackageModel/ResolvedModels.swift +++ b/Sources/PackageModel/ResolvedModels.swift @@ -178,6 +178,18 @@ public final class ResolvedProduct: ObjectIdentifierProtocol, CustomStringConver public var description: String { return "" } + + /// True if this product contains Swift targets. + public var containsSwiftTargets: Bool { + // C targets can't import Swift targets in SwiftPM (at least not right + // now), so we can just look at the top-level targets. + // + // If that ever changes, we'll need to do something more complex here, + // recursively checking dependencies for SwiftTargets, and considering + // dynamic library targets to be Swift targets (since the dylib could + // contain Swift code we don't know about as part of this build). + return targets.contains { $0.underlyingTarget is SwiftTarget } + } } extension ResolvedTarget.Dependency: CustomStringConvertible { diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index 9015daa695c..c9ccd35e29d 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -310,7 +310,7 @@ final class BuildPlanTests: XCTestCase { "/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "@/path/to/build/debug/exe.product/Objects.LinkFileList", - "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift/macosx", + "-runtime-compatibility-version", "none", ]) #else XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), [ @@ -318,6 +318,7 @@ final class BuildPlanTests: XCTestCase { "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/exe.product/Objects.LinkFileList", + "-runtime-compatibility-version", "none", ]) #endif @@ -366,7 +367,7 @@ final class BuildPlanTests: XCTestCase { "/fake/path/to/swiftc", "-lc++", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "@/path/to/build/debug/exe.product/Objects.LinkFileList", - "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift/macosx", + "-runtime-compatibility-version", "none", ]) #else XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), [ @@ -374,6 +375,7 @@ final class BuildPlanTests: XCTestCase { "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/exe.product/Objects.LinkFileList", + "-runtime-compatibility-version", "none", ]) #endif @@ -857,12 +859,12 @@ final class BuildPlanTests: XCTestCase { XCTAssertEqual(lib.moduleMap, AbsolutePath("/path/to/build/debug/lib.build/module.modulemap")) #if os(macOS) - XCTAssertEqual(try result.buildProduct(for: "lib").linkArguments(), ["/fake/path/to/swiftc", "-lc++", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/liblib.dylib", "-module-name", "lib", "-emit-library", "@/path/to/build/debug/lib.product/Objects.LinkFileList"]) + XCTAssertEqual(try result.buildProduct(for: "lib").linkArguments(), ["/fake/path/to/swiftc", "-lc++", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/liblib.dylib", "-module-name", "lib", "-emit-library", "@/path/to/build/debug/lib.product/Objects.LinkFileList", "-runtime-compatibility-version", "none"]) - XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), ["/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "@/path/to/build/debug/exe.product/Objects.LinkFileList", "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift/macosx",]) + XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), ["/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "@/path/to/build/debug/exe.product/Objects.LinkFileList", "-runtime-compatibility-version", "none"]) #else - XCTAssertEqual(try result.buildProduct(for: "lib").linkArguments(), ["/fake/path/to/swiftc", "-lstdc++", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/liblib.so", "-module-name", "lib", "-emit-library", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/lib.product/Objects.LinkFileList"]) - XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), ["/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/exe.product/Objects.LinkFileList"]) + XCTAssertEqual(try result.buildProduct(for: "lib").linkArguments(), ["/fake/path/to/swiftc", "-lstdc++", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/liblib.so", "-module-name", "lib", "-emit-library", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/lib.product/Objects.LinkFileList", "-runtime-compatibility-version", "none"]) + XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), ["/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", "-emit-executable", "-Xlinker", "-rpath=$ORIGIN", "@/path/to/build/debug/exe.product/Objects.LinkFileList", "-runtime-compatibility-version", "none"]) #endif } From 116e059f15489b4c61ff0f4eedd865afe613a6ce Mon Sep 17 00:00:00 2001 From: Benjamin Herzog Date: Fri, 31 May 2019 09:41:47 -0700 Subject: [PATCH 33/67] Add default case to switch on CommandResult If new cases are added to CommandResult we need to handle them. Since we only care about succeeded or skipped commands, we don't do anything here. rdar://51069563 --- Sources/Build/BuildDelegate.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Sources/Build/BuildDelegate.swift b/Sources/Build/BuildDelegate.swift index beb2e36b65f..dcb1703564e 100644 --- a/Sources/Build/BuildDelegate.swift +++ b/Sources/Build/BuildDelegate.swift @@ -412,6 +412,8 @@ fileprivate struct CommandTaskTracker { finishedCount += 1 case .cancelled, .failed: break + default: + break } } From 24ab169de5be5743c083b4ea0593f14cebbc6024 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Mon, 3 Jun 2019 14:19:31 -0700 Subject: [PATCH 34/67] Update doc about iOS/tvOS/watchOS --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22aef9cba32..63711238fc0 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ The Swift Package Manager is a tool for managing distribution of source code, ai We’ve designed the system to make it easy to share packages on services like GitHub, but packages are also great for private personal development, sharing code within a team, or at any other granularity. -Note that at this time the Package Manager has no support for iOS, watchOS, or tvOS platforms. +Swift Package Manager includes a build system that can build for macOS and Linux. Xcode 11 integrates with libSwiftPM to provide support for iOS, watchOS, and tvOS platforms. --- From c2dc30a5002c776d6137ed5e61dae2fed22ed2e9 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Mon, 3 Jun 2019 13:37:53 -0700 Subject: [PATCH 35/67] [PackageDescription4] Add new OS versions in SupportedPlatforms --- .../SupportedPlatforms.swift | 24 ++++++++++++++++++ Sources/PackageLoading/ManifestLoader.swift | 4 ++- Sources/PackageLoading/PackageBuilder.swift | 2 +- Sources/PackageModel/Manifest.swift | 5 +++- Sources/PackageModel/Sources.swift | 2 +- Sources/Xcodeproj/pbxproj().swift | 2 +- .../PackageLoadingTests/PD4LoadingTests.swift | 11 +++++++- .../PackageLoadingTests/PD5LoadingTests.swift | 25 +++++++++++++++++++ 8 files changed, 69 insertions(+), 6 deletions(-) diff --git a/Sources/PackageDescription4/SupportedPlatforms.swift b/Sources/PackageDescription4/SupportedPlatforms.swift index b71a85650c8..8124b3a86a4 100644 --- a/Sources/PackageDescription4/SupportedPlatforms.swift +++ b/Sources/PackageDescription4/SupportedPlatforms.swift @@ -184,6 +184,12 @@ extension SupportedPlatform { /// /// - Since: First available in PackageDescription 5.0 public static let v10_14: MacOSVersion = .init(string: "10.14") + + /// macOS 10.15 + /// + /// - Since: First available in PackageDescription 5.1 + @available(_PackageDescription, introduced: 5.1) + public static let v10_15: MacOSVersion = .init(string: "10.15") } public struct TVOSVersion: Encodable, AppleOSVersion { @@ -216,6 +222,12 @@ extension SupportedPlatform { /// /// - Since: First available in PackageDescription 5.0 public static let v12: TVOSVersion = .init(string: "12.0") + + /// tvOS 13.0 + /// + /// - Since: First available in PackageDescription 5.1 + @available(_PackageDescription, introduced: 5.1) + public static let v13: TVOSVersion = .init(string: "13.0") } public struct IOSVersion: Encodable, AppleOSVersion { @@ -253,6 +265,12 @@ extension SupportedPlatform { /// /// - Since: First available in PackageDescription 5.0 public static let v12: IOSVersion = .init(string: "12.0") + + /// iOS 13.0 + /// + /// - Since: First available in PackageDescription 5.1 + @available(_PackageDescription, introduced: 5.1) + public static let v13: IOSVersion = .init(string: "13.0") } public struct WatchOSVersion: Encodable, AppleOSVersion { @@ -285,6 +303,12 @@ extension SupportedPlatform { /// /// - Since: First available in PackageDescription 5.0 public static let v5: WatchOSVersion = .init(string: "5.0") + + /// watchOS 6.0 + /// + /// - Since: First available in PackageDescription 5.1 + @available(_PackageDescription, introduced: 5.1) + public static let v6: WatchOSVersion = .init(string: "6.0") } } diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 21a9ba5b066..530bedbe3ba 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -70,10 +70,12 @@ extension ToolsVersion { // Otherwise, return 4.2 return .v4_2 + case 5 where minor < 1: + return .v5 default: // For rest, return the latest manifest version. - return .v5 + return .v5_1 } } } diff --git a/Sources/PackageLoading/PackageBuilder.swift b/Sources/PackageLoading/PackageBuilder.swift index 317266067b6..44b02ea7702 100644 --- a/Sources/PackageLoading/PackageBuilder.swift +++ b/Sources/PackageLoading/PackageBuilder.swift @@ -367,7 +367,7 @@ public final class PackageBuilder { // Emit deprecation notice. switch manifest.manifestVersion { case .v4: break - case .v4_2, .v5: + case .v4_2, .v5, .v5_1: diagnostics.emit( data: PackageBuilderDiagnostics.SystemPackageDeprecatedDiagnostic(), location: diagnosticLocation() diff --git a/Sources/PackageModel/Manifest.swift b/Sources/PackageModel/Manifest.swift index 54b491cb553..d70adc8eac1 100644 --- a/Sources/PackageModel/Manifest.swift +++ b/Sources/PackageModel/Manifest.swift @@ -16,6 +16,7 @@ public enum ManifestVersion: String, Codable, CustomStringConvertible { case v4 case v4_2 case v5 + case v5_1 /// The Swift language version to use when parsing the manifest file. public var swiftLanguageVersion: SwiftLanguageVersion { @@ -30,6 +31,7 @@ public enum ManifestVersion: String, Codable, CustomStringConvertible { case .v4: return .v4 case .v4_2: return .v4_2 case .v5: return .v5 + case .v5_1: return .v5 } } @@ -38,6 +40,7 @@ public enum ManifestVersion: String, Codable, CustomStringConvertible { case .v4: return "4" case .v4_2: return "4.2" case .v5: return "5" + case .v5_1: return "5.1" } } @@ -46,7 +49,7 @@ public enum ManifestVersion: String, Codable, CustomStringConvertible { switch self { case .v4: return RelativePath("4") - case .v4_2, .v5: + case .v4_2, .v5, .v5_1: // PackageDescription 4.2 and 5 are source compatible so they're contained in the same dylib. return RelativePath("4_2") } diff --git a/Sources/PackageModel/Sources.swift b/Sources/PackageModel/Sources.swift index 47713078e85..9ca653149c5 100644 --- a/Sources/PackageModel/Sources.swift +++ b/Sources/PackageModel/Sources.swift @@ -81,7 +81,7 @@ public enum SupportedLanguageExtension: String { switch manifestVersion { case .v4, .v4_2: return alwaysValidExts - case .v5: + case .v5, .v5_1: return alwaysValidExts.union(assemblyExtensions) } } diff --git a/Sources/Xcodeproj/pbxproj().swift b/Sources/Xcodeproj/pbxproj().swift index f6aa3f39aa0..36b8d85bc34 100644 --- a/Sources/Xcodeproj/pbxproj().swift +++ b/Sources/Xcodeproj/pbxproj().swift @@ -428,7 +428,7 @@ func xcodeProject( // Assign the deployment target if the package is using the newer manifest version. switch package.manifest.manifestVersion { - case .v5: + case .v5, .v5_1: for supportedPlatform in target.underlyingTarget.platforms { let version = supportedPlatform.version.versionString switch supportedPlatform.platform { diff --git a/Tests/PackageLoadingTests/PD4LoadingTests.swift b/Tests/PackageLoadingTests/PD4LoadingTests.swift index f47a22a0e64..77feffc1757 100644 --- a/Tests/PackageLoadingTests/PD4LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD4LoadingTests.swift @@ -75,13 +75,22 @@ class PackageDescription4LoadingTests: XCTestCase { } let fiveVersions = [ - "5.1.0", "6.1.100", "5.0.0", "7.0.0", + "5.0.0", "5.0.1", "5.0.2", ] for version in fiveVersions { let toolsVersion = ToolsVersion(string: version)! XCTAssertEqual(toolsVersion.manifestVersion, .v5, version) } + + let fiveOneVersions = [ + "5.1.0", "6.1.100", "5.1.1", "7.0.0", + ] + + for version in fiveOneVersions { + let toolsVersion = ToolsVersion(string: version)! + XCTAssertEqual(toolsVersion.manifestVersion, .v5_1, version) + } } func testTrivial() { diff --git a/Tests/PackageLoadingTests/PD5LoadingTests.swift b/Tests/PackageLoadingTests/PD5LoadingTests.swift index 1e73b6e2d69..c28ac4761d5 100644 --- a/Tests/PackageLoadingTests/PD5LoadingTests.swift +++ b/Tests/PackageLoadingTests/PD5LoadingTests.swift @@ -226,6 +226,31 @@ class PackageDescription5LoadingTests: XCTestCase { } catch ManifestParseError.runtimeManifestErrors(let errors) { XCTAssertEqual(errors, ["supported platforms can't be empty"]) } + + // Newer OS version. + stream = BufferedOutputByteStream() + stream <<< """ + import PackageDescription + let package = Package( + name: "Foo", + platforms: [ + .macOS(.v10_15), .iOS(.v13), + ] + ) + """ + + do { + try loadManifestThrowing(stream.bytes) { _ in } + XCTFail("Unexpected success") + } catch { + guard case let ManifestParseError.invalidManifestFormat(message, _) = error else { + return XCTFail("\(error)") + } + + XCTAssertMatch(message, .contains("error: 'v10_15' is unavailable")) + XCTAssertMatch(message, .contains("note: 'v10_15' was introduced in PackageDescription 5.1")) + XCTAssertMatch(message, .contains("note: 'v13' was introduced in PackageDescription 5.1")) + } } func testBuildSettings() throws { From 66684f43b6a3e23585f3e5a0fe3cd34e156ccbda Mon Sep 17 00:00:00 2001 From: Noah Gilmore Date: Thu, 6 Jun 2019 21:01:28 -0700 Subject: [PATCH 36/67] [Documentation] Note Ninja Build requirement in development docs --- Documentation/Development.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Documentation/Development.md b/Documentation/Development.md index 852e80d5c5a..8fd6ef0da70 100644 --- a/Documentation/Development.md +++ b/Documentation/Development.md @@ -63,6 +63,8 @@ using a [snapshot](https://swift.org/download/#releases) from swift.org. $ cd swiftpm $ Utilities/bootstrap ``` + + Note: The bootstrap script requires having [Ninja](https://ninja-build.org/) installed. This command will build the Package Manager inside `.build/` directory. Run the bootstrap script to rebuild after making a change to the source From 96e7174273c4a552636e6034221e46808530bb9a Mon Sep 17 00:00:00 2001 From: Noah Gilmore Date: Thu, 6 Jun 2019 21:18:28 -0700 Subject: [PATCH 37/67] Note CMake requirement in development documentation and link to Swift docs --- Documentation/Development.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Development.md b/Documentation/Development.md index 8fd6ef0da70..f6f7976f7bf 100644 --- a/Documentation/Development.md +++ b/Documentation/Development.md @@ -64,7 +64,7 @@ using a [snapshot](https://swift.org/download/#releases) from swift.org. $ Utilities/bootstrap ``` - Note: The bootstrap script requires having [Ninja](https://ninja-build.org/) installed. + Note: The bootstrap script requires having [CMake](https://cmake.org/) and [Ninja](https://ninja-build.org/) installed. Please refer to the [Swift project repo](https://github.com/apple/swift/blob/master/README.md#macos) for installation instructions. This command will build the Package Manager inside `.build/` directory. Run the bootstrap script to rebuild after making a change to the source From 431e5eea79131441124911c0a375260560b301da Mon Sep 17 00:00:00 2001 From: Aleph Retamal Date: Tue, 4 Jun 2019 09:38:34 +1000 Subject: [PATCH 38/67] Update Usage.md Remove the phrase saying iOS, watchOS, and tvOS are not supported --- Documentation/Usage.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Documentation/Usage.md b/Documentation/Usage.md index 8cb858ba157..1dffb3a23eb 100644 --- a/Documentation/Usage.md +++ b/Documentation/Usage.md @@ -684,11 +684,8 @@ A C language target is build with following flags in release mode: ## Depending on Apple Modules -At this time there is no explicit support for depending on UIKit, AppKit, etc, -though importing these modules should work if they are present in the proper -system location. We will add explicit support for system dependencies in the -future. Note that at this time the Package Manager has no support for iOS, -watchOS, or tvOS platforms. +Swift Package Manager includes a build system that can build for macOS and Linux. +Xcode 11 integrates with libSwiftPM to provide support for iOS, watchOS, and tvOS platforms. ## C language targets From 39a55bf888a1199bbbce67df51eaf9275bff5749 Mon Sep 17 00:00:00 2001 From: Gwen Mittertreiner Date: Sun, 7 Apr 2019 14:36:11 -0700 Subject: [PATCH 39/67] Remove SPMLibC from FileInfo --- Sources/Basic/FileInfo.swift | 79 ++++++++++---------------- Sources/Basic/FileSystem.swift | 7 +-- Sources/SPMLLBuild/llbuild.swift | 2 +- Tests/BasicTests/FileSystemTests.swift | 4 +- 4 files changed, 36 insertions(+), 56 deletions(-) diff --git a/Sources/Basic/FileInfo.swift b/Sources/Basic/FileInfo.swift index e162bdbc48b..740ebd0af09 100644 --- a/Sources/Basic/FileInfo.swift +++ b/Sources/Basic/FileInfo.swift @@ -8,71 +8,54 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -import SPMLibc import Foundation /// File system information for a particular file. public struct FileInfo: Equatable, Codable { - /// File timestamp wrapper. - public struct FileTimestamp: Equatable, Codable { - public let seconds: UInt64 - public let nanoseconds: UInt64 - } - - /// File system entity kind. - public enum Kind: String, Codable { - case file, directory, symlink, blockdev, chardev, socket, unknown - - fileprivate init(mode: mode_t) { - switch mode { - case S_IFREG: self = .file - case S_IFDIR: self = .directory - case S_IFLNK: self = .symlink - case S_IFBLK: self = .blockdev - case S_IFCHR: self = .chardev - case S_IFSOCK: self = .socket - default: - self = .unknown - } - } - } - /// The device number. public let device: UInt64 /// The inode number. public let inode: UInt64 - /// The mode flags of the file. - public let mode: UInt64 - /// The size of the file. public let size: UInt64 /// The modification time of the file. - public let modTime: FileTimestamp + public let modTime: Date /// Kind of file system entity. - public var kind: Kind { - return Kind(mode: mode_t(mode) & S_IFMT) - } + public let posixPermissions: Int16 + + /// Kind of file system entity. + public let fileType: FileAttributeType + + public init(_ attrs: [FileAttributeKey : Any]) { + let device = (attrs[.systemNumber] as? NSNumber)?.uint64Value + assert(device != nil) + self.device = device! + + let inode = attrs[.systemFileNumber] as? UInt64 + assert(inode != nil) + self.inode = inode! + + let posixPermissions = (attrs[.posixPermissions] as? NSNumber)?.int16Value + assert(posixPermissions != nil) + self.posixPermissions = posixPermissions! - public init(_ buf: SPMLibc.stat) { - self.device = UInt64(buf.st_dev) - self.inode = UInt64(buf.st_ino) - self.mode = UInt64(buf.st_mode) - self.size = UInt64(buf.st_size) - - #if canImport(Darwin) - let seconds = buf.st_mtimespec.tv_sec - let nanoseconds = buf.st_mtimespec.tv_nsec - #else - let seconds = buf.st_mtim.tv_sec - let nanoseconds = buf.st_mtim.tv_nsec - #endif - - self.modTime = FileTimestamp( - seconds: UInt64(seconds), nanoseconds: UInt64(nanoseconds)) + let fileType = attrs[.type] as? FileAttributeType + assert(fileType != nil) + self.fileType = fileType! + + let size = attrs[.size] as? UInt64 + assert(size != nil) + self.size = size! + + let modTime = attrs[.modificationDate] as? Date + assert(modTime != nil) + self.modTime = modTime! } } + +extension FileAttributeType: Codable {} diff --git a/Sources/Basic/FileSystem.swift b/Sources/Basic/FileSystem.swift index 23771775bb3..51d25b9b19a 100644 --- a/Sources/Basic/FileSystem.swift +++ b/Sources/Basic/FileSystem.swift @@ -259,11 +259,8 @@ private class LocalFileSystem: FileSystem { } func getFileInfo(_ path: AbsolutePath) throws -> FileInfo { - let path = path.pathString - var statBuf = SPMLibc.stat() - let rv = stat(path, &statBuf) - guard rv == 0 else { throw SystemError.stat(errno, path) } - return FileInfo(statBuf) + let attrs = try FileManager.default.attributesOfItem(atPath: path.pathString) + return FileInfo(attrs) } var currentWorkingDirectory: AbsolutePath? { diff --git a/Sources/SPMLLBuild/llbuild.swift b/Sources/SPMLLBuild/llbuild.swift index 128f85a2461..065b0b5595d 100644 --- a/Sources/SPMLLBuild/llbuild.swift +++ b/Sources/SPMLLBuild/llbuild.swift @@ -95,7 +95,7 @@ public final class LLBuildEngine { return T.BuildValue(value) } - public func attachDB(path: String, schemaVersion: Int = 0) throws { + public func attachDB(path: String, schemaVersion: Int = 1) throws { try engine.attachDB(path: path, schemaVersion: schemaVersion) } diff --git a/Tests/BasicTests/FileSystemTests.swift b/Tests/BasicTests/FileSystemTests.swift index 2ea744b67a7..7d6bc49a69c 100644 --- a/Tests/BasicTests/FileSystemTests.swift +++ b/Tests/BasicTests/FileSystemTests.swift @@ -29,7 +29,7 @@ class FileSystemTests: XCTestCase { let file = try! TemporaryFile() XCTAssertTrue(fs.exists(file.path)) XCTAssertTrue(fs.isFile(file.path)) - XCTAssertEqual(try fs.getFileInfo(file.path).kind, .file) + XCTAssertEqual(try fs.getFileInfo(file.path).fileType, .typeRegular) XCTAssertFalse(fs.isDirectory(file.path)) XCTAssertFalse(fs.isFile(AbsolutePath("/does-not-exist"))) XCTAssertFalse(fs.isSymlink(AbsolutePath("/does-not-exist"))) @@ -41,7 +41,7 @@ class FileSystemTests: XCTestCase { try! createSymlink(sym, pointingAt: file.path) XCTAssertTrue(fs.isSymlink(sym)) XCTAssertTrue(fs.isFile(sym)) - XCTAssertEqual(try fs.getFileInfo(sym).kind, .file) + XCTAssertEqual(try fs.getFileInfo(sym).fileType, .typeSymbolicLink) XCTAssertFalse(fs.isDirectory(sym)) // isExecutableFile From 095a4e81df02b3ee762e9112cb7097ebab92c92f Mon Sep 17 00:00:00 2001 From: Antonio Mayorga Date: Mon, 10 Jun 2019 19:50:13 -0700 Subject: [PATCH 40/67] =?UTF-8?q?Fixed=20argument=20parser=20so=20it=20thr?= =?UTF-8?q?ows=20an=20error=20when=20given=20multiple=20value=E2=80=A6=20(?= =?UTF-8?q?#2145)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixed argument parser so it throws an error when given multiple values are provided for a single value argument * Reverted unintended diff for MiscellaneousTest and XCTestManifests --- Sources/SPMUtility/ArgumentParser.swift | 10 ++++++++++ Tests/UtilityTests/ArgumentParserTests.swift | 12 ++++++++++++ Tests/UtilityTests/XCTestManifests.swift | 1 + 3 files changed, 23 insertions(+) diff --git a/Sources/SPMUtility/ArgumentParser.swift b/Sources/SPMUtility/ArgumentParser.swift index 8ef3b3fe58d..80054d5d0b2 100644 --- a/Sources/SPMUtility/ArgumentParser.swift +++ b/Sources/SPMUtility/ArgumentParser.swift @@ -29,6 +29,9 @@ public enum ArgumentParserError: Swift.Error { /// Expected these positional arguments but not found. case expectedArguments(ArgumentParser, [String]) + + /// Expected a single argument but got multiple ones. + case duplicateArgument(String) } extension ArgumentParserError: LocalizedError { @@ -50,6 +53,8 @@ extension ArgumentParserError: CustomStringConvertible { return "unexpected argument \(argument); use --help to list available arguments" case .expectedArguments(_, let arguments): return "expected arguments: \(arguments.joined(separator: ", "))" + case .duplicateArgument(let option): + return "expected single value for argument: \(option)" } } } @@ -556,6 +561,11 @@ public final class ArgumentParser { assertionFailure() return } + + guard results[argument.name] == nil else { + throw ArgumentParserError.duplicateArgument(argument.name) + } + results[argument.name] = value } } diff --git a/Tests/UtilityTests/ArgumentParserTests.swift b/Tests/UtilityTests/ArgumentParserTests.swift index b440794517f..008442acfbe 100644 --- a/Tests/UtilityTests/ArgumentParserTests.swift +++ b/Tests/UtilityTests/ArgumentParserTests.swift @@ -724,4 +724,16 @@ class ArgumentParserTests: XCTestCase { args = try parser.parse(["0"]) XCTAssertEqual(args.get(positional), 0) } + + func testSingleValueMultipleTimes() throws { + let parser = ArgumentParser(usage: "sample", overview: "sample") + _ = parser.add(option: "--verbosity", kind: Int.self) + + do { + _ = try parser.parse(["--verbosity", "5", "--verbosity", "6"]) + XCTFail("unexpected success") + } catch ArgumentParserError.duplicateArgument(let argument) { + XCTAssertEqual(argument, "--verbosity") + } + } } diff --git a/Tests/UtilityTests/XCTestManifests.swift b/Tests/UtilityTests/XCTestManifests.swift index 58841b468e0..58f489e9241 100644 --- a/Tests/UtilityTests/XCTestManifests.swift +++ b/Tests/UtilityTests/XCTestManifests.swift @@ -16,6 +16,7 @@ extension ArgumentParserTests { ("testPathArgument", testPathArgument), ("testRemainingStrategy", testRemainingStrategy), ("testShellCompletionGeneration", testShellCompletionGeneration), + ("testSingleValueMultipleTimes", testSingleValueMultipleTimes), ("testSubparser", testSubparser), ("testSubparserBinder", testSubparserBinder), ("testSubsubparser", testSubsubparser), From 796b5af95dc83688b395865d2eae127022ff690e Mon Sep 17 00:00:00 2001 From: Jason R Tibbetts <708510+jrtibbetts@users.noreply.github.com> Date: Tue, 11 Jun 2019 10:17:20 -0400 Subject: [PATCH 41/67] Added a missing word to an error message. (#2148) --- Sources/PackageGraph/DependencyResolver.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/PackageGraph/DependencyResolver.swift b/Sources/PackageGraph/DependencyResolver.swift index 62978609eb4..b7c16431ab8 100644 --- a/Sources/PackageGraph/DependencyResolver.swift +++ b/Sources/PackageGraph/DependencyResolver.swift @@ -79,7 +79,7 @@ public enum DependencyResolverError: Error, Equatable, CustomStringConvertible { case let .missingVersions(constraints): let stream = BufferedOutputByteStream() - stream <<< "the package dependency graph could not be resolved; unable find any available tag for the following requirements:\n" + stream <<< "the package dependency graph could not be resolved; unable to find any available tag for the following requirements:\n" for (i, constraint) in constraints.enumerated() { stream <<< " " stream <<< "\(constraint.identifier.path)" <<< " @ " From 3d3ce87ea6b8bddea4edc7232df362dd7fc98127 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Tue, 11 Jun 2019 07:20:10 -0700 Subject: [PATCH 42/67] Add link to SourceKit-LSP (#2146) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 63711238fc0..8e147b4c677 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ We’ve designed the system to make it easy to share packages on services like G Swift Package Manager includes a build system that can build for macOS and Linux. Xcode 11 integrates with libSwiftPM to provide support for iOS, watchOS, and tvOS platforms. +The [SourceKit-LSP](https://github.com/apple/sourcekit-lsp) project leverages libSwiftPM and provides Language Server Protocol implementation for editors that support LSP. + --- ## Table of Contents From dd109966cf9b8971018d9bba37a0c281a316b9dc Mon Sep 17 00:00:00 2001 From: TaborKelly Date: Tue, 11 Jun 2019 08:14:31 -0700 Subject: [PATCH 43/67] Add a --jobs/-j to limit parallel compilation (#2127) * Add a --numThreads/-j to limit parallel compilation which can cause OOM killer problems on some Linux systems. * Clarify that what we are really talking about is llbuild jobs. Go back to old BuildParameters. * PR feedback: better help message and correct -j value. --- Sources/Commands/Options.swift | 3 +++ Sources/Commands/SwiftTool.swift | 11 +++++++++++ 2 files changed, 14 insertions(+) diff --git a/Sources/Commands/Options.swift b/Sources/Commands/Options.swift index 417eccc72a1..126c71492d1 100644 --- a/Sources/Commands/Options.swift +++ b/Sources/Commands/Options.swift @@ -77,5 +77,8 @@ public class ToolOptions { /// Write dependency resolver trace to a file. public var enableResolverTrace = false + /// The number of jobs for llbuild to start (aka the number of schedulerLanes) + public var jobs: UInt32? = nil + public required init() {} } diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 42d033333d5..7b9eb04f1bb 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -366,6 +366,11 @@ public class SwiftTool { option: parser.add(option: "--trace-resolver", kind: Bool.self), to: { $0.enableResolverTrace = $1 }) + binder.bind( + option: parser.add(option: "--jobs", shortName: "-j", kind: Int.self, + usage: "The number of jobs to spawn in parallel during the build process"), + to: { $0.jobs = UInt32($1) }) + // Let subclasses bind arguments. type(of: self).defineArguments(parser: parser, binder: binder) @@ -642,6 +647,9 @@ public class SwiftTool { buildDelegate.isVerbose = isVerbose let databasePath = buildPath.appending(component: "build.db").pathString + if let jobs = options.jobs { + BuildSystem.setSchedulerLaneWidth(width: jobs) + } let buildSystem = BuildSystem(buildFile: manifest.pathString, databaseFile: databasePath, delegate: buildDelegate) buildDelegate.onCommmandFailure = { buildSystem.cancel() } @@ -677,6 +685,9 @@ public class SwiftTool { if verbosity != .concise { args.append("-v") } + if let jobs = options.jobs { + args.append("-j\(jobs)") + } // Create the environment for llbuild. var env = Process.env From 87a554b7e2c4a862d3ea077b4e261623a93a86b3 Mon Sep 17 00:00:00 2001 From: Ed Arenberg Date: Tue, 11 Jun 2019 10:17:22 -0700 Subject: [PATCH 44/67] [SR-10794] Close option suggestions (#2144) * Suggest Close Options [SR-10794] * Add Test for Suggestion * Added a comment about #available requirement, and some additional test cases * Add `bestMatch` function and clean up description * Tweak comment --- Sources/Basic/EditDistance.swift | 20 ++++++++++++++ Sources/SPMUtility/ArgumentParser.swift | 13 ++++++--- Tests/UtilityTests/ArgumentParserTests.swift | 28 +++++++++++++++----- 3 files changed, 51 insertions(+), 10 deletions(-) diff --git a/Sources/Basic/EditDistance.swift b/Sources/Basic/EditDistance.swift index 4873068bc54..7d04d650172 100644 --- a/Sources/Basic/EditDistance.swift +++ b/Sources/Basic/EditDistance.swift @@ -13,6 +13,8 @@ /// - Complexity: O(_n*m_), where *n* is the length of the first String and /// *m* is the length of the second one. public func editDistance(_ first: String, _ second: String) -> Int { + // FIXME: We should use the new `CollectionDifference` API once the + // deployment target is bumped. let a = Array(first.utf16) let b = Array(second.utf16) var distance = [[Int]](repeating: [Int](repeating: 0, count: b.count + 1), count: a.count + 1) @@ -34,3 +36,21 @@ public func editDistance(_ first: String, _ second: String) -> Int { } return distance[a.count][b.count] } + +/// Finds the "best" match for a `String` from an array of possible options. +/// +/// - Parameters: +/// - input: The input `String` to match. +/// - options: The available options for `input`. +/// +/// - Returns: The best match from the given `options`, or `nil` if none were sufficiently close. +public func bestMatch(for input: String, from options: [String]) -> String? { + return options + .map { ($0, editDistance(input, $0)) } + // Filter out unreasonable edit distances. Based on: + // https://github.com/apple/swift/blob/37daa03b7dc8fb3c4d91dc560a9e0e631c980326/lib/Sema/TypeCheckNameLookup.cpp#L606 + .filter { $0.1 <= ($0.0.count + 2) / 3 } + // Sort by edit distance + .sorted { $0.1 < $1.1 } + .first?.0 +} diff --git a/Sources/SPMUtility/ArgumentParser.swift b/Sources/SPMUtility/ArgumentParser.swift index 80054d5d0b2..a623ed6f0a3 100644 --- a/Sources/SPMUtility/ArgumentParser.swift +++ b/Sources/SPMUtility/ArgumentParser.swift @@ -16,7 +16,7 @@ import func SPMLibc.exit public enum ArgumentParserError: Swift.Error { /// An unknown option is encountered. - case unknownOption(String) + case unknownOption(String, suggestion: String?) /// The value of an argument is invalid. case invalidValue(argument: String, error: ArgumentConversionError) @@ -43,8 +43,12 @@ extension ArgumentParserError: LocalizedError { extension ArgumentParserError: CustomStringConvertible { public var description: String { switch self { - case .unknownOption(let option): - return "unknown option \(option); use --help to list available options" + case .unknownOption(let option, let suggestion): + var desc = "unknown option \(option); use --help to list available options" + if let suggestion = suggestion { + desc += "\nDid you mean \(suggestion)?" + } + return desc case .invalidValue(let argument, let error): return "\(error) for argument \(argument); use --help to print usage" case .expectedValue(let option): @@ -847,7 +851,8 @@ public final class ArgumentParser { let (argumentString, value) = argumentString.spm_split(around: "=") // Get the corresponding option for the option argument. guard let optionArgument = optionsMap[argumentString] else { - throw ArgumentParserError.unknownOption(argumentString) + let suggestion = bestMatch(for: argumentString, from: Array(optionsMap.keys)) + throw ArgumentParserError.unknownOption(argumentString, suggestion: suggestion) } argument = optionArgument diff --git a/Tests/UtilityTests/ArgumentParserTests.swift b/Tests/UtilityTests/ArgumentParserTests.swift index 008442acfbe..eaffcd1ae7a 100644 --- a/Tests/UtilityTests/ArgumentParserTests.swift +++ b/Tests/UtilityTests/ArgumentParserTests.swift @@ -120,8 +120,24 @@ class ArgumentParserTests: XCTestCase { do { _ = try parser.parse(["foo", "--bar"]) XCTFail("unexpected success") - } catch ArgumentParserError.unknownOption(let option) { + } catch ArgumentParserError.unknownOption(let option, let suggestion) { XCTAssertEqual(option, "--bar") + XCTAssertNil(suggestion) + } + + do { + _ = try parser.parse(["--food"]) + XCTFail("unexpected success") + } catch ArgumentParserError.unknownOption(let option, let suggestion) { + XCTAssertEqual(option, "--food") + XCTAssertEqual(suggestion, "--foo") + } + do { + _ = try parser.parse(["--verb"]) + XCTFail("unexpected success") + } catch ArgumentParserError.unknownOption(let option, let suggestion) { + XCTAssertEqual(option, "--verb") + XCTAssertNil(suggestion) } do { @@ -286,19 +302,19 @@ class ArgumentParserTests: XCTestCase { do { args = try parser.parse(["--foo", "foo", "b", "--no-fly", "--branch", "bugfix"]) - } catch ArgumentParserError.unknownOption(let arg) { + } catch ArgumentParserError.unknownOption(let arg, _) { XCTAssertEqual(arg, "--branch") } do { args = try parser.parse(["--foo", "foo", "a", "--branch", "bugfix", "--no-fly"]) - } catch ArgumentParserError.unknownOption(let arg) { + } catch ArgumentParserError.unknownOption(let arg, _) { XCTAssertEqual(arg, "--no-fly") } do { args = try parser.parse(["a", "--branch", "bugfix", "--foo"]) - } catch ArgumentParserError.unknownOption(let arg) { + } catch ArgumentParserError.unknownOption(let arg, _) { XCTAssertEqual(arg, "--foo") } @@ -374,7 +390,7 @@ class ArgumentParserTests: XCTestCase { do { args = try parser.parse(["foo", "bar", "--no-fly"]) - } catch ArgumentParserError.unknownOption(let arg) { + } catch ArgumentParserError.unknownOption(let arg, _) { XCTAssertEqual(arg, "--no-fly") } } @@ -717,7 +733,7 @@ class ArgumentParserTests: XCTestCase { do { _ = try parser.parse(["-18"]) XCTFail("unexpected success") - } catch ArgumentParserError.unknownOption(let option) { + } catch ArgumentParserError.unknownOption(let option, _) { XCTAssertEqual(option, "-18") } From e6b75cbf1bcb872afe5544f17c14f0391929d303 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Mon, 10 Jun 2019 19:39:41 -0700 Subject: [PATCH 45/67] [Build] Handle unparsable messages during message size parsing Looks like swift compiler can emit a non-parsable message in some cases. --- Sources/Build/BuildDelegate.swift | 11 +++++++---- Sources/Build/SwiftCompilerOutputParser.swift | 8 +++++++- Tests/BuildTests/SwiftCompilerOutputParserTests.swift | 8 ++++++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/Sources/Build/BuildDelegate.swift b/Sources/Build/BuildDelegate.swift index dcb1703564e..0247002687c 100644 --- a/Sources/Build/BuildDelegate.swift +++ b/Sources/Build/BuildDelegate.swift @@ -432,7 +432,7 @@ fileprivate struct CommandTaskTracker { } finishedCount += 1 - case .signalled, .skipped: + case .unparsableOutput, .signalled, .skipped: break } } @@ -482,9 +482,10 @@ fileprivate struct CommandTaskTracker { extension SwiftCompilerMessage { fileprivate var verboseProgressText: String? { - if case .began(let info) = kind { + switch kind { + case .began(let info): return ([info.commandExecutable] + info.commandArguments).joined(separator: " ") - } else { + case .skipped, .finished, .signalled, .unparsableOutput: return nil } } @@ -494,7 +495,9 @@ extension SwiftCompilerMessage { case .finished(let info), .signalled(let info): return info.output - default: + case .unparsableOutput(let output): + return output + case .skipped, .began: return nil } } diff --git a/Sources/Build/SwiftCompilerOutputParser.swift b/Sources/Build/SwiftCompilerOutputParser.swift index 1d2183b69f4..c6a624af019 100644 --- a/Sources/Build/SwiftCompilerOutputParser.swift +++ b/Sources/Build/SwiftCompilerOutputParser.swift @@ -41,6 +41,7 @@ struct SwiftCompilerMessage { case skipped(SkippedInfo) case finished(OutputInfo) case signalled(OutputInfo) + case unparsableOutput(String) } let name: String @@ -166,7 +167,12 @@ private extension SwiftCompilerOutputParser { } guard let messageSize = Int(string) else { - throw ParsingError(reason: "invalid message size") + // Non-parseable chunks are *assumed* to be output. E.g., you get + // a "remark" if you build with SWIFTC_MAXIMUM_DETERMINISM env variable. + let message = SwiftCompilerMessage(name: "unknown", kind: .unparsableOutput(string)) + delegate?.swiftCompilerOutputParser(self, didParse: message) + buffer.removeAll() + return } buffer.removeAll() diff --git a/Tests/BuildTests/SwiftCompilerOutputParserTests.swift b/Tests/BuildTests/SwiftCompilerOutputParserTests.swift index a3a092443c4..269f8fde6d7 100644 --- a/Tests/BuildTests/SwiftCompilerOutputParserTests.swift +++ b/Tests/BuildTests/SwiftCompilerOutputParserTests.swift @@ -211,7 +211,9 @@ class SwiftCompilerOutputParserTests: XCTestCase { 2A """.utf8) - delegate.assert(messages: [], errorDescription: "invalid message size") + delegate.assert(messages: [ + SwiftCompilerMessage(name: "unknown", kind: .unparsableOutput("2A")) + ], errorDescription: nil) parser.parse(bytes: """ 119 @@ -223,7 +225,9 @@ class SwiftCompilerOutputParserTests: XCTestCase { "signal": 4 } """.utf8) - delegate.assert(messages: [], errorDescription: nil) + delegate.assert(messages: [ + SwiftCompilerMessage(name: "link", kind: .signalled(.init(pid: 22699, output: nil))) + ], errorDescription: nil) } func testInvalidMessageBytes() { From 84b993ee95a1ee78b7a7676b22b8c218f01cc0ec Mon Sep 17 00:00:00 2001 From: Boris Buegling Date: Tue, 11 Jun 2019 14:05:07 -0700 Subject: [PATCH 46/67] Init type "manifest" was missing from help --- Sources/Commands/SwiftPackageTool.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/Commands/SwiftPackageTool.swift b/Sources/Commands/SwiftPackageTool.swift index 3610c6b0728..bee5ea65268 100644 --- a/Sources/Commands/SwiftPackageTool.swift +++ b/Sources/Commands/SwiftPackageTool.swift @@ -363,7 +363,7 @@ public class SwiftPackageTool: SwiftTool { binder.bind( option: initPackageParser.add( option: "--type", kind: InitPackage.PackageType.self, - usage: "empty|library|executable|system-module"), + usage: "empty|library|executable|system-module|manifest"), to: { $0.initMode = $1 }) binder.bind( From 79c84708de5a74483ccb2f33cda82e15d368c846 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Tue, 11 Jun 2019 12:16:36 -0700 Subject: [PATCH 47/67] [PackageGraph] Ensure container is of the RepositoryContainer type ... when diagnosing unavailable versions. --- Sources/PackageGraph/DependencyResolver.swift | 9 +++++++++ .../RepositoryPackageContainerProvider.swift | 4 ++++ Sources/TestSupport/MockDependencyResolver.swift | 4 ++++ 3 files changed, 17 insertions(+) diff --git a/Sources/PackageGraph/DependencyResolver.swift b/Sources/PackageGraph/DependencyResolver.swift index b7c16431ab8..afa464c0c3f 100644 --- a/Sources/PackageGraph/DependencyResolver.swift +++ b/Sources/PackageGraph/DependencyResolver.swift @@ -316,6 +316,13 @@ public protocol PackageContainer { /// after the container is available. The updated identifier is returned in result of the /// dependency resolution. func getUpdatedIdentifier(at boundVersion: BoundVersion) throws -> PackageReference + + /// Hack for the old resolver. Don't use. + var _isRemoteContainer: Bool? { get } +} + +extension PackageContainer { + public var _isRemoteContainer: Bool? { return nil } } /// An interface for resolving package containers. @@ -1006,6 +1013,8 @@ public class DependencyResolver { let constraintsWithNoAvailableVersions = constraints.filter { constraint in if case .versionSet(let versions) = constraint.requirement, let container = try? getContainer(for: constraint.identifier), + // FIXME: This is hacky but we should be moving away from this resolver anyway. + container._isRemoteContainer == true, !container.versions(filter: versions.contains).contains(where: { _ in true }) { return true } diff --git a/Sources/PackageGraph/RepositoryPackageContainerProvider.swift b/Sources/PackageGraph/RepositoryPackageContainerProvider.swift index 1790ffcf71d..e8d1d42beaa 100644 --- a/Sources/PackageGraph/RepositoryPackageContainerProvider.swift +++ b/Sources/PackageGraph/RepositoryPackageContainerProvider.swift @@ -324,6 +324,10 @@ public class RepositoryPackageContainer: BasePackageContainer, CustomStringConve return "RepositoryPackageContainer(\(identifier.repository.url.debugDescription))" } + public var _isRemoteContainer: Bool { + return true + } + public func getTag(for version: Version) -> String? { return knownVersions[version] } diff --git a/Sources/TestSupport/MockDependencyResolver.swift b/Sources/TestSupport/MockDependencyResolver.swift index 5e7eba10a03..decc5824a4f 100644 --- a/Sources/TestSupport/MockDependencyResolver.swift +++ b/Sources/TestSupport/MockDependencyResolver.swift @@ -149,6 +149,10 @@ public class MockPackageContainer: PackageContainer { self._versions = versions.sorted().reversed() self.dependencies = dependencies } + + public var _isRemoteContainer: Bool? { + return true + } } public class MockPackageContainer2: MockPackageContainer { From cc5678612366e2d84c57cfc2339db8f0e7d951f3 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Tue, 11 Jun 2019 13:18:56 -0700 Subject: [PATCH 48/67] Isolate ModuleCache for SwiftPM tests To workaround the ModuleCache issues that we've been seeing on Swift CI --- Sources/Build/BuildPlan.swift | 14 +++----------- Sources/Commands/SwiftTool.swift | 3 +-- Sources/PackageLoading/ManifestLoader.swift | 17 ++++++++++++++--- Sources/TestSupport/SwiftPMProduct.swift | 2 +- 4 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index 181976bcc78..fb8ae3c572c 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -26,22 +26,14 @@ public struct BuildParameters { case auto } - // FIXME: Error handling. - // - /// Path to the module cache directory to use for SwiftPM's own tests. - public static let swiftpmTestCache = resolveSymlinks(try! determineTempDirectory()).appending(component: "org.swift.swiftpm.tests-3") - /// Returns the directory to be used for module cache. fileprivate var moduleCache: AbsolutePath { - let base: AbsolutePath // FIXME: We use this hack to let swiftpm's functional test use shared // cache so it doesn't become painfully slow. - if Process.env["IS_SWIFTPM_TEST"] != nil { - base = BuildParameters.swiftpmTestCache - } else { - base = buildPath + if let path = Process.env["SWIFTPM_TESTS_MODULECACHE"] { + return AbsolutePath(path) } - return base.appending(component: "ModuleCache") + return buildPath.appending(component: "ModuleCache") } /// The path to the data directory. diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 7b9eb04f1bb..42a65e1251a 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -675,7 +675,6 @@ public class SwiftTool { let allowedDirectories = [ tempDir, buildPath, - BuildParameters.swiftpmTestCache ].map(resolveSymlinks) args += ["sandbox-exec", "-p", sandboxProfile(allowedDirectories: allowedDirectories)] } @@ -842,7 +841,7 @@ private func findPackageRoot() -> AbsolutePath? { /// Returns the build path from the environment, if present. private func getEnvBuildPath(workingDir: AbsolutePath) -> AbsolutePath? { // Don't rely on build path from env for SwiftPM's own tests. - guard Process.env["IS_SWIFTPM_TEST"] == nil else { return nil } + guard Process.env["SWIFTPM_TESTS_MODULECACHE"] == nil else { return nil } guard let env = Process.env["SWIFTPM_BUILD_DIR"] else { return nil } return AbsolutePath(env, relativeTo: workingDir) } diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 530bedbe3ba..881606a171d 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -384,13 +384,21 @@ public final class ManifestLoader: ManifestLoaderProtocol { let runtimePath = self.runtimePath(for: manifestVersion).pathString let interpreterFlags = self.interpreterFlags(for: manifestVersion) + // FIXME: Workaround for the module cache bug that's been haunting Swift CI + // + let moduleCachePath = Process.env["SWIFTPM_TESTS_MODULECACHE"] + var cmd = [String]() #if os(macOS) // If enabled, use sandbox-exec on macOS. This provides some safety against // arbitrary code execution when parsing manifest files. We only allow // the permissions which are absolutely necessary for manifest parsing. if isManifestSandboxEnabled { - cmd += ["sandbox-exec", "-p", sandboxProfile(cacheDir)] + let cacheDirs = [ + cacheDir, + moduleCachePath.map{ AbsolutePath($0) } + ].compactMap{$0} + cmd += ["sandbox-exec", "-p", sandboxProfile(cacheDirs)] } #endif cmd += [resources.swiftCompiler.pathString] @@ -399,6 +407,9 @@ public final class ManifestLoader: ManifestLoaderProtocol { cmd += verbosity.ccArgs cmd += ["-L", runtimePath, "-lPackageDescription"] cmd += interpreterFlags + if let moduleCachePath = moduleCachePath { + cmd += ["-module-cache-path", moduleCachePath] + } // Add the arguments for emitting serialized diagnostics, if requested. if serializedDiagnostics, cacheDir != nil { @@ -542,7 +553,7 @@ public final class ManifestLoader: ManifestLoaderProtocol { } /// Returns the sandbox profile to be used when parsing manifest on macOS. -private func sandboxProfile(_ cacheDir: AbsolutePath? = nil) -> String { +private func sandboxProfile(_ cacheDirs: [AbsolutePath] = []) -> String { let stream = BufferedOutputByteStream() stream <<< "(version 1)" <<< "\n" // Deny everything by default. @@ -559,7 +570,7 @@ private func sandboxProfile(_ cacheDir: AbsolutePath? = nil) -> String { for directory in Platform.darwinCacheDirectories() { stream <<< " (regex #\"^\(directory.pathString)/org\\.llvm\\.clang.*\")" <<< "\n" } - if let cacheDir = cacheDir { + for cacheDir in cacheDirs { stream <<< " (subpath \"\(cacheDir.pathString)\")" <<< "\n" } stream <<< ")" <<< "\n" diff --git a/Sources/TestSupport/SwiftPMProduct.swift b/Sources/TestSupport/SwiftPMProduct.swift index 07799ae1b7e..0495eeb3e2c 100644 --- a/Sources/TestSupport/SwiftPMProduct.swift +++ b/Sources/TestSupport/SwiftPMProduct.swift @@ -115,7 +115,7 @@ public enum SwiftPMProduct { #endif // FIXME: We use this private environment variable hack to be able to // create special conditions in swift-build for swiftpm tests. - environment["IS_SWIFTPM_TEST"] = "1" + environment["SWIFTPM_TESTS_MODULECACHE"] = self.path.parentDirectory.pathString environment["SDKROOT"] = nil var completeArgs = [path.pathString] From 3e5b1ea3ca095335a8dc15cd65689709003ef2a4 Mon Sep 17 00:00:00 2001 From: BJ Homer Date: Wed, 12 Jun 2019 06:49:24 -0600 Subject: [PATCH 49/67] Fix some formatting --- Documentation/Usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Documentation/Usage.md b/Documentation/Usage.md index 1dffb3a23eb..cdcfb89ab62 100644 --- a/Documentation/Usage.md +++ b/Documentation/Usage.md @@ -575,7 +575,7 @@ changes (e.g. because a teammate pushed a new version of the file) the next resolve command will update packages to match that file. After a successful resolve command, the checked out versions of all dependencies and the versions recorded in the resolved versions file will match. In most cases the resolve -command will perform no changes unless the `Package.swift manifest or +command will perform no changes unless the `Package.swift` manifest or `Package.resolved` file have changed. Most SwiftPM commands will implicitly invoke the swift package resolve From a8c2b02bb1d7e96888ec26627a1336295336cc23 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 12 Jun 2019 11:38:42 -0700 Subject: [PATCH 50/67] Support new XCTest overlays --- Sources/Commands/SwiftTestTool.swift | 5 +++-- Sources/TestSupport/Resources.swift | 2 +- Sources/Workspace/Destination.swift | 32 +++++++++++++++++++++------- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index 660217448d0..32b50293168 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -477,8 +477,9 @@ public class SwiftTestTool: SwiftTool { var env = try constructTestEnvironment(toolchain: try getToolchain(), options: self.options, buildParameters: self.buildParameters()) // Add the sdk platform path if we have it. If this is not present, we // might always end up failing. - if let sdkPlatformFrameworksPath = Destination.sdkPlatformFrameworkPath() { - env["DYLD_FRAMEWORK_PATH"] = sdkPlatformFrameworksPath.pathString + if let sdkPlatformFrameworksPath = Destination.sdkPlatformFrameworkPaths() { + env["DYLD_FRAMEWORK_PATH"] = sdkPlatformFrameworksPath.fwk.pathString + env["DYLD_LIBRARY_PATH"] = sdkPlatformFrameworksPath.lib.pathString } try Process.checkNonZeroExit(arguments: args, environment: env) // Read the temporary file's content. diff --git a/Sources/TestSupport/Resources.swift b/Sources/TestSupport/Resources.swift index fe05e9a8b11..49f0506c6fa 100644 --- a/Sources/TestSupport/Resources.swift +++ b/Sources/TestSupport/Resources.swift @@ -36,7 +36,7 @@ public class Resources: ManifestResourceProvider { #if os(macOS) public var sdkPlatformFrameworksPath: AbsolutePath { - return Destination.sdkPlatformFrameworkPath()! + return Destination.sdkPlatformFrameworkPaths()!.fwk } #endif diff --git a/Sources/Workspace/Destination.swift b/Sources/Workspace/Destination.swift index 368c77c6758..22bb20f78f9 100644 --- a/Sources/Workspace/Destination.swift +++ b/Sources/Workspace/Destination.swift @@ -103,15 +103,21 @@ public struct Destination { } // Compute common arguments for clang and swift. - // This is currently just frameworks path. - let commonArgs = Destination.sdkPlatformFrameworkPath(environment: environment).map({ ["-F", $0.pathString] }) ?? [] + var extraCCFlags: [String] = [] + var extraSwiftCFlags: [String] = [] + if let sdkPaths = Destination.sdkPlatformFrameworkPaths(environment: environment) { + extraCCFlags += ["-F", sdkPaths.fwk.pathString] + extraSwiftCFlags += ["-F", sdkPaths.fwk.pathString] + extraSwiftCFlags += ["-I", sdkPaths.lib.pathString] + extraSwiftCFlags += ["-L", sdkPaths.lib.pathString] + } return Destination( target: hostTargetTriple, sdk: sdkPath, binDir: binDir, - extraCCFlags: commonArgs, - extraSwiftCFlags: commonArgs, + extraCCFlags: extraCCFlags, + extraSwiftCFlags: extraSwiftCFlags, extraCPPFlags: ["-lc++"] ) #else @@ -127,21 +133,31 @@ public struct Destination { } /// Returns macosx sdk platform framework path. - public static func sdkPlatformFrameworkPath(environment: [String:String] = Process.env) -> AbsolutePath? { + public static func sdkPlatformFrameworkPaths( + environment: [String:String] = Process.env + ) -> (fwk: AbsolutePath, lib: AbsolutePath)? { if let path = _sdkPlatformFrameworkPath { return path } let platformPath = try? Process.checkNonZeroExit( - arguments: ["xcrun", "--sdk", "macosx", "--show-sdk-platform-path"], environment: environment).spm_chomp() + arguments: ["xcrun", "--sdk", "macosx", "--show-sdk-platform-path"], + environment: environment).spm_chomp() if let platformPath = platformPath, !platformPath.isEmpty { - _sdkPlatformFrameworkPath = AbsolutePath(platformPath).appending( + // For XCTest framework. + let fwk = AbsolutePath(platformPath).appending( components: "Developer", "Library", "Frameworks") + + // For XCTest Swift library. + let lib = AbsolutePath(platformPath).appending( + components: "Developer", "usr", "lib") + + _sdkPlatformFrameworkPath = (fwk, lib) } return _sdkPlatformFrameworkPath } /// Cache storage for sdk platform path. - private static var _sdkPlatformFrameworkPath: AbsolutePath? = nil + private static var _sdkPlatformFrameworkPath: (fwk: AbsolutePath, lib: AbsolutePath)? = nil /// Target triple for the host system. private static let hostTargetTriple = Triple.hostTriple From a9e3d4dacf007f7f5c4c26ab4d01eede102c890f Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 12 Jun 2019 11:49:10 -0700 Subject: [PATCH 51/67] [Build] Disable Swift static linking on macOS --- Sources/Build/BuildPlan.swift | 33 +++++++++++++++++++-------- Tests/BuildTests/BuildPlanTests.swift | 10 +++++++- 2 files changed, 33 insertions(+), 10 deletions(-) diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index fb8ae3c572c..b5a336ebd60 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -664,12 +664,16 @@ public final class ProductBuildDescription { return tempsPath.appending(component: "Objects.LinkFileList") } + /// Diagnostics Engine for emitting diagnostics. + let diagnostics: DiagnosticsEngine + /// Create a build description for a product. - init(product: ResolvedProduct, buildParameters: BuildParameters, fs: FileSystem) { + init(product: ResolvedProduct, buildParameters: BuildParameters, fs: FileSystem, diagnostics: DiagnosticsEngine) { assert(product.type != .library(.automatic), "Automatic type libraries should not be described.") self.product = product self.buildParameters = buildParameters self.fs = fs + self.diagnostics = diagnostics } /// Strips the arguments which should *never* be passed to Swift compiler @@ -724,12 +728,12 @@ public final class ProductBuildDescription { case .library(.dynamic): args += ["-emit-library"] case .executable: - // Link the Swift stdlib statically if requested. - if containsSwiftTargets, - buildParameters.shouldLinkStaticSwiftStdlib { - // FIXME: This does not work for linux yet (SR-648). - if !buildParameters.triple.isLinux() { - args += ["-static-stdlib"] + // Link the Swift stdlib statically, if requested. + // + // FIXME: This does not work for linux yet (SR-648). + if buildParameters.shouldLinkStaticSwiftStdlib { + if buildParameters.triple.isDarwin() { + diagnostics.emit(data: SwiftBackDeployLibrariesNote()) } } args += ["-emit-executable"] @@ -861,7 +865,7 @@ public class BuildPlan { /// The filesystem to operate on. let fileSystem: FileSystem - /// Diagnostics Engine to emit diagnostics + /// Diagnostics Engine for emitting diagnostics. let diagnostics: DiagnosticsEngine /// Create a build plan with build parameters and a package graph. @@ -938,7 +942,8 @@ public class BuildPlan { for product in graph.allProducts where product.type != .library(.automatic) { productMap[product] = ProductBuildDescription( product: product, buildParameters: buildParameters, - fs: fileSystem + fs: fileSystem, + diagnostics: diagnostics ) } @@ -1218,3 +1223,13 @@ struct ProductRequiresHigherPlatformVersion: DiagnosticData { self.platform = platform } } + +struct SwiftBackDeployLibrariesNote: DiagnosticData { + static let id = DiagnosticID( + type: SwiftBackDeployLibrariesNote.self, + name: "org.swift.diags.\(SwiftBackDeployLibrariesNote.self)", + defaultBehavior: .warning, + description: { + $0 <<< "Swift compiler no longer supports statically linking the Swift libraries. They're included in the OS by default starting with macOS Mojave 10.14.4 beta 3. For macOS Mojave 10.14.3 and earlier, there's an optional Swift library package that can be downloaded from \"More Downloads\" for Apple Developers at https://developer.apple.com/download/more/" + }) +} diff --git a/Tests/BuildTests/BuildPlanTests.swift b/Tests/BuildTests/BuildPlanTests.swift index c9ccd35e29d..15d0be36473 100644 --- a/Tests/BuildTests/BuildPlanTests.swift +++ b/Tests/BuildTests/BuildPlanTests.swift @@ -111,7 +111,7 @@ final class BuildPlanTests: XCTestCase { let linkArguments = [ "/fake/path/to/swiftc", "-g", "-L", "/path/to/build/debug", "-o", "/path/to/build/debug/exe", "-module-name", "exe", - "-static-stdlib", "-emit-executable", + "-emit-executable", "@/path/to/build/debug/exe.product/Objects.LinkFileList", "-Xlinker", "-rpath", "-Xlinker", "/fake/path/lib/swift/macosx", ] @@ -126,6 +126,14 @@ final class BuildPlanTests: XCTestCase { #endif XCTAssertEqual(try result.buildProduct(for: "exe").linkArguments(), linkArguments) + + #if os(macOS) + DiagnosticsEngineTester(diagnostics) { result in + result.check(diagnostic: .contains("can be downloaded"), behavior: .warning) + } + #else + XCTAssertNoDiagnostics(diagnostics) + #endif } func testBasicExtPackages() throws { From caf924ee7dd5b3f16c4fb87e0f9b7b861eb1edc1 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 12 Jun 2019 10:05:26 -0700 Subject: [PATCH 52/67] [Toolchain] Lookup clang in the toolchain Now that we have clang shipping in the Swift toolchains, we can just locate it in the bin dir. https://bugs.swift.org/browse/SR-10633 --- Sources/Workspace/UserToolchain.swift | 29 ++++++++++++++++----------- Utilities/bootstrap | 18 ++++++++++++++++- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/Sources/Workspace/UserToolchain.swift b/Sources/Workspace/UserToolchain.swift index ac7e2edbf0d..5fd2679cce9 100644 --- a/Sources/Workspace/UserToolchain.swift +++ b/Sources/Workspace/UserToolchain.swift @@ -151,30 +151,35 @@ public final class UserToolchain: Toolchain { return toolPath } - // Otherwise, lookup the tool on the system. + // Then, check the toolchain. + do { + let toolPath = destination.binDir.appending(component: "clang" + hostExecutableSuffix) + if localFileSystem.exists(toolPath) { + _clangCompiler = toolPath + return toolPath + } + } + + // Otherwise, lookup it up on the system. let arguments = whichArgs + ["clang"] let foundPath = try Process.checkNonZeroExit(arguments: arguments, environment: processEnvironment).spm_chomp() guard !foundPath.isEmpty else { throw InvalidToolchainDiagnostic("could not find clang") } let toolPath = try AbsolutePath(validating: foundPath) - - // If we found clang using xcrun, assume the vendor is Apple. - // FIXME: This might not be the best way to determine this. - #if os(macOS) - __isClangCompilerVendorApple = true - #endif - _clangCompiler = toolPath return toolPath } private var _clangCompiler: AbsolutePath? - private var __isClangCompilerVendorApple: Bool? public func _isClangCompilerVendorApple() throws -> Bool? { - // The boolean gets computed as a side-effect of lookup for clang compiler. - _ = try getClangCompiler() - return __isClangCompilerVendorApple + // Assume the vendor is Apple on macOS. + // FIXME: This might not be the best way to determine this. + #if os(macOS) + return true + #else + return false + #endif } /// Returns the path to llvm-cov tool. diff --git a/Utilities/bootstrap b/Utilities/bootstrap index 3b0278b1ba6..aabb643782a 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -306,7 +306,7 @@ class Target(object): link_input_nodes.append(object_path) - args = ["clang"] + args = [args.clang_path] args.extend(common_args) args.extend([deps_path, "-c", source,"-o", object_path]) @@ -733,6 +733,20 @@ def get_llbuild_source_path(): note("clone llbuild next to swiftpm directory; see development docs: https://github.com/apple/swift-package-manager/blob/master/Documentation/Development.md#using-trunk-snapshot") error("unable to find llbuild source directory at %s" % llbuild_path) +def get_clang_path(): + try: + if os.getenv("CC"): + clang_path=os.path.realpath(os.getenv("CC")) + return clang_path + elif platform.system() == 'Darwin': + return subprocess.check_output(["xcrun", "--find", "clang"], + stderr=subprocess.PIPE, universal_newlines=True).strip() + else: + return subprocess.check_output(["which", "clang"], + universal_newlines=True).strip() + except: + error("unable to find 'clang' tool for bootstrap build") + def get_swiftc_path(): try: if os.getenv("SWIFT_EXEC"): @@ -978,6 +992,7 @@ def main(): if not args.swiftc_path: args.swiftc_path = get_swiftc_path() + args.clang_path = get_clang_path() args.swift_stdlib_path = os.path.normpath( os.path.join(os.path.dirname(os.path.realpath(args.swiftc_path)), "..", @@ -1128,6 +1143,7 @@ def main(): def make_fake_toolchain(): symlink_force(args.swiftc_path, os.path.join(bindir, "swift")) symlink_force(args.swiftc_path, os.path.join(bindir, "swiftc")) + symlink_force(args.clang_path, os.path.join(bindir, "clang")) symlink_force(args.sbt_path, os.path.join(bindir, "swift-build-tool")) symlink_force(os.path.join(sandbox_path, "bin", "swift-build"), bootstrapped_product) From 0a973d27375ed218989d72731244e2db88280aab Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 12 Jun 2019 13:50:43 -0700 Subject: [PATCH 53/67] Remove use of swift-build-tool from SwiftPM We got library-based llbuild execution last year and swift-build-tool invocation is just dead code at this point. We should remove it. --- Sources/Commands/Options.swift | 3 - Sources/Commands/SwiftTool.swift | 85 ++------------------------- Sources/Workspace/UserToolchain.swift | 10 ---- 3 files changed, 5 insertions(+), 93 deletions(-) diff --git a/Sources/Commands/Options.swift b/Sources/Commands/Options.swift index 126c71492d1..7d812f820d0 100644 --- a/Sources/Commands/Options.swift +++ b/Sources/Commands/Options.swift @@ -50,9 +50,6 @@ public class ToolOptions { /// If should link the Swift stdlib statically. public var shouldLinkStaticSwiftStdlib = false - /// If should enable building with llbuild library. - public var shouldEnableLLBuildLibrary = true - /// Skip updating dependencies from their remote during a resolution. public var skipDependencyUpdate = false diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 42a65e1251a..8b3d3e78c21 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -212,10 +212,6 @@ public class SwiftTool { /// The stream to print standard output on. fileprivate var stdoutStream: OutputByteStream = Basic.stdoutStream - /// If true, Redirects the stdout stream to stderr when invoking - /// `swift-build-tool`. - private var shouldRedirectStdoutToStderr = false - /// Create an instance of this tool. /// /// - parameter args: The command line arguments to be passed to this tool. @@ -329,11 +325,6 @@ public class SwiftTool { usage: "Link Swift stdlib statically"), to: { $0.shouldLinkStaticSwiftStdlib = $1 }) - binder.bind( - option: parser.add(option: "--enable-llbuild-library", kind: Bool.self, - usage: "Enable building with the llbuild library"), - to: { $0.shouldEnableLLBuildLibrary = $1 }) - binder.bind( option: parser.add(option: "--force-resolved-versions", kind: Bool.self), to: { $0.forceResolvedVersions = $1 }) @@ -523,7 +514,6 @@ public class SwiftTool { /// Start redirecting the standard output stream to the standard error stream. func redirectStdoutToStderr() { - self.shouldRedirectStdoutToStderr = true self.stdoutStream = Basic.stderrStream DiagnosticsEngineHandler.default.stdoutStream = Basic.stderrStream } @@ -607,14 +597,14 @@ public class SwiftTool { return } - let yaml = plan.buildParameters.llbuildManifest + let manifest = plan.buildParameters.llbuildManifest // Generate the llbuild manifest. - let client = options.shouldEnableLLBuildLibrary ? "basic" : "swift-build" - let llbuild = LLBuildManifestGenerator(plan, client: client) - try llbuild.generateManifest(at: yaml) + let llbuild = LLBuildManifestGenerator(plan, client: "basic") + try llbuild.generateManifest(at: manifest) // Run llbuild. - try runLLBuild(plan: plan, manifest: yaml, llbuildTarget: llbuildTargetName) + assert(localFileSystem.isFile(manifest), "llbuild manifest not present: \(manifest)") + try runLLBuild(plan: plan, manifest: manifest, llbuildTarget: llbuildTargetName) // Create backwards-compatibilty symlink to old build path. let oldBuildPath = buildPath.appending(component: options.configuration.dirname) @@ -625,15 +615,6 @@ public class SwiftTool { } func runLLBuild(plan: BuildPlan, manifest: AbsolutePath, llbuildTarget: String) throws { - assert(localFileSystem.isFile(manifest), "llbuild manifest not present: \(manifest)") - if options.shouldEnableLLBuildLibrary { - try runLLBuildAsLibrary(plan: plan, manifest: manifest, llbuildTarget: llbuildTarget) - } else { - try runLLBuildAsExecutable(manifest: manifest, llbuildTarget: llbuildTarget) - } - } - - func runLLBuildAsLibrary(plan: BuildPlan, manifest: AbsolutePath, llbuildTarget: String) throws { // Setup the build delegate. let isVerbose = verbosity != .concise let progressAnimation: ProgressAnimationProtocol = isVerbose ? @@ -658,62 +639,6 @@ public class SwiftTool { guard success else { throw Diagnostics.fatalError } } - func runLLBuildAsExecutable(manifest: AbsolutePath, llbuildTarget: String) throws { - // Create a temporary directory for the build process. - let tempDirName = "org.swift.swiftpm.\(NSUserName())" - let tempDir = try determineTempDirectory().appending(component: tempDirName) - try localFileSystem.createDirectory(tempDir, recursive: true) - - // Run the swift-build-tool with the generated manifest. - var args = [String]() - - #if os(macOS) - // If enabled, use sandbox-exec on macOS. This provides some safety - // against arbitrary code execution. We only allow the permissions which - // are absolutely necessary for performing a build. - if !options.shouldDisableSandbox { - let allowedDirectories = [ - tempDir, - buildPath, - ].map(resolveSymlinks) - args += ["sandbox-exec", "-p", sandboxProfile(allowedDirectories: allowedDirectories)] - } - #endif - - args += [try getToolchain().llbuild.pathString, "-f", manifest.pathString, llbuildTarget] - if verbosity != .concise { - args.append("-v") - } - if let jobs = options.jobs { - args.append("-j\(jobs)") - } - - // Create the environment for llbuild. - var env = Process.env - // We override the temporary directory so tools assuming full access to - // the tmp dir can create files here freely, provided they respect this - // variable. - env["TMPDIR"] = tempDir.pathString - - // Run llbuild and print output on standard streams. - let process = Process(arguments: args, environment: env, outputRedirection: shouldRedirectStdoutToStderr ? .collect : .none) - try process.launch() - try processSet.add(process) - let result = try process.waitUntilExit() - - // Emit the output to the selected stream if we need to redirect the - // stream. - if shouldRedirectStdoutToStderr { - self.stdoutStream <<< (try result.utf8stderrOutput()) - self.stdoutStream <<< (try result.utf8Output()) - self.stdoutStream.flush() - } - - guard result.exitStatus == .terminated(code: 0) else { - throw ProcessResult.Error.nonZeroExit(result) - } - } - /// Return the build parameters. func buildParameters() throws -> BuildParameters { return try _buildParameters.dematerialize() diff --git a/Sources/Workspace/UserToolchain.swift b/Sources/Workspace/UserToolchain.swift index ac7e2edbf0d..fb79df971af 100644 --- a/Sources/Workspace/UserToolchain.swift +++ b/Sources/Workspace/UserToolchain.swift @@ -69,9 +69,6 @@ public final class UserToolchain: Toolchain { /// This is only present on macOS. public let xctest: AbsolutePath? - /// Path to llbuild. - public let llbuild: AbsolutePath - /// The compilation destination object. public let destination: Destination @@ -211,13 +208,6 @@ public final class UserToolchain: Toolchain { let swiftCompilers = try UserToolchain.determineSwiftCompilers(binDir: binDir, lookup: { UserToolchain.lookup(variable: $0, searchPaths: searchPaths) }) self.swiftCompiler = swiftCompilers.compile - // Look for llbuild in bin dir. - llbuild = binDir.appending(component: "swift-build-tool" + hostExecutableSuffix) - guard localFileSystem.exists(llbuild) else { - throw InvalidToolchainDiagnostic("could not find `llbuild` at expected path \(llbuild)") - } - - // We require xctest to exist on macOS. #if os(macOS) // FIXME: We should have some general utility to find tools. From d19b26c02a81ae1170e09fc7c4c525e3f15f43ee Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Thu, 13 Jun 2019 15:12:26 -0700 Subject: [PATCH 54/67] [PackageGraph] Actually implement _isRemoteContainer --- .../PackageGraph/RepositoryPackageContainerProvider.swift | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Sources/PackageGraph/RepositoryPackageContainerProvider.swift b/Sources/PackageGraph/RepositoryPackageContainerProvider.swift index e8d1d42beaa..a90f08fe89d 100644 --- a/Sources/PackageGraph/RepositoryPackageContainerProvider.swift +++ b/Sources/PackageGraph/RepositoryPackageContainerProvider.swift @@ -164,6 +164,10 @@ public class BasePackageContainer: PackageContainer { self.toolsVersionLoader = toolsVersionLoader self.currentToolsVersion = currentToolsVersion } + + public var _isRemoteContainer: Bool? { + return nil + } } /// Local package container. @@ -324,7 +328,7 @@ public class RepositoryPackageContainer: BasePackageContainer, CustomStringConve return "RepositoryPackageContainer(\(identifier.repository.url.debugDescription))" } - public var _isRemoteContainer: Bool { + public override var _isRemoteContainer: Bool? { return true } From fba7a31676d5be5e851fd17ce2e6e532f1ab64eb Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Thu, 13 Jun 2019 15:31:36 -0700 Subject: [PATCH 55/67] Add SWIFTPM_MODULECACHE_OVERRIDE for Swift CI --- Sources/PackageLoading/ManifestLoader.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/PackageLoading/ManifestLoader.swift b/Sources/PackageLoading/ManifestLoader.swift index 881606a171d..aee16ceb63f 100644 --- a/Sources/PackageLoading/ManifestLoader.swift +++ b/Sources/PackageLoading/ManifestLoader.swift @@ -386,7 +386,7 @@ public final class ManifestLoader: ManifestLoaderProtocol { // FIXME: Workaround for the module cache bug that's been haunting Swift CI // - let moduleCachePath = Process.env["SWIFTPM_TESTS_MODULECACHE"] + let moduleCachePath = Process.env["SWIFTPM_MODULECACHE_OVERRIDE"] ?? Process.env["SWIFTPM_TESTS_MODULECACHE"] var cmd = [String]() #if os(macOS) From b6ecad4fd250cea74299f956bcecbcc5e5c6902d Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 14 Jun 2019 14:29:52 -0700 Subject: [PATCH 56/67] [Workspace] Add ability to notify when Package.resolved file is changed This adds a delegate method that will notify clients when the Package.resolved file is changed outside of libSwiftPM operations. For example, when a git operation is performed. --- Sources/SPMUtility/FSWatch.swift | 34 +++++++++-------------- Sources/Workspace/PinsStore.swift | 45 +++++++++++++++++++++++++++++++ Sources/Workspace/Workspace.swift | 29 ++++++++++++++++++++ 3 files changed, 86 insertions(+), 22 deletions(-) diff --git a/Sources/SPMUtility/FSWatch.swift b/Sources/SPMUtility/FSWatch.swift index cbb80a50174..70b12765cd3 100644 --- a/Sources/SPMUtility/FSWatch.swift +++ b/Sources/SPMUtility/FSWatch.swift @@ -13,35 +13,23 @@ import Dispatch import Foundation import SPMLibc -public protocol FSWatchDelegate { - // FIXME: We need to provide richer information about the events. - func pathsDidReceiveEvent(_ paths: [AbsolutePath]) -} - /// FSWatch is a cross-platform filesystem watching utility. public class FSWatch { - /// Delegate for handling events from the underling watcher. - fileprivate class _WatcherDelegate { - - /// Back reference to the fswatch instance. - unowned let fsWatch: FSWatch + public typealias EventReceivedBlock = (_ paths: [AbsolutePath]) -> Void - init(_ fsWatch: FSWatch) { - self.fsWatch = fsWatch - } + /// Delegate for handling events from the underling watcher. + fileprivate struct _WatcherDelegate { + let block: EventReceivedBlock func pathsDidReceiveEvent(_ paths: [AbsolutePath]) { - fsWatch.delegate.pathsDidReceiveEvent(paths) + block(paths) } } /// The paths being watched. public let paths: [AbsolutePath] - /// The delegate for reporting received events. - let delegate: FSWatchDelegate - /// The underlying file watching utility. /// /// This is FSEventStream on macOS and inotify on linux. @@ -54,10 +42,9 @@ public class FSWatch { /// Create an instance with given paths. /// /// Paths can be files or directories. Directories are watched recursively. - public init(paths: [AbsolutePath], latency: Double = 1, delegate: FSWatchDelegate) { + public init(paths: [AbsolutePath], latency: Double = 1, block: @escaping EventReceivedBlock) { precondition(!paths.isEmpty) self.paths = paths - self.delegate = delegate self.latency = latency #if canImport(Glibc) @@ -75,9 +62,9 @@ public class FSWatch { } } - self._watcher = Inotify(paths: ipaths, latency: latency, delegate: _WatcherDelegate(self)) + self._watcher = Inotify(paths: ipaths, latency: latency, delegate: _WatcherDelegate(block: block)) #elseif os(macOS) - self._watcher = FSEventStream(paths: paths, latency: latency, delegate: _WatcherDelegate(self)) + self._watcher = FSEventStream(paths: paths, latency: latency, delegate: _WatcherDelegate(block: block)) #else fatalError("Unsupported platform") #endif @@ -603,7 +590,10 @@ public final class FSEventStream { /// Stop watching the events. public func stop() { - CFRunLoopStop(runLoop!) + // FIXME: This is probably not thread safe? + if let runLoop = self.runLoop { + CFRunLoopStop(runLoop) + } } } #endif diff --git a/Sources/Workspace/PinsStore.swift b/Sources/Workspace/PinsStore.swift index df2c8d48d4d..fd2449c2e5f 100644 --- a/Sources/Workspace/PinsStore.swift +++ b/Sources/Workspace/PinsStore.swift @@ -182,3 +182,48 @@ extension PinsStore.Pin: JSONMappable, JSONSerializable, Equatable { ]) } } + +/// A file watcher utility for the Package.resolved file. +/// +/// This is not intended to be used directly by clients. +final class ResolvedFileWatcher { + private var fswatch: FSWatch! + private var existingValue: ByteString? + private let valueLock: Lock = Lock() + private let resolvedFile: AbsolutePath + + public func updateValue() { + valueLock.withLock { + self.existingValue = try? localFileSystem.readFileContents(resolvedFile) + } + } + + init(resolvedFile: AbsolutePath, onChange: @escaping () -> ()) throws { + self.resolvedFile = resolvedFile + + let block = { [weak self] (paths: [AbsolutePath]) in + guard let self = self else { return } + + // Check if resolved file is part of the received paths. + let hasResolvedFile = paths.contains{ $0.appending(component: resolvedFile.basename) == resolvedFile } + guard hasResolvedFile else { return } + + self.valueLock.withLock { + // Compute the contents of the resolved file and fire the onChange block + // if its value is different than existing value. + let newValue = try? localFileSystem.readFileContents(resolvedFile) + if self.existingValue != newValue { + self.existingValue = newValue + onChange() + } + } + } + + fswatch = FSWatch(paths: [resolvedFile.parentDirectory], latency: 1, block: block) + try fswatch.start() + } + + deinit { + fswatch.stop() + } +} diff --git a/Sources/Workspace/Workspace.swift b/Sources/Workspace/Workspace.swift index 65f2dde8774..5e219dc9b73 100644 --- a/Sources/Workspace/Workspace.swift +++ b/Sources/Workspace/Workspace.swift @@ -45,6 +45,11 @@ public protocol WorkspaceDelegate: class { /// Called when the resolver is about to be run. func willResolveDependencies() + + /// Called when the Package.resolved file is changed *outside* of libSwiftPM operations. + /// + /// This is only fired when activated using Workspace's watchResolvedFile() method. + func resolvedFileChanged() } public extension WorkspaceDelegate { @@ -53,6 +58,7 @@ public extension WorkspaceDelegate { func repositoryDidUpdate(_ repository: String) {} func willResolveDependencies() {} func dependenciesUpToDate() {} + func resolvedFileChanged() {} } private class WorkspaceResolverDelegate: DependencyResolverDelegate { @@ -252,6 +258,9 @@ public class Workspace { /// The Pins store. The pins file will be created when first pin is added to pins store. public let pinsStore: LoadableResult + /// The path to the Package.resolved file for this workspace. + public let resolvedFile: AbsolutePath + /// The path for working repository clones (checkouts). public let checkoutsPath: AbsolutePath @@ -291,6 +300,8 @@ public class Workspace { /// Write dependency resolver trace to a file. fileprivate let enableResolverTrace: Bool + fileprivate var resolvedFileWatcher: ResolvedFileWatcher? + /// Typealias for dependency resolver we use in the workspace. fileprivate typealias PackageDependencyResolver = DependencyResolver fileprivate typealias PubgrubResolver = PubgrubDependencyResolver @@ -336,6 +347,7 @@ public class Workspace { self.enablePubgrubResolver = enablePubgrubResolver self.skipUpdate = skipUpdate self.enableResolverTrace = enableResolverTrace + self.resolvedFile = pinsFile let repositoriesPath = self.dataPath.appending(component: "repositories") self.repositoryManager = RepositoryManager( @@ -904,6 +916,10 @@ extension Workspace { } } diagnostics.wrap({ try pinsStore.saveState() }) + + // Ask resolved file watcher to update its value so we don't fire + // an extra event if the file was modified by us. + self.resolvedFileWatcher?.updateValue() } } @@ -911,6 +927,19 @@ extension Workspace { extension Workspace { + /// Watch the Package.resolved for changes. + /// + /// This is useful if clients want to be notified when the Package.resolved + /// file is changed *outside* of libSwiftPM operations. For example, as part + /// of a git operation. + public func watchResolvedFile() throws { + // Return if we're already watching it. + guard self.resolvedFileWatcher == nil else { return } + self.resolvedFileWatcher = try ResolvedFileWatcher(resolvedFile: self.resolvedFile) { [weak self] in + self?.delegate?.resolvedFileChanged() + } + } + /// Create the cache directories. fileprivate func createCacheDirectories(with diagnostics: DiagnosticsEngine) { do { From 0425b508b3767c9e0c600c4bc423b21b3a9a2f64 Mon Sep 17 00:00:00 2001 From: Benjamin Scholtysik Date: Thu, 20 Jun 2019 12:09:01 -0700 Subject: [PATCH 57/67] Remove old PackageDescription API docs. --- Documentation/PackageDescriptionV3.md | 383 ------------------------ Documentation/PackageDescriptionV4.md | 317 -------------------- Documentation/PackageDescriptionV4_2.md | 84 ------ 3 files changed, 784 deletions(-) delete mode 100644 Documentation/PackageDescriptionV3.md delete mode 100644 Documentation/PackageDescriptionV4.md delete mode 100644 Documentation/PackageDescriptionV4_2.md diff --git a/Documentation/PackageDescriptionV3.md b/Documentation/PackageDescriptionV3.md deleted file mode 100644 index ee4a86fe3f6..00000000000 --- a/Documentation/PackageDescriptionV3.md +++ /dev/null @@ -1,383 +0,0 @@ -# PackageDescription API Version 3 - -⚠️ This version is no longer supported ⚠️ - ---- - -## Target Format Reference - -### Source Layouts - -The targets that `swift build` creates are determined from the filesystem -layout of your source files. - -For example, if you create a directory with the following layout: - - example/ - example/Sources/bar.swift - example/Sources/baz.swift - -This defines a single target, named after the package name from -`Package.swift`. - -To create multiple targets, create multiple subdirectories: - - example/Sources/Foo/Widget.swift - example/Sources/Bar/Bazzer.swift - -This defines two targets: `Foo` and `Bar`. - -To generate an executable target (instead of a library target), add a -`main.swift` file to that target’s directory: - - example/Sources/Foo/main.swift - -Running `swift build` will now produce an executable output file: `example/.build/debug/Foo`. - -The C language targets are laid out in a similar format. For e.g. a library -`Baz` can be created with following layout: - - example/Sources/Baz/Baz.c - example/Sources/Baz/include/Baz.h - -The public headers for this library go in the directory `include`. - -Similarly, an executable C language target `Baz` looks like this: - - example/Sources/Baz/main.c - -Note: It is possible to have C, C++, Objective-C and Objective-C++ sources as -part of a C language target. Swift targets can import C language targets but -not vice versa. - -Read more on C language targets [here](Usage.md#c-language-targets). - -### Test Target Layouts - -The package manager supports laying out test sources following a similar -convention as primary sources: - - example/Tests/FooTests/WidgetTests.swift - -This defines a `FooTests` test target. By convention, when there is a target -`Foo` and a matching test target `FooTests`, the package manager will establish -an implicit dependency between the test target and the target it assumes it is -trying to test. - -On Linux, the `XCTest` testing framework does not support dynamic discovery of -tests. Instead, packages which are intended for use on Linux should include an: - - example/Tests/LinuxMain.swift - -file which imports all of the individual test targets in the package, and then -invokes `XCTest.XCTMain` passing it the list of all tests. - -### Other Rules - -* `Tests` or any other subdirectory can be [excluded](#exclude) via Manifest - file. -* Subdirectories of a directory named `Sources`, `Source`, `srcs` or `src` in - the root directory become target. -* It is acceptable to have no `Sources` directory, in which case the root - directory is treated as a single target (place your sources there) or sub - directories of the root are considered targets. Use this layout convention - for simple projects. - ---- - -## Package Manifest File Format Reference - -Instructions for how to build a package are provided by the `Package.swift` -manifest file. `Package.swift` is a Swift file defining a single `Package` -object. This object is configured via the APIs defined in the -`PackageDescription` Swift target supplied with the Swift Package Manager. - -### Package Declaration - -Every `Package.swift` file should follow the following format: - -```swift -import PackageDescription - -/// The package description. -let package = Package(/* ... */) - -// ... subsequent package configuration APIs can be used here to further -// configure the package ... -``` - -Conceptually, the description defined by the `Package.swift` file is _combined_ -with the information on the package derived from the filesystem conventions -described previously. - -### Package - -```swift -Package( - name: String, - pkgConfig: String? = nil, - providers: [SystemPackageProvider]? = nil, - targets: [Target] = [], - dependencies: [Package.Dependency] = [], - swiftLanguageVersions: [Int]? = nil, - exclude: [String] = [] -) -``` - -\- [name](#name): The name of the package. -\- [pkgConfig](#pkgconfig): Name of the pkg-config (.pc) file to get the -additional flags for system modules. -\- [providers](#providers): Defines hints to display for installing system -modules. -\- [targets](#targets): Additional information on each target. -\- [dependencies](#dependencies): Declare dependencies on external packages. -\- [swiftLanguageVersions](#swiftlanguageversions): Specifies the set of -supported Swift language versions. -\- [exclude](#exclude): Exclude files and directories from package sources. - -Creates a new package instance. There should only be one package declared per -manifest. The parameters here supply the package description and are documented -in further detail below. - -#### name - -```swift -import PackageDescription - -let package = Package( - name: "FooBar" -) -``` - -This is the minimal requirement for a manifest to be valid. When the sources -are located directly under `Sources/` directory, there is only one target and -the target name will be the same as the package name. - -#### pkgConfig - -This property should only be used for System Module Packages. It defines the -name of the pkg-config (.pc) file that should be searched and read to get the -additional flags like include search path, linker search path, system libraries -to link etc. - -```swift -import PackageDescription - -let package = Package( - name: "CGtk3", - pkgConfig: "gtk+-3.0" -) -``` - -Here `gtk+-3.0.pc` will be searched in standard locations for the current -system. Users can provide their own paths for location of pc files using the -environment variable, `PKG_CONFIG_PATH`, which will be searched before the -standard locations. - -_NOTE: This feature does not require pkg-config to be installed. However, if -installed it will used to find additional platform specific pc file locations -which might be unknown to SwiftPM._ - -#### providers - -This property should only be used for system module packages. It can be used to -provide _hints_ for other users to install a System Module using -a system package manager like homebrew, apt-get etc. - -_NOTE: SwiftPM will *never* execute the command and only suggest the users to -run it._ - -```swift -import PackageDescription - -let package = Package( - name: "CGtk3", - pkgConfig: "gtk+-3.0", - providers: [ - .Brew("gtk+3"), - .Apt("gtk3") - ] -) -``` - -In this case if SwiftPM determines that GTK 3 package is not installed, it will -output an appropriate hint depending on which platform the user is on i.e. -macOS, Ubuntu, etc. - -#### targets - -The targets property is required when you have more than one target in your -package and need to declare a dependency between them. - -```swift -import PackageDescription - -let package = Package( - name: "Hello", - targets: [ - Target(name: "Bar", dependencies: ["Foo"]), - ] -) -``` - -The name identifies which target, the information is being associated with, and -the list of dependencies specifies the names of other targets in the same -package which must be built before that target. In the example here, `Foo` and -`Bar` are targets present under `Sources/` directory, and a dependency is being -establish on `Foo` from `Bar`. This will cause the `Foo` target to be built -before `Bar` target so that it can be imported: - -_NOTE: It is also possible to declare target dependencies between a test and -regular target._ - -#### dependencies - -This is the list of packages that the current package depends on and -information about the required versions. You can specify a URL (or local path) -to any valid Swift package. - -```swift -import PackageDescription - -let package = Package( - name: "Example", - dependencies: [ - .Package(url: "ssh://git@example.com/Greeter.git", versions: Version(1,0,0)..) -``` -\- *url*: URL or local path to a Package. -\- *versions*: The range of [versions](#version) which are required. - -```swift -.Package(url: String, versions: ClosedRange) -``` -\- *url*: URL or local path to a Package. -\- *versions*: The closed range of [versions](#version) which are required. - -```swift -.Package(url: String, majorVersion: Int) -``` -\- *url*: URL or local path to a Package. -\- *majorVersion*: The major version which is required. - -This is a short-hand form for specifying a range including all versions of a -major version, and is the recommended way for specifying a dependency following -the [semantic versioning](http://semver.org) standard. - -```swift -.Package(url: String, majorVersion: Int, minor: Int) -``` -\- *url*: URL or local path to a Package. -\- *majorVersion*: Major version to consider. -\- *minor*: Minor version to consider. - -As for the prior API, this is a short-hand form for specifying a range that -inclues all versions of a major and minor version. - -```swift -.Package(url: String, _ version: Version) -``` -\- *url*: URL or local path to a Package. -\- *version*: The exact [Version](#version) which is required. - -## Version - -A struct representing a [semantic version](http://semver.org). - -```swift -Version( - _ major: Int, - _ minor: Int, - _ patch: Int, - prereleaseIdentifiers: [String] = [], - buildMetadataIdentifier: String? = nil -) -``` - -\- *major*: The major version, incremented when you make incompatible API -changes. -\- *minor*: The minor version, incremented when you add functionality in a -backwards-compatible manner. -\- *patch*: The patch version, incremented when you make backwards-compatible -bug fixes. -\- *prereleaseIdentifiers*: Used to denote a pre-released version for eg: -alpha, beta, etc. -\- *buildMetadataIdentifier*: Optional build meta data for eg: timestamp, hash, -etc. - -A `Version` struct can be initialized using a string literal in following -format: - -``` "major.minor.patch[-prereleaseIdentifiers][+buildMetadata]" ``` - -where `prereleaseIdentifiers` and `buildMetadata` are optional. -_NOTE: prereleaseIdentifiers are separated by dot (.)._ - -### Customizing Builds - -Using Swift as the format for the manifest allows for powerful customization, -for example: - -```swift -import PackageDescription - -var package = Package(name: "Example") - -#if os(Linux) -let target = Target(name: "LinuxSources/foo") -package.targets.append(target) -#endif -``` diff --git a/Documentation/PackageDescriptionV4.md b/Documentation/PackageDescriptionV4.md deleted file mode 100644 index 20387c2299c..00000000000 --- a/Documentation/PackageDescriptionV4.md +++ /dev/null @@ -1,317 +0,0 @@ -# PackageDescription API Version 4 - -⚠️ This document is no longer maintained ⚠️ - -See [this](PackageDescription.md) document instead. - ---- - -## Target Format Reference - -All targets should be declared in the `Package.swift` manifest file. Unless the -relative path of the target is declared, the Package Manager will look for -a directory matching the name of the target in these places: - -Regular targets: Sources, Source, src, srcs. -Test targets: Tests, Sources, Source, src, srcs. - -## Package Manifest File Format Reference - -### Package - -```swift -Package( - name: String, - pkgConfig: String? = nil, - providers: [SystemPackageProvider]? = nil, - products: [Product] = [], - dependencies: [Dependency] = [], - targets: [Target] = [], - swiftLanguageVersions: [Int]? = nil -) -``` - -\- [name](#name): The name of the package. -\- [pkgConfig](#pkgconfig): Name of the pkg-config (.pc) file to get the -additional flags for system modules. -\- [providers](#providers): Defines hints to display for installing system -modules. -\- [products](#products): The products vended by the package. -\- [dependencies](#dependencies): The external package dependencies. -\- [targets](#targets): The list of targets in the package. -\- [swiftLanguageVersions](#swiftlanguageversions): Specifies the set of -supported Swift language versions. - -#### name - -```swift -import PackageDescription - -let package = Package( - name: "FooBar" -) -``` - -This is the minimal requirement for a manifest to be valid. However, at least -one target is required to build the package. - -#### pkgConfig - -This property should only be used for System Module Packages. It defines the -name of the pkg-config (.pc) file that should be searched and read to get the -additional flags like include search path, linker search path, system libraries -to link etc. - -```swift -import PackageDescription - -let package = Package( - name: "CGtk3", - pkgConfig: "gtk+-3.0" -) -``` - -Here `gtk+-3.0.pc` will be searched in standard locations for the current -system. Users can provide their own paths for location of pc files using the -environment variable, `PKG_CONFIG_PATH`, which will be searched before the -standard locations. - -_NOTE: This feature does not require pkg-config to be installed. However, if -installed it will be used to find additional platform specific pc file locations -which might be unknown to SwiftPM._ - -#### providers - -This property should only be used for system module packages. It can be used to -provide _hints_ for users to install a System Module using a system package -manager like homebrew, apt-get etc. - -_NOTE: SwiftPM will **never** execute the command, and only provide suggestions._ - -```swift -import PackageDescription - -let package = Package( - name: "CGtk3", - pkgConfig: "gtk+-3.0", - providers: [ - .brew(["gtk+3"]), - .apt(["gtk3"]) - ] -) -``` - -In this case if SwiftPM determines that GTK 3 package is not installed, it will -output an appropriate hint depending on which platform the user is on i.e. -macOS, Ubuntu, etc. - -#### products - -This is the list of all the products that are vended by the package. A target is -available to other packages only if it is a part of some product. - -Two types of products are supported: - -* library: A library product contains library targets. It should contain the - targets which are supposed to be used by other packages, i.e. the public API - of a library package. The library product can be declared static, dynamic - or automatic. It is recommended to use automatic so the Package Manager can - decide appropriate linkage. - -* executable: An executable product is used to vend an executable target. This - should only be used if the executable needs to be made available to - other packages. - -Example: - -```swift -let package = Package( - name: "Paper", - products: [ - .executable(name: "tool", targets: ["tool"]), - .library(name: "Paper", targets: ["Paper"]), - .library(name: "PaperStatic", type: .static, targets: ["Paper"]), - .library(name: "PaperDynamic", type: .dynamic, targets: ["Paper"]), - ], - dependencies: [ - .package(url: "http://github.com/SwiftyJSON/SwiftyJSON", from: "1.2.3"), - .package(url: "../CHTTPParser", .upToNextMinor(from: "2.2.0")), - .package(url: "http://some/other/lib", .exact("1.2.3")), - ], - targets: [ - .target( - name: "tool", - dependencies: [ - "Paper", - "SwiftyJSON" - ]), - .target( - name: "Paper", - dependencies: [ - "Basic", - .target(name: "Utility"), - .product(name: "CHTTPParser"), - ]) - ] -) -``` - -#### dependencies - -This is the list of packages that the package depends on. You can specify -a URL (or local path) to any valid Swift package. - -```swift -import PackageDescription - -let package = Package( - name: "Example", - dependencies: [ - .package(url: "https://github.com/SwiftyJSON/SwiftyJSON.git", from: "1.0.0"), - ], - targets: [ - .target(name: "Foo", dependencies: ["SwiftyJSON"]), - ] -) -``` - -A package dependency represents the location and the required version -information of an external dependency. The version range controls what versions -of a package dependency are expected to work with the current package. When the -package manager is fetching the complete set of packages required to build -a package, it considers all of the version range specifications from all of the -packages in order to select appropriate versions. - -The following options are available for declaring a package dependency: - -```swift - -// 1.0.0 ..< 2.0.0 -.package(url: "/SwiftyJSON", from: "1.0.0"), - -// 1.2.0 ..< 2.0.0 -.package(url: "/SwiftyJSON", from: "1.2.0"), - -// 1.5.8 ..< 2.0.0 -.package(url: "/SwiftyJSON", from: "1.5.8"), - -// 1.5.8 ..< 2.0.0 -.package(url: "/SwiftyJSON", .upToNextMajor(from: "1.5.8")), - -// 1.5.8 ..< 1.6.0 -.package(url: "/SwiftyJSON", .upToNextMinor(from: "1.5.8")), - -// 1.5.8 -.package(url: "/SwiftyJSON", .exact("1.5.8")), - -// Constraint to an arbitrary open range. -.package(url: "/SwiftyJSON", "1.2.3"..<"1.2.6"), - -// Constraint to an arbitrary closed range. -.package(url: "/SwiftyJSON", "1.2.3"..."1.2.8"), - -// Branch and revision. -.package(url: "/SwiftyJSON", .branch("develop")), -.package(url: "/SwiftyJSON", .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021")) -``` - -#### targets - -The targets property is used to declare the targets in the package. - -```swift -import PackageDescription - -let package = Package( - name: "FooBar", - targets: [ - .target(name: "Foo", dependencies: []), - .testTarget(name: "Bar", dependencies: ["Foo"]), - ] -) -``` - -The above manifest declares two targets, `Foo` and `Bar`. `Bar` is a test target -which depends on `Foo`. The Package Manager will automatically search for the -targets inside package in the [predefined search paths](#target-format-reference). - -A target dependency can either be another target in the same package or a product -in one of its package dependencies. All target dependencies, internal or -external, must be explicitly declared. - -A target can be further customized with these properties: - -* path: This property defines the path to the top-level directory containing the -target's sources, relative to the package root. It is not legal for this path to -escape the package root, i.e., values like "../Foo", "/Foo" are invalid. The -default value of this property will be nil, which means the target will be -searched for in the pre-defined paths. The empty string ("") or dot (".") -implies that the target's sources are directly inside the package root. - -* exclude: This property can be used to exclude certain files and directories from -being picked up as sources. Exclude paths are relative to the target path. This -property has more precedence than sources property. - -* sources: This property defines the source files to be included in the target. -The default value of this property will be nil, which means all valid source -files found in the target's path will be included. This can contain directories -and individual source files. Directories will be searched recursively for valid -source files. Paths specified are relative to the target path. - -* publicHeadersPath: This property defines the path to the directory containing -public headers of a C target. This path is relative to the target path and -default value of this property is include. *Only valid for C family library -targets*. - -Note: It is an error if the paths of two targets overlap (unless resolved with -exclude). - -#### swiftLanguageVersions - -This property is used to specify the set of supported Swift language versions. - -The package manager will select the Swift language version that is most close to -(but not exceeding) the major version of the Swift compiler in use. It is an -error if a package does not support any version compatible with the current -compiler. For e.g. if Swift language version is set to `[3]`, both Swift 3 and -4 compilers will select '3', and if Swift language version is set to `[3, 4]`, -Swift 3 compiler will select '3' and Swift 4 compiler will select '4'. - -If a package does not specify any Swift language versions, the language version -to be used will match the major version of the package's [Swift tools -version](Usage.md#swift-tools-version). For e.g.: A Swift tools version with -a major version of '3' will imply a default Swift language version of '3', and -a Swift tools version with a major version of '4' will imply a default Swift -language version of '4'. - -## Version - -A struct representing a [semantic version](http://semver.org). - -```swift -Version( - _ major: Int, - _ minor: Int, - _ patch: Int, - prereleaseIdentifiers: [String] = [], - buildMetadataIdentifiers: [String] = [] -) -``` - -\- *major*: The major version, incremented when you make incompatible API -changes. -\- *minor*: The minor version, incremented when you add functionality in a -backwards-compatible manner. -\- *patch*: The patch version, incremented when you make backwards-compatible -bug fixes. -\- *prereleaseIdentifiers*: Used to denote a pre-release version; for example, -alpha, beta. -\- *buildMetadataIdentifiers*: Optional build metadata; for example, timestamp, hash. - -A `Version` struct can be initialized using a string literal in following -format: - -``` "major.minor.patch[-prereleaseIdentifiers][+buildMetadataIdentifiers]" ``` - -where `prereleaseIdentifiers` and `buildMetadataIdentifiers` are optional. -_NOTE: prereleaseIdentifiers and buildMetadataIdentifiers elements are separated by dot (.)._ diff --git a/Documentation/PackageDescriptionV4_2.md b/Documentation/PackageDescriptionV4_2.md deleted file mode 100644 index aa912d27aef..00000000000 --- a/Documentation/PackageDescriptionV4_2.md +++ /dev/null @@ -1,84 +0,0 @@ -# PackageDescription API Version 4.2 - -⚠️ This document is no longer maintained ⚠️ - -See [this](PackageDescription.md) document instead. - ---- - -The PackageDescription 4.2 contains one breaking and two additive changes to [PackageDescription API Version 4](PackageDescriptionV4.md). - -## Swift Language Version - -The `swiftLanguageVersions` takes an array of `SwiftVersion` enum: - -```swift -public enum SwiftVersion { - case v3 - case v4 - case v4_2 - case version(String) -} -``` - -Example usage: - -```swift -// swift-tools-version:4.2 - -import PackageDescription - -let package = Package( - name: "HTTPClient", - ... - swiftLanguageVersions: [.v4, .v4_2] -) -``` - -## Local Dependencies - -Local dependences are packages on disk that can be referred directly using their -paths. Local dependencies are only allowed in the root package and they override -all dependencies with same name in the package graph. Example declaration: - -```swift -import PackageDescription - -let package = Package( - name: "MyPackage", - dependencies: [ - .package(path: "../example-package-playingcard"), - ], - targets: [ - .target( - name: "MyPackage", - dependencies: ["PlayingCard"] - ), - ] -) -``` - -## System Library Targets - -System library targets supply the same metadata needed to adapt system libraries -to work with the package manager, but as a target. This allows packages to embed -these targets with the libraries that need them. - -```swift -// swift-tools-version:4.2 -import PackageDescription - -let package = Package( - name: "ZLib", - products: [ - .library(name: "ZLib", targets: ["ZLib"]), - ], - targets: [ - .systemLibrary( - name: "CZLib") - .target( - name: "ZLib", - dependencies: ["CZLib"]), - ] -) -``` From b89553e940b2fe44df6a16aa283346a4fb5293dc Mon Sep 17 00:00:00 2001 From: Benjamin Scholtysik Date: Thu, 20 Jun 2019 12:21:24 -0700 Subject: [PATCH 58/67] Update links in Usage.md --- Documentation/Usage.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/Usage.md b/Documentation/Usage.md index cdcfb89ab62..2367178a314 100644 --- a/Documentation/Usage.md +++ b/Documentation/Usage.md @@ -48,7 +48,7 @@ get started, create a directory and run `swift package init` command: This will create the directory structure needed for a library package with a target and the corresponding test target to write unit tests. A library package can contain multiple targets as explained in [Target Format -Reference](PackageDescriptionV4.md#target-format-reference). +Reference](PackageDescription.md#target). ### Create an executable package @@ -65,7 +65,7 @@ get started: This creates the directory structure needed for executable targets. Any target can be turned into a executable target if there is a `main.swift` present in its sources. Complete reference for layout is -[here](PackageDescriptionV4.md#target-format-reference). +[here](PackageDescription.md#target). ## Define Dependencies From a220f4c37a224b521063dbe21155228223eb4850 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Thu, 20 Jun 2019 15:11:51 -0700 Subject: [PATCH 59/67] Revert "Support new XCTest overlays" --- Sources/Commands/SwiftTestTool.swift | 5 ++--- Sources/TestSupport/Resources.swift | 2 +- Sources/Workspace/Destination.swift | 32 +++++++--------------------- 3 files changed, 11 insertions(+), 28 deletions(-) diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index 32b50293168..660217448d0 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -477,9 +477,8 @@ public class SwiftTestTool: SwiftTool { var env = try constructTestEnvironment(toolchain: try getToolchain(), options: self.options, buildParameters: self.buildParameters()) // Add the sdk platform path if we have it. If this is not present, we // might always end up failing. - if let sdkPlatformFrameworksPath = Destination.sdkPlatformFrameworkPaths() { - env["DYLD_FRAMEWORK_PATH"] = sdkPlatformFrameworksPath.fwk.pathString - env["DYLD_LIBRARY_PATH"] = sdkPlatformFrameworksPath.lib.pathString + if let sdkPlatformFrameworksPath = Destination.sdkPlatformFrameworkPath() { + env["DYLD_FRAMEWORK_PATH"] = sdkPlatformFrameworksPath.pathString } try Process.checkNonZeroExit(arguments: args, environment: env) // Read the temporary file's content. diff --git a/Sources/TestSupport/Resources.swift b/Sources/TestSupport/Resources.swift index 49f0506c6fa..fe05e9a8b11 100644 --- a/Sources/TestSupport/Resources.swift +++ b/Sources/TestSupport/Resources.swift @@ -36,7 +36,7 @@ public class Resources: ManifestResourceProvider { #if os(macOS) public var sdkPlatformFrameworksPath: AbsolutePath { - return Destination.sdkPlatformFrameworkPaths()!.fwk + return Destination.sdkPlatformFrameworkPath()! } #endif diff --git a/Sources/Workspace/Destination.swift b/Sources/Workspace/Destination.swift index 22bb20f78f9..368c77c6758 100644 --- a/Sources/Workspace/Destination.swift +++ b/Sources/Workspace/Destination.swift @@ -103,21 +103,15 @@ public struct Destination { } // Compute common arguments for clang and swift. - var extraCCFlags: [String] = [] - var extraSwiftCFlags: [String] = [] - if let sdkPaths = Destination.sdkPlatformFrameworkPaths(environment: environment) { - extraCCFlags += ["-F", sdkPaths.fwk.pathString] - extraSwiftCFlags += ["-F", sdkPaths.fwk.pathString] - extraSwiftCFlags += ["-I", sdkPaths.lib.pathString] - extraSwiftCFlags += ["-L", sdkPaths.lib.pathString] - } + // This is currently just frameworks path. + let commonArgs = Destination.sdkPlatformFrameworkPath(environment: environment).map({ ["-F", $0.pathString] }) ?? [] return Destination( target: hostTargetTriple, sdk: sdkPath, binDir: binDir, - extraCCFlags: extraCCFlags, - extraSwiftCFlags: extraSwiftCFlags, + extraCCFlags: commonArgs, + extraSwiftCFlags: commonArgs, extraCPPFlags: ["-lc++"] ) #else @@ -133,31 +127,21 @@ public struct Destination { } /// Returns macosx sdk platform framework path. - public static func sdkPlatformFrameworkPaths( - environment: [String:String] = Process.env - ) -> (fwk: AbsolutePath, lib: AbsolutePath)? { + public static func sdkPlatformFrameworkPath(environment: [String:String] = Process.env) -> AbsolutePath? { if let path = _sdkPlatformFrameworkPath { return path } let platformPath = try? Process.checkNonZeroExit( - arguments: ["xcrun", "--sdk", "macosx", "--show-sdk-platform-path"], - environment: environment).spm_chomp() + arguments: ["xcrun", "--sdk", "macosx", "--show-sdk-platform-path"], environment: environment).spm_chomp() if let platformPath = platformPath, !platformPath.isEmpty { - // For XCTest framework. - let fwk = AbsolutePath(platformPath).appending( + _sdkPlatformFrameworkPath = AbsolutePath(platformPath).appending( components: "Developer", "Library", "Frameworks") - - // For XCTest Swift library. - let lib = AbsolutePath(platformPath).appending( - components: "Developer", "usr", "lib") - - _sdkPlatformFrameworkPath = (fwk, lib) } return _sdkPlatformFrameworkPath } /// Cache storage for sdk platform path. - private static var _sdkPlatformFrameworkPath: (fwk: AbsolutePath, lib: AbsolutePath)? = nil + private static var _sdkPlatformFrameworkPath: AbsolutePath? = nil /// Target triple for the host system. private static let hostTargetTriple = Triple.hostTriple From 720a913c1639880e32ff19bfed658c3d0b601b00 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 21 Jun 2019 11:39:05 -0700 Subject: [PATCH 60/67] [bootstrap] Add rpath to look inside @exec/../lib/swift/pm/llbuild --- Utilities/bootstrap | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Utilities/bootstrap b/Utilities/bootstrap index aabb643782a..3c5d1d2c489 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -1242,14 +1242,17 @@ def main(): build_flags.extend(["-Xswiftc", "-F%s" % args.llbuild_build_dir]) # Embed rpath to find llbuild library or framework at runtime. + llbuild_libs_rpaths = [] if args.llbuild_link_framework: - llbuild_libs_rpath = "@executable_path/../../../../../SharedFrameworks" + llbuild_libs_rpaths.append("@executable_path/../../../../../SharedFrameworks") + llbuild_libs_rpaths.append("@executable_path/../lib/swift/pm/llbuild") else: if platform.system() == 'Darwin': - llbuild_libs_rpath = "@executable_path/../lib/swift/pm/llbuild" + llbuild_libs_rpaths.append("@executable_path/../lib/swift/pm/llbuild") else: - llbuild_libs_rpath = "$ORIGIN/../lib/swift/pm/llbuild" - build_flags.extend(["-Xlinker", "-rpath", "-Xlinker", llbuild_libs_rpath]) + llbuild_libs_rpaths.append("$ORIGIN/../lib/swift/pm/llbuild") + for rpath in llbuild_libs_rpaths: + build_flags.extend(["-Xlinker", "-rpath", "-Xlinker", rpath]) # Add llbuild link flags. build_flags.extend(llbuild_link_args(args)) From 31632abdfb499f5fc98951973447d169b70369e1 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Fri, 21 Jun 2019 15:28:11 -0700 Subject: [PATCH 61/67] [SwiftTestTool] Allow skipping SwiftPM tests using an env variable --- Documentation/Development.md | 8 +++++ Sources/Commands/SwiftTestTool.swift | 45 +++++++++++++++++++++++++--- 2 files changed, 49 insertions(+), 4 deletions(-) diff --git a/Documentation/Development.md b/Documentation/Development.md index f6f7976f7bf..442e8a7a40e 100644 --- a/Documentation/Development.md +++ b/Documentation/Development.md @@ -189,3 +189,11 @@ installed. This path can be overridden by setting the environment variable absolute search paths separated by colon (":"). SwiftPM will choose the first path which exists on disk. If none of the path are present on disk, it will fall back to built-in computation. + +## Skip SwiftPM tests + +SwiftPM has a hidden env variable `_SWIFTPM_SKIP_TESTS_LIST` that can be used +to skip a list of tests. This value of the variable is either a file path that contains a +new-line separated list of tests to skip or a colon separated list of tests. + +This is only a development feature and should be considered _unsupported_. diff --git a/Sources/Commands/SwiftTestTool.swift b/Sources/Commands/SwiftTestTool.swift index 32b50293168..f8817c396f9 100644 --- a/Sources/Commands/SwiftTestTool.swift +++ b/Sources/Commands/SwiftTestTool.swift @@ -136,10 +136,38 @@ public class TestToolOptions: ToolOptions { /// Generate LinuxMain entries and exit. var shouldGenerateLinuxMain = false - var testCaseSpecifier: TestCaseSpecifier = .none + var testCaseSpecifier: TestCaseSpecifier { + testCaseSpecifierOverride() ?? _testCaseSpecifier + } + + var _testCaseSpecifier: TestCaseSpecifier = .none /// Path where the xUnit xml file should be generated. var xUnitOutput: AbsolutePath? + + /// Returns the test case specifier if overridden in the env. + private func testCaseSpecifierOverride() -> TestCaseSpecifier? { + guard let override = ProcessEnv.vars["_SWIFTPM_SKIP_TESTS_LIST"] else { + return nil + } + + do { + let skipTests: [String.SubSequence] + // Read from the file if it exists. + if let path = try? AbsolutePath(validating: override), localFileSystem.exists(path) { + let contents = try localFileSystem.readFileContents(path).cString + skipTests = contents.split(separator: "\n", omittingEmptySubsequences: true) + } else { + // Otherwise, read the env variable. + skipTests = override.split(separator: ":", omittingEmptySubsequences: true) + } + + return .skip(skipTests.map(String.init)) + } catch { + // FIXME: We should surface errors from here. + } + return nil + } } /// Tests filtering specifier @@ -152,6 +180,7 @@ public enum TestCaseSpecifier { case none case specific(String) case regex(String) + case skip([String]) } public enum TestMode { @@ -234,7 +263,7 @@ public class SwiftTestTool: SwiftTool { ) ranSuccessfully = runner.test() - case .regex, .specific: + case .regex, .specific, .skip: // If old specifier `-s` option was used, emit deprecation notice. if case .specific = options.testCaseSpecifier { diagnostics.emit(data: SpecifierDeprecatedDiagnostic()) @@ -419,7 +448,7 @@ public class SwiftTestTool: SwiftTool { binder.bind( option: parser.add(option: "--specifier", shortName: "-s", kind: String.self), - to: { $0.testCaseSpecifier = .specific($1) }) + to: { $0._testCaseSpecifier = .specific($1) }) binder.bind( option: parser.add(option: "--xunit-output", kind: PathArgument.self), @@ -429,7 +458,7 @@ public class SwiftTestTool: SwiftTool { option: parser.add(option: "--filter", kind: String.self, usage: "Run test cases matching regular expression, Format: . or " + "./"), - to: { $0.testCaseSpecifier = .regex($1) }) + to: { $0._testCaseSpecifier = .regex($1) }) binder.bind( option: parser.add(option: "--enable-code-coverage", kind: Bool.self, @@ -926,6 +955,14 @@ fileprivate extension Sequence where Iterator.Element == TestSuite { }) case .specific(let name): return allTests.filter{ $0.specifier == name } + case .skip(let skippedTests): + var result = allTests + for skippedTest in skippedTests { + result = result.filter{ + $0.specifier.range(of: skippedTest, options: .regularExpression) == nil + } + } + return result } } } From e36d674fae03ad83785ce6c4ca6d1294a733be23 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Sat, 15 Jun 2019 13:30:48 -0700 Subject: [PATCH 62/67] Implement test discovery on platforms without an Objective-C runtime (Linux, etc.) This is a WIP PR for implementing test discovery on linux using indexing data. The basic idea is to leverage the IndexStore library to get the test methods and then generate a LinuxMain.swift file during the build process. This PR "works" but there are a number of serious hacks that require resolving before we can merge it. --- Sources/Basic/Path.swift | 8 + Sources/Build/BuildDelegate.swift | 188 ++++++- Sources/Build/BuildPlan.swift | 98 +++- Sources/Build/ToolProtocol.swift | 16 +- Sources/Build/llbuild.swift | 40 +- Sources/Commands/Options.swift | 3 + Sources/Commands/SwiftTool.swift | 22 +- Sources/PackageModel/Target.swift | 13 + Sources/SPMUtility/IndexStore.swift | 240 ++++++++ Sources/SPMUtility/dlopen.swift | 116 ++++ Sources/clibc/include/indexstore_functions.h | 561 +++++++++++++++++++ Sources/clibc/include/module.modulemap | 1 + 12 files changed, 1276 insertions(+), 30 deletions(-) create mode 100644 Sources/SPMUtility/IndexStore.swift create mode 100644 Sources/SPMUtility/dlopen.swift create mode 100644 Sources/clibc/include/indexstore_functions.h diff --git a/Sources/Basic/Path.swift b/Sources/Basic/Path.swift index 1f6a528ed65..06f50abcb6c 100644 --- a/Sources/Basic/Path.swift +++ b/Sources/Basic/Path.swift @@ -121,6 +121,14 @@ public struct AbsolutePath: Hashable { return _impl.basename } + /// Returns the basename without the extension. + public var basenameWithoutExt: String { + if let ext = self.extension { + return String(basename.dropLast(ext.count + 1)) + } + return basename + } + /// Suffix (including leading `.` character) if any. Note that a basename /// that starts with a `.` character is not considered a suffix, nor is a /// trailing `.` character. diff --git a/Sources/Build/BuildDelegate.swift b/Sources/Build/BuildDelegate.swift index 0247002687c..bd183c701ee 100644 --- a/Sources/Build/BuildDelegate.swift +++ b/Sources/Build/BuildDelegate.swift @@ -186,6 +186,183 @@ extension SPMLLBuild.Diagnostic: DiagnosticDataConvertible { } } +class CustomLLBuildCommand: ExternalCommand { + let ctx: BuildExecutionContext + + required init(_ ctx: BuildExecutionContext) { + self.ctx = ctx + } + + func getSignature(_ command: SPMLLBuild.Command) -> [UInt8] { + return [] + } + + func execute(_ command: SPMLLBuild.Command) -> Bool { + fatalError("subclass responsibility") + } +} + +final class TestDiscoveryCommand: CustomLLBuildCommand { + + private func write( + tests: [IndexStore.TestCaseClass], + forModule module: String, + to path: AbsolutePath + ) throws { + let stream = try LocalFileOutputByteStream(path) + + stream <<< "import XCTest" <<< "\n" + stream <<< "@testable import " <<< module <<< "\n" + + for klass in tests { + stream <<< "\n" + stream <<< "fileprivate extension " <<< klass.name <<< " {" <<< "\n" + stream <<< indent(4) <<< "static let __allTests__\(klass.name) = [" <<< "\n" + for method in klass.methods { + let method = method.hasSuffix("()") ? String(method.dropLast(2)) : method + stream <<< indent(8) <<< "(\"\(method)\", \(method))," <<< "\n" + } + stream <<< indent(4) <<< "]" <<< "\n" + stream <<< "}" <<< "\n" + } + + stream <<< """ + func __allTests_\(module)() -> [XCTestCaseEntry] { + return [\n + """ + + for klass in tests { + stream <<< indent(8) <<< "testCase(\(klass.name).__allTests__\(klass.name)),\n" + } + + stream <<< """ + ] + } + """ + + stream.flush() + } + + private func execute(with tool: ToolProtocol) throws { + assert(tool is TestDiscoveryTool, "Unexpected tool \(tool)") + + let index = ctx.buildParameters.indexStore + let api = try ctx.indexStoreAPI.dematerialize() + let store = try IndexStore.open(store: index, api: api) + + // FIXME: We can speed this up by having one llbuild command per object file. + let tests = try tool.inputs.flatMap { + try store.listTests(inObjectFile: AbsolutePath($0)) + } + + let outputs = tool.outputs.compactMap{ try? AbsolutePath(validating: $0) } + let testsByModule = Dictionary(grouping: tests, by: { $0.module }) + + func isMainFile(_ path: AbsolutePath) -> Bool { + return path.basename == "main.swift" + } + + // Write one file for each test module. + // + // We could write everything in one file but that can easily run into type conflicts due + // in complex packages with large number of test targets. + for file in outputs { + if isMainFile(file) { continue } + + // FIXME: This is relying on implementation detail of the output but passing the + // the context all the way through is not worth it right now. + let module = file.basenameWithoutExt + + guard let tests = testsByModule[module] else { + // This module has no tests so just write an empty file for it. + try localFileSystem.writeFileContents(file, bytes: "") + continue + } + try write(tests: tests, forModule: module, to: file) + } + + // Write the main file. + let mainFile = outputs.first(where: isMainFile)! + let stream = try LocalFileOutputByteStream(mainFile) + + stream <<< "import XCTest" <<< "\n\n" + stream <<< "var tests = [XCTestCaseEntry]()" <<< "\n" + for module in testsByModule.keys { + stream <<< "tests += __allTests_\(module)()" <<< "\n" + } + stream <<< "\n" + stream <<< "XCTMain(tests)" <<< "\n" + + stream.flush() + } + + private func indent(_ spaces: Int) -> ByteStreamable { + return Format.asRepeating(string: " ", count: spaces) + } + + override func execute(_ command: SPMLLBuild.Command) -> Bool { + guard let tool = ctx.buildTimeCmdToolMap[command.name] else { + print("command \(command.name) not registered") + return false + } + do { + try execute(with: tool) + } catch { + // FIXME: Shouldn't use "print" here. + print("error:", error) + return false + } + return true + } +} + +private final class InProcessTool: Tool { + let ctx: BuildExecutionContext + + init(_ ctx: BuildExecutionContext) { + self.ctx = ctx + } + + func createCommand(_ name: String) -> ExternalCommand { + // FIXME: This should be able to dynamically look up the right command. + switch ctx.buildTimeCmdToolMap[name] { + case is TestDiscoveryTool: + return TestDiscoveryCommand(ctx) + default: + fatalError("Unhandled command \(name)") + } + } +} + +/// The context available during build execution. +public final class BuildExecutionContext { + + /// Mapping of command-name to its tool. + let buildTimeCmdToolMap: [String: ToolProtocol] + + var indexStoreAPI: Result { + indexStoreAPICache.getValue(self) + } + + let buildParameters: BuildParameters + + public init(_ plan: BuildPlan, buildTimeCmdToolMap: [String: ToolProtocol]) { + self.buildParameters = plan.buildParameters + self.buildTimeCmdToolMap = buildTimeCmdToolMap + } + + // MARK:- Private + + private var indexStoreAPICache = LazyCache(createIndexStoreAPI) + private func createIndexStoreAPI() -> Result { + Result { + let ext = buildParameters.triple.dynamicLibraryExtension + let indexStoreLib = buildParameters.toolchain.toolchainLibDir.appending(component: "libIndexStore" + ext) + return try IndexStoreAPI(dylib: indexStoreLib) + } + } +} + private let newLineByte: UInt8 = 10 public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParserDelegate { private let diagnostics: DiagnosticsEngine @@ -201,7 +378,10 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser /// Target name keyed by llbuild command name. private let targetNames: [String: String] + let buildExecutionContext: BuildExecutionContext + public init( + bctx: BuildExecutionContext, plan: BuildPlan, diagnostics: DiagnosticsEngine, outputStream: OutputByteStream, @@ -212,6 +392,7 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser // https://forums.swift.org/t/allow-self-x-in-class-convenience-initializers/15924 self.outputStream = outputStream as? ThreadSafeOutputByteStream ?? ThreadSafeOutputByteStream(outputStream) self.progressAnimation = progressAnimation + self.buildExecutionContext = bctx let buildConfig = plan.buildParameters.configuration.dirname @@ -231,7 +412,12 @@ public final class BuildDelegate: BuildSystemDelegate, SwiftCompilerOutputParser } public func lookupTool(_ name: String) -> Tool? { - return nil + switch name { + case TestDiscoveryTool.name: + return InProcessTool(buildExecutionContext) + default: + return nil + } } public func hadCommandFailure() { diff --git a/Sources/Build/BuildPlan.swift b/Sources/Build/BuildPlan.swift index b5a336ebd60..d0f0720ed35 100644 --- a/Sources/Build/BuildPlan.swift +++ b/Sources/Build/BuildPlan.swift @@ -128,6 +128,9 @@ public struct BuildParameters { /// Whether to enable code coverage. public let enableCodeCoverage: Bool + /// Whether to enable test discovery on platforms without Objective-C runtime. + public let enableTestDiscovery: Bool + /// Whether to enable generation of `.swiftinterface` files alongside /// `.swiftmodule`s. public let enableParseableModuleInterfaces: Bool @@ -156,7 +159,8 @@ public struct BuildParameters { sanitizers: EnabledSanitizers = EnabledSanitizers(), enableCodeCoverage: Bool = false, indexStoreMode: IndexStoreMode = .auto, - enableParseableModuleInterfaces: Bool = false + enableParseableModuleInterfaces: Bool = false, + enableTestDiscovery: Bool = false ) { self.dataPath = dataPath self.configuration = configuration @@ -170,6 +174,7 @@ public struct BuildParameters { self.enableCodeCoverage = enableCodeCoverage self.indexStoreMode = indexStoreMode self.enableParseableModuleInterfaces = enableParseableModuleInterfaces + self.enableTestDiscovery = enableTestDiscovery } /// Returns the compiler arguments for the index store, if enabled. @@ -469,13 +474,22 @@ public final class SwiftTargetBuildDescription { /// If this target is a test target. public let isTestTarget: Bool + /// True if this is the test discovery target. + public let testDiscoveryTarget: Bool + /// Create a new target description with target and build parameters. - init(target: ResolvedTarget, buildParameters: BuildParameters, isTestTarget: Bool? = nil) { + init( + target: ResolvedTarget, + buildParameters: BuildParameters, + isTestTarget: Bool? = nil, + testDiscoveryTarget: Bool = false + ) { assert(target.underlyingTarget is SwiftTarget, "underlying target type mismatch \(target)") self.target = target self.buildParameters = buildParameters // Unless mentioned explicitly, use the target type to determine if this is a test target. self.isTestTarget = isTestTarget ?? (target.type == .test) + self.testDiscoveryTarget = testDiscoveryTarget } /// The arguments needed to compile this target. @@ -868,6 +882,65 @@ public class BuildPlan { /// Diagnostics Engine for emitting diagnostics. let diagnostics: DiagnosticsEngine + private static func planLinuxMain( + _ buildParameters: BuildParameters, + _ graph: PackageGraph + ) throws -> (ResolvedTarget, SwiftTargetBuildDescription)? { + guard buildParameters.triple.isLinux() else { + return nil + } + + // Currently, there can be only one test product in a package graph. + guard let testProduct = graph.allProducts.first(where: { $0.type == .test }) else { + return nil + } + + if !buildParameters.enableTestDiscovery { + guard let linuxMainTarget = testProduct.linuxMainTarget else { + throw Error.missingLinuxMain + } + + let desc = SwiftTargetBuildDescription( + target: linuxMainTarget, + buildParameters: buildParameters, + isTestTarget: true + ) + return (linuxMainTarget, desc) + } + + // We'll generate sources containing the test names as part of the build process. + let derivedTestListDir = buildParameters.buildPath.appending(components: "testlist.derived") + let mainFile = derivedTestListDir.appending(component: "main.swift") + + var paths: [AbsolutePath] = [] + paths.append(mainFile) + let testTargets = graph.rootPackages.flatMap{ $0.targets }.filter{ $0.type == .test } + for testTarget in testTargets { + let path = derivedTestListDir.appending(components: testTarget.name + ".swift") + paths.append(path) + } + + let src = Sources(paths: paths, root: derivedTestListDir) + + let swiftTarget = SwiftTarget( + testDiscoverySrc: src, + name: testProduct.name, + dependencies: testProduct.underlyingProduct.targets) + let linuxMainTarget = ResolvedTarget( + target: swiftTarget, + dependencies: testProduct.targets.map(ResolvedTarget.Dependency.target) + ) + + let target = SwiftTargetBuildDescription( + target: linuxMainTarget, + buildParameters: buildParameters, + isTestTarget: true, + testDiscoveryTarget: true + ) + + return (linuxMainTarget, target) + } + /// Create a build plan with build parameters and a package graph. public init( buildParameters: BuildParameters, @@ -921,19 +994,10 @@ public class BuildPlan { throw Diagnostics.fatalError } - if buildParameters.triple.isLinux() { - // FIXME: Create a target for LinuxMain file on linux. - // This will go away once it is possible to auto detect tests. - let testProducts = graph.allProducts.filter({ $0.type == .test }) - - for product in testProducts { - guard let linuxMainTarget = product.linuxMainTarget else { - throw Error.missingLinuxMain - } - let target = SwiftTargetBuildDescription( - target: linuxMainTarget, buildParameters: buildParameters, isTestTarget: true) - targetMap[linuxMainTarget] = .swift(target) - } + // Plan the linux main target. + if let result = try Self.planLinuxMain(buildParameters, graph) { + targetMap[result.0] = .swift(result.1) + self.linuxMainTarget = result.0 } var productMap: [ResolvedProduct: ProductBuildDescription] = [:] @@ -953,6 +1017,8 @@ public class BuildPlan { try plan() } + private var linuxMainTarget: ResolvedTarget? + static func validateDeploymentVersionOfProductDependency( _ product: ResolvedProduct, forTarget target: ResolvedTarget, @@ -1094,7 +1160,7 @@ public class BuildPlan { if buildParameters.triple.isLinux() { if product.type == .test { - product.linuxMainTarget.map({ staticTargets.append($0) }) + linuxMainTarget.map({ staticTargets.append($0) }) } } diff --git a/Sources/Build/ToolProtocol.swift b/Sources/Build/ToolProtocol.swift index 07ad19b7861..aa7715de700 100644 --- a/Sources/Build/ToolProtocol.swift +++ b/Sources/Build/ToolProtocol.swift @@ -14,7 +14,7 @@ import SPMUtility import class Foundation.ProcessInfo /// Describes a tool which can be understood by llbuild's BuildSystem library. -protocol ToolProtocol { +public protocol ToolProtocol { /// The list of inputs to declare. var inputs: [String] { get } @@ -38,6 +38,20 @@ struct PhonyTool: ToolProtocol { } } +struct TestDiscoveryTool: ToolProtocol { + + static let name: String = "test-discovery-tool" + + let inputs: [String] + let outputs: [String] + + func append(to stream: OutputByteStream) { + stream <<< " tool: \(Self.name)\n" + stream <<< " inputs: " <<< Format.asJSON(inputs) <<< "\n" + stream <<< " outputs: " <<< Format.asJSON(outputs) <<< "\n" + } +} + struct ShellTool: ToolProtocol { let description: String let inputs: [String] diff --git a/Sources/Build/llbuild.swift b/Sources/Build/llbuild.swift index dd5b7861a68..5f2c589983f 100644 --- a/Sources/Build/llbuild.swift +++ b/Sources/Build/llbuild.swift @@ -14,7 +14,7 @@ import PackageModel import PackageGraph /// llbuild manifest file generator for a build plan. -public struct LLBuildManifestGenerator { +public final class LLBuildManifestGenerator { /// The name of the llbuild target that builds all products and targets (excluding tests). public static let llbuildMainTargetName = "main" @@ -49,7 +49,7 @@ public struct LLBuildManifestGenerator { } /// All commands. - private(set) var allCommands = SortedArray(areInIncreasingOrder: <) + var allCommands = SortedArray(areInIncreasingOrder: <) /// Other targets. private var otherTargets: [Target] = [] @@ -101,6 +101,8 @@ public struct LLBuildManifestGenerator { } } + addTestFileGeneration(&targets) + // Create command for all products in the plan. for (product, description) in plan.productMap { // Only build products by default if they are reachabe from a root target. @@ -134,6 +136,40 @@ public struct LLBuildManifestGenerator { try localFileSystem.writeFileContents(path, bytes: stream.bytes) } + private func addTestFileGeneration(_ targets: inout Targets) { + var testTargets: [SwiftTargetBuildDescription] = [] + var _testDiscoveryTarget: SwiftTargetBuildDescription? + + for target in plan.targets { + switch target { + case .swift(let target) where target.isTestTarget: + if target.testDiscoveryTarget { + _testDiscoveryTarget = target + } else { + testTargets.append(target) + } + default: + break + } + } + + // Nothing to do if we don't have the test discovery target. + guard let testDiscoveryTarget = _testDiscoveryTarget else { + return + } + + let objectFiles = testTargets.flatMap{ $0.objects }.map{ $0.pathString }.sorted() + let outputs = testDiscoveryTarget.target.sources.paths + let tool = TestDiscoveryTool(inputs: objectFiles, outputs: outputs.map{ $0.pathString }) + + let cmdName = outputs.first{ $0.basename == "main.swift" }!.pathString + targets.allCommands.insert(Command(name: cmdName, tool: tool)) + buildTimeCmdToolMap[cmdName] = tool + } + + /// Map of command -> tool that is used during the build for in-process tools. + public private(set) var buildTimeCmdToolMap: [String: ToolProtocol] = [:] + /// Create a llbuild target for a product description. private func createProductTarget(_ buildProduct: ProductBuildDescription) -> Target { let tool: ToolProtocol diff --git a/Sources/Commands/Options.swift b/Sources/Commands/Options.swift index 7d812f820d0..93ee81b2d86 100644 --- a/Sources/Commands/Options.swift +++ b/Sources/Commands/Options.swift @@ -77,5 +77,8 @@ public class ToolOptions { /// The number of jobs for llbuild to start (aka the number of schedulerLanes) public var jobs: UInt32? = nil + /// Whether to enable test discovery on platforms without Objective-C runtime. + public var enableTestDiscovery: Bool = false + public required init() {} } diff --git a/Sources/Commands/SwiftTool.swift b/Sources/Commands/SwiftTool.swift index 8b3d3e78c21..28c61d76565 100644 --- a/Sources/Commands/SwiftTool.swift +++ b/Sources/Commands/SwiftTool.swift @@ -362,6 +362,11 @@ public class SwiftTool { usage: "The number of jobs to spawn in parallel during the build process"), to: { $0.jobs = UInt32($1) }) + binder.bind( + option: parser.add(option: "--enable-test-discovery", kind: Bool.self, + usage: "Enable test discovery on platforms without Objective-C runtime"), + to: { $0.enableTestDiscovery = $1 }) + // Let subclasses bind arguments. type(of: self).defineArguments(parser: parser, binder: binder) @@ -583,13 +588,6 @@ public class SwiftTool { return try subset.llbuildTargetName(for: loadPackageGraph(), diagnostics: diagnostics, config: buildParameters.configuration.dirname) } } - - func build(plan: BuildPlan, parameters: BuildParameters, subset: BuildSubset) throws { - guard let llbuildTargetName = try computeLLBuildTargetName(for: subset, buildParameters: parameters) else { - return - } - try runLLBuild(plan: plan, manifest: parameters.llbuildManifest, llbuildTarget: llbuildTargetName) - } /// Build a subset of products and targets using swift-build-tool. func build(plan: BuildPlan, subset: BuildSubset) throws { @@ -602,9 +600,11 @@ public class SwiftTool { let llbuild = LLBuildManifestGenerator(plan, client: "basic") try llbuild.generateManifest(at: manifest) + let bctx = BuildExecutionContext(plan, buildTimeCmdToolMap: llbuild.buildTimeCmdToolMap) + // Run llbuild. assert(localFileSystem.isFile(manifest), "llbuild manifest not present: \(manifest)") - try runLLBuild(plan: plan, manifest: manifest, llbuildTarget: llbuildTargetName) + try runLLBuild(plan: plan, bctx: bctx, manifest: manifest, llbuildTarget: llbuildTargetName) // Create backwards-compatibilty symlink to old build path. let oldBuildPath = buildPath.appending(component: options.configuration.dirname) @@ -614,13 +614,14 @@ public class SwiftTool { try createSymlink(oldBuildPath, pointingAt: plan.buildParameters.buildPath, relative: true) } - func runLLBuild(plan: BuildPlan, manifest: AbsolutePath, llbuildTarget: String) throws { + private func runLLBuild(plan: BuildPlan, bctx: BuildExecutionContext, manifest: AbsolutePath, llbuildTarget: String) throws { // Setup the build delegate. let isVerbose = verbosity != .concise let progressAnimation: ProgressAnimationProtocol = isVerbose ? MultiLineNinjaProgressAnimation(stream: stdoutStream) : NinjaProgressAnimation(stream: stdoutStream) let buildDelegate = BuildDelegate( + bctx: bctx, plan: plan, diagnostics: diagnostics, outputStream: stdoutStream, @@ -658,7 +659,8 @@ public class SwiftTool { sanitizers: options.sanitizers, enableCodeCoverage: options.shouldEnableCodeCoverage, indexStoreMode: options.indexStoreMode, - enableParseableModuleInterfaces: options.shouldEnableParseableModuleInterfaces + enableParseableModuleInterfaces: options.shouldEnableParseableModuleInterfaces, + enableTestDiscovery: options.enableTestDiscovery ) }) }() diff --git a/Sources/PackageModel/Target.swift b/Sources/PackageModel/Target.swift index ca9cbcdb584..7f346d33bc0 100644 --- a/Sources/PackageModel/Target.swift +++ b/Sources/PackageModel/Target.swift @@ -79,6 +79,19 @@ public class SwiftTarget: Target { /// The file name of linux main file. public static let linuxMainBasename = "LinuxMain.swift" + public init(testDiscoverySrc: Sources, name: String, dependencies: [Target]) { + self.swiftVersion = .v5 + + super.init( + name: name, + platforms: [], + type: .executable, + sources: testDiscoverySrc, + dependencies: dependencies, + buildSettings: .init() + ) + } + /// Create an executable Swift target from linux main test manifest file. init(linuxMain: AbsolutePath, name: String, dependencies: [Target]) { // Look for the first swift test target and use the same swift version diff --git a/Sources/SPMUtility/IndexStore.swift b/Sources/SPMUtility/IndexStore.swift new file mode 100644 index 00000000000..99814fba409 --- /dev/null +++ b/Sources/SPMUtility/IndexStore.swift @@ -0,0 +1,240 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2019 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See http://swift.org/LICENSE.txt for license information + See http://swift.org/CONTRIBUTORS.txt for Swift project authors + */ + +import Basic +import clibc + +public final class IndexStore { + + public struct TestCaseClass { + public var name: String + public var module: String + public var methods: [String] + } + + let api: IndexStoreAPI + + var fn: indexstore_functions_t { + return api.fn + } + + let store: indexstore_t + + private init(store: indexstore_t, api: IndexStoreAPI) { + self.store = store + self.api = api + } + + static public func open(store path: AbsolutePath, api: IndexStoreAPI) throws -> IndexStore { + if let store = try api.call({ api.fn.store_create(path.pathString, &$0) }) { + return IndexStore(store: store, api: api) + } + throw StringError("Unable to open store at \(path)") + } + + public func listTests(inObjectFile object: AbsolutePath) throws -> [TestCaseClass] { + // Get the records of this object file. + let unitReader = try api.call{ fn.unit_reader_create(store, unitName(object: object), &$0) } + let records = try getRecords(unitReader: unitReader) + + // Get the test classes. + let testCaseClasses = try records.flatMap{ try self.getTestCaseClasses(forRecord: $0) } + + // Fill the module name and return. + let module = fn.unit_reader_get_module_name(unitReader).str + return testCaseClasses.map { + var c = $0 + c.module = module + return c + } + } + + private func getTestCaseClasses(forRecord record: String) throws -> [TestCaseClass] { + let recordReader = try api.call{ fn.record_reader_create(store, record, &$0) } + + class TestCaseBuilder { + var classToMethods: [String: Set] = [:] + + func add(klass: String, method: String) { + classToMethods[klass, default: []].insert(method) + } + + func build() -> [TestCaseClass] { + return classToMethods.map { + TestCaseClass(name: $0.key, module: "", methods: $0.value.sorted()) + } + } + } + + let builder = Ref(TestCaseBuilder(), api: api) + + let ctx = unsafeBitCast(Unmanaged.passUnretained(builder), to: UnsafeMutableRawPointer.self) + _ = fn.record_reader_occurrences_apply_f(recordReader, ctx) { ctx , occ -> Bool in + let builder = Unmanaged>.fromOpaque(ctx!).takeUnretainedValue() + let fn = builder.api.fn + + // Get the symbol. + let sym = fn.occurrence_get_symbol(occ) + + // We only care about symbols that are marked unit tests and are instance methods. + if fn.symbol_get_properties(sym) != UInt64(INDEXSTORE_SYMBOL_PROPERTY_UNITTEST.rawValue) { + return true + } + if fn.symbol_get_kind(sym) != INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD { + return true + } + + let className = Ref("", api: builder.api) + let ctx = unsafeBitCast(Unmanaged.passUnretained(className), to: UnsafeMutableRawPointer.self) + + _ = fn.occurrence_relations_apply_f(occ!, ctx) { ctx, relation in + guard let relation = relation else { return true } + let className = Unmanaged>.fromOpaque(ctx!).takeUnretainedValue() + let fn = className.api.fn + + // Look for the class. + if fn.symbol_relation_get_roles(relation) != UInt64(INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF.rawValue) { + return true + } + + let sym = fn.symbol_relation_get_symbol(relation) + className.instance = fn.symbol_get_name(sym).str + return true + } + + if !className.instance.isEmpty { + let testMethod = fn.symbol_get_name(sym).str + builder.instance.add(klass: className.instance, method: testMethod) + } + + return true + } + + return builder.instance.build() + } + + private func getRecords(unitReader: indexstore_unit_reader_t?) throws -> [String] { + let builder = Ref([String](), api: api) + + let ctx = unsafeBitCast(Unmanaged.passUnretained(builder), to: UnsafeMutableRawPointer.self) + _ = fn.unit_reader_dependencies_apply_f(unitReader, ctx) { ctx , unit -> Bool in + let store = Unmanaged>.fromOpaque(ctx!).takeUnretainedValue() + let fn = store.api.fn + if fn.unit_dependency_get_kind(unit) == INDEXSTORE_UNIT_DEPENDENCY_RECORD { + store.instance.append(fn.unit_dependency_get_name(unit).str) + } + return true + } + + return builder.instance + } + + private func unitName(object: AbsolutePath) -> String { + let initialSize = 64 + var buf = UnsafeMutablePointer.allocate(capacity: initialSize) + let len = fn.store_get_unit_name_from_output_path(store, object.pathString, buf, initialSize) + + if len + 1 > initialSize { + buf.deallocate() + buf = UnsafeMutablePointer.allocate(capacity: len + 1) + _ = fn.store_get_unit_name_from_output_path(store, object.pathString, buf, len + 1) + } + + defer { + buf.deallocate() + } + + return String(cString: buf) + } +} + +private class Ref { + let api: IndexStoreAPI + var instance: T + init(_ instance: T, api: IndexStoreAPI) { + self.instance = instance + self.api = api + } +} + +public final class IndexStoreAPI { + + /// The path of the index store dylib. + private let path: AbsolutePath + + /// Handle of the dynamic library. + private let dylib: DLHandle + + /// The index store API functions. + fileprivate let fn: indexstore_functions_t + + fileprivate func call(_ fn: (inout indexstore_error_t?) -> T) throws -> T { + var error: indexstore_error_t? = nil + let ret = fn(&error) + + if let error = error { + if let desc = self.fn.error_get_description(error) { + throw StringError(String(cString: desc)) + } + throw StringError("Unable to get description for error: \(error)") + } + + return ret + } + + public init(dylib path: AbsolutePath) throws { + self.path = path + self.dylib = try dlopen(path.pathString, mode: [.lazy, .local, .first, .deepBind]) + + func dlsym_required(_ handle: DLHandle, symbol: String) throws -> T { + guard let sym: T = dlsym(handle, symbol: symbol) else { + throw StringError("Missing required symbol: \(symbol)") + } + return sym + } + + var api = indexstore_functions_t() + api.store_create = try dlsym_required(dylib, symbol: "indexstore_store_create") + api.store_get_unit_name_from_output_path = try dlsym_required(dylib, symbol: "indexstore_store_get_unit_name_from_output_path") + api.unit_reader_create = try dlsym_required(dylib, symbol: "indexstore_unit_reader_create") + api.error_get_description = try dlsym_required(dylib, symbol: "indexstore_error_get_description") + api.unit_reader_dependencies_apply_f = try dlsym_required(dylib, symbol: "indexstore_unit_reader_dependencies_apply_f") + api.unit_reader_get_module_name = try dlsym_required(dylib, symbol: "indexstore_unit_reader_get_module_name") + api.unit_dependency_get_kind = try dlsym_required(dylib, symbol: "indexstore_unit_dependency_get_kind") + api.unit_dependency_get_name = try dlsym_required(dylib, symbol: "indexstore_unit_dependency_get_name") + api.record_reader_create = try dlsym_required(dylib, symbol: "indexstore_record_reader_create") + api.symbol_get_name = try dlsym_required(dylib, symbol: "indexstore_symbol_get_name") + api.symbol_get_properties = try dlsym_required(dylib, symbol: "indexstore_symbol_get_properties") + api.symbol_get_kind = try dlsym_required(dylib, symbol: "indexstore_symbol_get_kind") + api.record_reader_occurrences_apply_f = try dlsym_required(dylib, symbol: "indexstore_record_reader_occurrences_apply_f") + api.occurrence_get_symbol = try dlsym_required(dylib, symbol: "indexstore_occurrence_get_symbol") + api.occurrence_relations_apply_f = try dlsym_required(dylib, symbol: "indexstore_occurrence_relations_apply_f") + api.symbol_relation_get_symbol = try dlsym_required(dylib, symbol: "indexstore_symbol_relation_get_symbol") + api.symbol_relation_get_roles = try dlsym_required(dylib, symbol: "indexstore_symbol_relation_get_roles") + + self.fn = api + } + + deinit { + // FIXME: is it safe to dlclose() indexstore? If so, do that here. For now, let the handle leak. + dylib.leak() + } +} + +extension indexstore_string_ref_t { + fileprivate var str: String { + return String( + bytesNoCopy: UnsafeMutableRawPointer(mutating: data), + length: length, + encoding: .utf8, + freeWhenDone: false + )! + } +} diff --git a/Sources/SPMUtility/dlopen.swift b/Sources/SPMUtility/dlopen.swift new file mode 100644 index 00000000000..a36b00522a2 --- /dev/null +++ b/Sources/SPMUtility/dlopen.swift @@ -0,0 +1,116 @@ +/* + This source file is part of the Swift.org open source project + + Copyright (c) 2019 Apple Inc. and the Swift project authors + Licensed under Apache License v2.0 with Runtime Library Exception + + See http://swift.org/LICENSE.txt for license information + See http://swift.org/CONTRIBUTORS.txt for Swift project authors +*/ + +import SPMLibc + +public final class DLHandle { + #if os(Windows) + typealias Handle = HMODULE + #else + typealias Handle = UnsafeMutableRawPointer + #endif + var rawValue: Handle? = nil + + init(rawValue: Handle) { + self.rawValue = rawValue + } + + deinit { + precondition(rawValue == nil, "DLHandle must be closed or explicitly leaked before destroying") + } + + public func close() throws { + if let handle = rawValue { + #if os(Windows) + guard FreeLibrary(handle) != 0 else { + throw DLError.close("Failed to FreeLibrary: \(GetLastError())") + } + #else + guard dlclose(handle) == 0 else { + throw DLError.close(dlerror() ?? "unknown error") + } + #endif + } + rawValue = nil + } + + public func leak() { + rawValue = nil + } +} + +public struct DLOpenFlags: RawRepresentable, OptionSet { + + #if !os(Windows) + public static let lazy: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LAZY) + public static let now: DLOpenFlags = DLOpenFlags(rawValue: RTLD_NOW) + public static let local: DLOpenFlags = DLOpenFlags(rawValue: RTLD_LOCAL) + public static let global: DLOpenFlags = DLOpenFlags(rawValue: RTLD_GLOBAL) + + // Platform-specific flags. + #if os(macOS) + public static let first: DLOpenFlags = DLOpenFlags(rawValue: RTLD_FIRST) + public static let deepBind: DLOpenFlags = DLOpenFlags(rawValue: 0) + #else + public static let first: DLOpenFlags = DLOpenFlags(rawValue: 0) + public static let deepBind: DLOpenFlags = DLOpenFlags(rawValue: RTLD_DEEPBIND) + #endif + #endif + + public var rawValue: Int32 + + public init(rawValue: Int32) { + self.rawValue = rawValue + } +} + +public enum DLError: Swift.Error { + case `open`(String) + case close(String) +} + +public func dlopen(_ path: String?, mode: DLOpenFlags) throws -> DLHandle { + #if os(Windows) + guard let handle = path?.withCString(encodedAs: UTF16.self, LoadLibraryW) else { + throw DLError.open("LoadLibraryW failed: \(GetLastError())") + } + #else + guard let handle = SPMLibc.dlopen(path, mode.rawValue) else { + throw DLError.open(dlerror() ?? "unknown error") + } + #endif + return DLHandle(rawValue: handle) +} + +public func dlsym(_ handle: DLHandle, symbol: String) -> T? { + #if os(Windows) + guard let ptr = GetProcAddress(handle.rawValue!, symbol) else { + return nil + } + #else + guard let ptr = dlsym(handle.rawValue!, symbol) else { + return nil + } + #endif + return unsafeBitCast(ptr, to: T.self) +} + +public func dlclose(_ handle: DLHandle) throws { + try handle.close() +} + +#if !os(Windows) +public func dlerror() -> String? { + if let err: UnsafeMutablePointer = dlerror() { + return String(cString: err) + } + return nil +} +#endif diff --git a/Sources/clibc/include/indexstore_functions.h b/Sources/clibc/include/indexstore_functions.h new file mode 100644 index 00000000000..cc2ca2acbe1 --- /dev/null +++ b/Sources/clibc/include/indexstore_functions.h @@ -0,0 +1,561 @@ +/*===-- indexstore/indexstore_functions.h - Index Store C API ------- C -*-===*\ +|* *| +|* The LLVM Compiler Infrastructure *| +|* *| +|* This file is distributed under the University of Illinois Open Source *| +|* License. See LICENSE.TXT for details. *| +|* *| +|*===----------------------------------------------------------------------===*| +|* *| +|* Shim version of indexstore.h suitable for using with dlopen. *| +|* *| +\*===----------------------------------------------------------------------===*/ + +#ifndef INDEXSTOREDB_INDEXSTORE_INDEXSTORE_FUNCTIONS_H +#define INDEXSTOREDB_INDEXSTORE_INDEXSTORE_FUNCTIONS_H + +#include +#include +#include +#include + +/** + * \brief The version constants for the Index Store C API. + * INDEXSTORE_VERSION_MINOR should increase when there are API additions. + * INDEXSTORE_VERSION_MAJOR is intended for "major" source/ABI breaking changes. + */ +#define INDEXSTORE_VERSION_MAJOR 0 +#define INDEXSTORE_VERSION_MINOR 11 + +#define INDEXSTORE_VERSION_ENCODE(major, minor) ( \ + ((major) * 10000) \ + + ((minor) * 1)) + +#define INDEXSTORE_VERSION INDEXSTORE_VERSION_ENCODE( \ + INDEXSTORE_VERSION_MAJOR, \ + INDEXSTORE_VERSION_MINOR ) + +#define INDEXSTORE_VERSION_STRINGIZE_(major, minor) \ + #major"."#minor +#define INDEXSTORE_VERSION_STRINGIZE(major, minor) \ + INDEXSTORE_VERSION_STRINGIZE_(major, minor) + +#define INDEXSTORE_VERSION_STRING INDEXSTORE_VERSION_STRINGIZE( \ + INDEXSTORE_VERSION_MAJOR, \ + INDEXSTORE_VERSION_MINOR) + +// Workaround a modules issue with time_t on linux. +#if __has_include() +#include +#endif + +#ifdef __cplusplus +# define INDEXSTORE_BEGIN_DECLS extern "C" { +# define INDEXSTORE_END_DECLS } +#else +# define INDEXSTORE_BEGIN_DECLS +# define INDEXSTORE_END_DECLS +#endif + +#ifndef INDEXSTORE_PUBLIC +# if defined (_MSC_VER) +# define INDEXSTORE_PUBLIC __declspec(dllimport) +# else +# define INDEXSTORE_PUBLIC +# endif +#endif + +#ifndef __has_feature +# define __has_feature(x) 0 +#endif + +// FIXME: we need a runtime check as well since the library may have been built +// without blocks support. +#if __has_feature(blocks) && defined(__APPLE__) +# define INDEXSTORE_HAS_BLOCKS 1 +#else +# define INDEXSTORE_HAS_BLOCKS 0 +#endif + +INDEXSTORE_BEGIN_DECLS + +typedef void *indexstore_error_t; + +typedef struct { + const char *data; + size_t length; +} indexstore_string_ref_t; + +typedef void *indexstore_t; + +typedef void *indexstore_unit_event_notification_t; +typedef void *indexstore_unit_event_t; + +typedef enum { + INDEXSTORE_UNIT_EVENT_ADDED = 1, + INDEXSTORE_UNIT_EVENT_REMOVED = 2, + INDEXSTORE_UNIT_EVENT_MODIFIED = 3, + INDEXSTORE_UNIT_EVENT_DIRECTORY_DELETED = 4, +} indexstore_unit_event_kind_t; + +typedef struct { + /// If true, \c indexstore_store_start_unit_event_listening will block until + /// the initial set of units is passed to the unit event handler, otherwise + /// the function will return and the initial set will be passed asynchronously. + bool wait_initial_sync; +} indexstore_unit_event_listen_options_t; + +typedef void *indexstore_symbol_t; + +typedef enum { + INDEXSTORE_SYMBOL_KIND_UNKNOWN = 0, + INDEXSTORE_SYMBOL_KIND_MODULE = 1, + INDEXSTORE_SYMBOL_KIND_NAMESPACE = 2, + INDEXSTORE_SYMBOL_KIND_NAMESPACEALIAS = 3, + INDEXSTORE_SYMBOL_KIND_MACRO = 4, + INDEXSTORE_SYMBOL_KIND_ENUM = 5, + INDEXSTORE_SYMBOL_KIND_STRUCT = 6, + INDEXSTORE_SYMBOL_KIND_CLASS = 7, + INDEXSTORE_SYMBOL_KIND_PROTOCOL = 8, + INDEXSTORE_SYMBOL_KIND_EXTENSION = 9, + INDEXSTORE_SYMBOL_KIND_UNION = 10, + INDEXSTORE_SYMBOL_KIND_TYPEALIAS = 11, + INDEXSTORE_SYMBOL_KIND_FUNCTION = 12, + INDEXSTORE_SYMBOL_KIND_VARIABLE = 13, + INDEXSTORE_SYMBOL_KIND_FIELD = 14, + INDEXSTORE_SYMBOL_KIND_ENUMCONSTANT = 15, + INDEXSTORE_SYMBOL_KIND_INSTANCEMETHOD = 16, + INDEXSTORE_SYMBOL_KIND_CLASSMETHOD = 17, + INDEXSTORE_SYMBOL_KIND_STATICMETHOD = 18, + INDEXSTORE_SYMBOL_KIND_INSTANCEPROPERTY = 19, + INDEXSTORE_SYMBOL_KIND_CLASSPROPERTY = 20, + INDEXSTORE_SYMBOL_KIND_STATICPROPERTY = 21, + INDEXSTORE_SYMBOL_KIND_CONSTRUCTOR = 22, + INDEXSTORE_SYMBOL_KIND_DESTRUCTOR = 23, + INDEXSTORE_SYMBOL_KIND_CONVERSIONFUNCTION = 24, + INDEXSTORE_SYMBOL_KIND_PARAMETER = 25, + INDEXSTORE_SYMBOL_KIND_USING = 26, + + INDEXSTORE_SYMBOL_KIND_COMMENTTAG = 1000, +} indexstore_symbol_kind_t; + +typedef enum { + INDEXSTORE_SYMBOL_SUBKIND_NONE = 0, + INDEXSTORE_SYMBOL_SUBKIND_CXXCOPYCONSTRUCTOR = 1, + INDEXSTORE_SYMBOL_SUBKIND_CXXMOVECONSTRUCTOR = 2, + INDEXSTORE_SYMBOL_SUBKIND_ACCESSORGETTER = 3, + INDEXSTORE_SYMBOL_SUBKIND_ACCESSORSETTER = 4, + INDEXSTORE_SYMBOL_SUBKIND_USINGTYPENAME = 5, + INDEXSTORE_SYMBOL_SUBKIND_USINGVALUE = 6, + + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORWILLSET = 1000, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORDIDSET = 1001, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORADDRESSOR = 1002, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMUTABLEADDRESSOR = 1003, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFSTRUCT = 1004, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFCLASS = 1005, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFENUM = 1006, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTEXTENSIONOFPROTOCOL = 1007, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTPREFIXOPERATOR = 1008, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTPOSTFIXOPERATOR = 1009, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTINFIXOPERATOR = 1010, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTSUBSCRIPT = 1011, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTASSOCIATEDTYPE = 1012, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTGENERICTYPEPARAM = 1013, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORREAD = 1014, + INDEXSTORE_SYMBOL_SUBKIND_SWIFTACCESSORMODIFY = 1015, +} indexstore_symbol_subkind_t; + +typedef enum { + INDEXSTORE_SYMBOL_PROPERTY_GENERIC = 1 << 0, + INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_PARTIAL_SPECIALIZATION = 1 << 1, + INDEXSTORE_SYMBOL_PROPERTY_TEMPLATE_SPECIALIZATION = 1 << 2, + INDEXSTORE_SYMBOL_PROPERTY_UNITTEST = 1 << 3, + INDEXSTORE_SYMBOL_PROPERTY_IBANNOTATED = 1 << 4, + INDEXSTORE_SYMBOL_PROPERTY_IBOUTLETCOLLECTION = 1 << 5, + INDEXSTORE_SYMBOL_PROPERTY_GKINSPECTABLE = 1 << 6, + INDEXSTORE_SYMBOL_PROPERTY_LOCAL = 1 << 7, + INDEXSTORE_SYMBOL_PROPERTY_PROTOCOL_INTERFACE = 1 << 8, +} indexstore_symbol_property_t; + +typedef enum { + INDEXSTORE_SYMBOL_LANG_C = 0, + INDEXSTORE_SYMBOL_LANG_OBJC = 1, + INDEXSTORE_SYMBOL_LANG_CXX = 2, + + INDEXSTORE_SYMBOL_LANG_SWIFT = 100, +} indexstore_symbol_language_t; + +typedef enum { + INDEXSTORE_SYMBOL_ROLE_DECLARATION = 1 << 0, + INDEXSTORE_SYMBOL_ROLE_DEFINITION = 1 << 1, + INDEXSTORE_SYMBOL_ROLE_REFERENCE = 1 << 2, + INDEXSTORE_SYMBOL_ROLE_READ = 1 << 3, + INDEXSTORE_SYMBOL_ROLE_WRITE = 1 << 4, + INDEXSTORE_SYMBOL_ROLE_CALL = 1 << 5, + INDEXSTORE_SYMBOL_ROLE_DYNAMIC = 1 << 6, + INDEXSTORE_SYMBOL_ROLE_ADDRESSOF = 1 << 7, + INDEXSTORE_SYMBOL_ROLE_IMPLICIT = 1 << 8, + INDEXSTORE_SYMBOL_ROLE_UNDEFINITION = 1 << 19, + + // Relation roles. + INDEXSTORE_SYMBOL_ROLE_REL_CHILDOF = 1 << 9, + INDEXSTORE_SYMBOL_ROLE_REL_BASEOF = 1 << 10, + INDEXSTORE_SYMBOL_ROLE_REL_OVERRIDEOF = 1 << 11, + INDEXSTORE_SYMBOL_ROLE_REL_RECEIVEDBY = 1 << 12, + INDEXSTORE_SYMBOL_ROLE_REL_CALLEDBY = 1 << 13, + INDEXSTORE_SYMBOL_ROLE_REL_EXTENDEDBY = 1 << 14, + INDEXSTORE_SYMBOL_ROLE_REL_ACCESSOROF = 1 << 15, + INDEXSTORE_SYMBOL_ROLE_REL_CONTAINEDBY = 1 << 16, + INDEXSTORE_SYMBOL_ROLE_REL_IBTYPEOF = 1 << 17, + INDEXSTORE_SYMBOL_ROLE_REL_SPECIALIZATIONOF = 1 << 18, +} indexstore_symbol_role_t; + +typedef void *indexstore_unit_dependency_t; +typedef void *indexstore_unit_include_t; + +typedef enum { + INDEXSTORE_UNIT_DEPENDENCY_UNIT = 1, + INDEXSTORE_UNIT_DEPENDENCY_RECORD = 2, + INDEXSTORE_UNIT_DEPENDENCY_FILE = 3, +} indexstore_unit_dependency_kind_t; + +typedef void *indexstore_symbol_relation_t; + +typedef void *indexstore_occurrence_t; + +typedef void *indexstore_record_reader_t; + +typedef void *indexstore_unit_reader_t; + +#if INDEXSTORE_HAS_BLOCKS +typedef void (^indexstore_unit_event_handler_t)(indexstore_unit_event_notification_t); +#endif + +typedef struct { + INDEXSTORE_PUBLIC const char * + (*error_get_description)(indexstore_error_t); + + INDEXSTORE_PUBLIC void + (*error_dispose)(indexstore_error_t); + + INDEXSTORE_PUBLIC unsigned + (*format_version)(void); + + INDEXSTORE_PUBLIC indexstore_t + (*store_create)(const char *store_path, indexstore_error_t *error); + + INDEXSTORE_PUBLIC void + (*store_dispose)(indexstore_t); + + #if INDEXSTORE_HAS_BLOCKS + INDEXSTORE_PUBLIC bool + (*store_units_apply)(indexstore_t, unsigned sorted, + bool(^applier)(indexstore_string_ref_t unit_name)); + #endif + + INDEXSTORE_PUBLIC bool + (*store_units_apply_f)(indexstore_t, unsigned sorted, + void *context, + bool(*applier)(void *context, indexstore_string_ref_t unit_name)); + + INDEXSTORE_PUBLIC size_t + (*unit_event_notification_get_events_count)(indexstore_unit_event_notification_t); + + INDEXSTORE_PUBLIC indexstore_unit_event_t + (*unit_event_notification_get_event)(indexstore_unit_event_notification_t, size_t index); + + INDEXSTORE_PUBLIC bool + (*unit_event_notification_is_initial)(indexstore_unit_event_notification_t); + + INDEXSTORE_PUBLIC indexstore_unit_event_kind_t + (*unit_event_get_kind)(indexstore_unit_event_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_event_get_unit_name)(indexstore_unit_event_t); + + INDEXSTORE_PUBLIC struct timespec + (*unit_event_get_modification_time)(indexstore_unit_event_t); + + + #if INDEXSTORE_HAS_BLOCKS + INDEXSTORE_PUBLIC void + (*store_set_unit_event_handler)(indexstore_t, + indexstore_unit_event_handler_t handler); + #endif + + INDEXSTORE_PUBLIC void + (*store_set_unit_event_handler_f)(indexstore_t, void *context, + void(*handler)(void *context, indexstore_unit_event_notification_t), + void(*finalizer)(void *context)); + + INDEXSTORE_PUBLIC bool + (*store_start_unit_event_listening)(indexstore_t, + indexstore_unit_event_listen_options_t *, + size_t listen_options_struct_size, + indexstore_error_t *error); + + INDEXSTORE_PUBLIC void + (*store_stop_unit_event_listening)(indexstore_t); + + INDEXSTORE_PUBLIC void + (*store_discard_unit)(indexstore_t, const char *unit_name); + + INDEXSTORE_PUBLIC void + (*store_discard_record)(indexstore_t, const char *record_name); + + INDEXSTORE_PUBLIC void + (*store_purge_stale_data)(indexstore_t); + + /// Determines the unit name from the \c output_path and writes it out in the + /// \c name_buf buffer. It doesn't write more than \c buf_size. + /// \returns the length of the name. If this is larger than \c buf_size, the + /// caller should call the function again with a buffer of the appropriate size. + INDEXSTORE_PUBLIC size_t + (*store_get_unit_name_from_output_path)(indexstore_t store, + const char *output_path, + char *name_buf, + size_t buf_size); + + /// \returns true if an error occurred, false otherwise. + INDEXSTORE_PUBLIC bool + (*store_get_unit_modification_time)(indexstore_t store, + const char *unit_name, + int64_t *seconds, + int64_t *nanoseconds, + indexstore_error_t *error); + + + INDEXSTORE_PUBLIC indexstore_symbol_language_t + (*symbol_get_language)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC indexstore_symbol_kind_t + (*symbol_get_kind)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC indexstore_symbol_subkind_t + (*symbol_get_subkind)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC uint64_t + (*symbol_get_properties)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC uint64_t + (*symbol_get_roles)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC uint64_t + (*symbol_get_related_roles)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*symbol_get_name)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*symbol_get_usr)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*symbol_get_codegen_name)(indexstore_symbol_t); + + INDEXSTORE_PUBLIC uint64_t + (*symbol_relation_get_roles)(indexstore_symbol_relation_t); + + INDEXSTORE_PUBLIC indexstore_symbol_t + (*symbol_relation_get_symbol)(indexstore_symbol_relation_t); + + INDEXSTORE_PUBLIC indexstore_symbol_t + (*occurrence_get_symbol)(indexstore_occurrence_t); + + #if INDEXSTORE_HAS_BLOCKS + INDEXSTORE_PUBLIC bool + (*occurrence_relations_apply)(indexstore_occurrence_t, + bool(^applier)(indexstore_symbol_relation_t symbol_rel)); + #endif + + INDEXSTORE_PUBLIC bool + (*occurrence_relations_apply_f)(indexstore_occurrence_t, + void *context, + bool(*applier)(void *context, indexstore_symbol_relation_t symbol_rel)); + + INDEXSTORE_PUBLIC uint64_t + (*occurrence_get_roles)(indexstore_occurrence_t); + + INDEXSTORE_PUBLIC void + (*occurrence_get_line_col)(indexstore_occurrence_t, + unsigned *line, unsigned *column); + + INDEXSTORE_PUBLIC indexstore_record_reader_t + (*record_reader_create)(indexstore_t store, const char *record_name, + indexstore_error_t *error); + + INDEXSTORE_PUBLIC void + (*record_reader_dispose)(indexstore_record_reader_t); + + #if INDEXSTORE_HAS_BLOCKS + /// Goes through the symbol data and passes symbols to \c receiver, for the + /// symbol data that \c filter returns true on. + /// + /// This allows allocating memory only for the record symbols that the caller is + /// interested in. + INDEXSTORE_PUBLIC bool + (*record_reader_search_symbols)(indexstore_record_reader_t, + bool(^filter)(indexstore_symbol_t symbol, bool *stop), + void(^receiver)(indexstore_symbol_t symbol)); + + /// \param nocache if true, avoids allocating memory for the symbols. + /// Useful when the caller does not intend to keep \c indexstore_record_reader_t + /// for more queries. + INDEXSTORE_PUBLIC bool + (*record_reader_symbols_apply)(indexstore_record_reader_t, + bool nocache, + bool(^applier)(indexstore_symbol_t symbol)); + + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_apply)(indexstore_record_reader_t, + bool(^applier)(indexstore_occurrence_t occur)); + + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_in_line_range_apply)(indexstore_record_reader_t, + unsigned line_start, + unsigned line_count, + bool(^applier)(indexstore_occurrence_t occur)); + + /// \param symbols if non-zero \c symbols_count, indicates the list of symbols + /// that we want to get occurrences for. An empty array indicates that we want + /// occurrences for all symbols. + /// \param related_symbols Same as \c symbols but for related symbols. + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_of_symbols_apply)(indexstore_record_reader_t, + indexstore_symbol_t *symbols, size_t symbols_count, + indexstore_symbol_t *related_symbols, size_t related_symbols_count, + bool(^applier)(indexstore_occurrence_t occur)); + #endif + + INDEXSTORE_PUBLIC bool + (*record_reader_search_symbols_f)(indexstore_record_reader_t, + void *filter_ctx, + bool(*filter)(void *filter_ctx, indexstore_symbol_t symbol, bool *stop), + void *receiver_ctx, + void(*receiver)(void *receiver_ctx, indexstore_symbol_t symbol)); + + INDEXSTORE_PUBLIC bool + (*record_reader_symbols_apply_f)(indexstore_record_reader_t, + bool nocache, + void *context, + bool(*applier)(void *context, indexstore_symbol_t symbol)); + + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_apply_f)(indexstore_record_reader_t, + void *context, + bool(*applier)(void *context, indexstore_occurrence_t occur)); + + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_in_line_range_apply_f)(indexstore_record_reader_t, + unsigned line_start, + unsigned line_count, + void *context, + bool(*applier)(void *context, indexstore_occurrence_t occur)); + + INDEXSTORE_PUBLIC bool + (*record_reader_occurrences_of_symbols_apply_f)(indexstore_record_reader_t, + indexstore_symbol_t *symbols, size_t symbols_count, + indexstore_symbol_t *related_symbols, size_t related_symbols_count, + void *context, + bool(*applier)(void *context, indexstore_occurrence_t occur)); + + + INDEXSTORE_PUBLIC indexstore_unit_reader_t + (*unit_reader_create)(indexstore_t store, const char *unit_name, + indexstore_error_t *error); + + void + (*unit_reader_dispose)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_provider_identifier)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_provider_version)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC void + (*unit_reader_get_modification_time)(indexstore_unit_reader_t, + int64_t *seconds, + int64_t *nanoseconds); + + INDEXSTORE_PUBLIC bool + (*unit_reader_is_system_unit)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC bool + (*unit_reader_is_module_unit)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC bool + (*unit_reader_is_debug_compilation)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC bool + (*unit_reader_has_main_file)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_main_file)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_module_name)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_working_dir)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_output_file)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_sysroot_path)(indexstore_unit_reader_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_reader_get_target)(indexstore_unit_reader_t); + + + INDEXSTORE_PUBLIC indexstore_unit_dependency_kind_t + (*unit_dependency_get_kind)(indexstore_unit_dependency_t); + + INDEXSTORE_PUBLIC bool + (*unit_dependency_is_system)(indexstore_unit_dependency_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_dependency_get_filepath)(indexstore_unit_dependency_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_dependency_get_modulename)(indexstore_unit_dependency_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_dependency_get_name)(indexstore_unit_dependency_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_include_get_source_path)(indexstore_unit_include_t); + + INDEXSTORE_PUBLIC indexstore_string_ref_t + (*unit_include_get_target_path)(indexstore_unit_include_t); + + INDEXSTORE_PUBLIC unsigned + (*unit_include_get_source_line)(indexstore_unit_include_t); + + #if INDEXSTORE_HAS_BLOCKS + INDEXSTORE_PUBLIC bool + (*unit_reader_dependencies_apply)(indexstore_unit_reader_t, + bool(^applier)(indexstore_unit_dependency_t)); + + INDEXSTORE_PUBLIC bool + (*unit_reader_includes_apply)(indexstore_unit_reader_t, + bool(^applier)(indexstore_unit_include_t)); + #endif + + INDEXSTORE_PUBLIC bool + (*unit_reader_dependencies_apply_f)(indexstore_unit_reader_t, + void *context, + bool(*applier)(void *context, indexstore_unit_dependency_t)); + + INDEXSTORE_PUBLIC bool + (*unit_reader_includes_apply_f)(indexstore_unit_reader_t, + void *context, + bool(*applier)(void *context, indexstore_unit_include_t)); + +} indexstore_functions_t; + + +INDEXSTORE_END_DECLS + +#endif diff --git a/Sources/clibc/include/module.modulemap b/Sources/clibc/include/module.modulemap index b276387c7a1..2f908650dde 100644 --- a/Sources/clibc/include/module.modulemap +++ b/Sources/clibc/include/module.modulemap @@ -1,4 +1,5 @@ module clibc { header "clibc.h" + header "indexstore_functions.h" export * } From d444c08bb9bdbf0907b827aa9f69871dab35fdde Mon Sep 17 00:00:00 2001 From: Daniel Duan Date: Sat, 22 Jun 2019 14:57:46 -0700 Subject: [PATCH 63/67] Ignore xcuserdata/ Now that SwiftPM is more likely to checked in alongside with Xcode artifacts, ignore the commonly ignored Xcode artifacts. --- Sources/Workspace/InitPackage.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Sources/Workspace/InitPackage.swift b/Sources/Workspace/InitPackage.swift index 41e781b5655..31670b22764 100644 --- a/Sources/Workspace/InitPackage.swift +++ b/Sources/Workspace/InitPackage.swift @@ -176,6 +176,7 @@ public final class InitPackage { /.build /Packages /*.xcodeproj + xcuserdata/ """ } From f6292e68b99a781b952f74fc6548f90d654c9a30 Mon Sep 17 00:00:00 2001 From: Benjamin Scholtysik Date: Tue, 18 Jun 2019 14:42:37 -0700 Subject: [PATCH 64/67] Update the in-source docs for better readability. --- .../PackageDescription4/BuildSettings.swift | 151 ++++++++------- .../LanguageStandardSettings.swift | 12 +- Sources/PackageDescription4/Package.swift | 181 +++++++++++------- .../PackageDependency.swift | 39 ++-- .../PackageRequirement.swift | 31 +-- Sources/PackageDescription4/Product.swift | 42 ++-- .../SupportedPlatforms.swift | 95 +++++---- Sources/PackageDescription4/Target.swift | 179 +++++++++-------- .../Version+StringLiteralConvertible.swift | 20 ++ Sources/PackageDescription4/Version.swift | 62 +++--- 10 files changed, 460 insertions(+), 352 deletions(-) diff --git a/Sources/PackageDescription4/BuildSettings.swift b/Sources/PackageDescription4/BuildSettings.swift index 5cdcd490e1b..575ed20388a 100644 --- a/Sources/PackageDescription4/BuildSettings.swift +++ b/Sources/PackageDescription4/BuildSettings.swift @@ -8,7 +8,7 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// The build configuration such as debug or release. +/// The build configuration such as debug or release.. public struct BuildConfiguration: Encodable { private let config: String @@ -23,31 +23,31 @@ public struct BuildConfiguration: Encodable { public static let release: BuildConfiguration = BuildConfiguration("release") } -/// A build setting condition. +/// A condition that limits the application of a build setting. /// -/// By default, build settings will be applicable for all platforms and build -/// configurations. The `.when` modifier can be used to conditionalize a build -/// setting. Invalid usage of `.when` will cause an error to be emitted during -/// manifest parsing. For example, it is invalid to specify a `.when` condition with +/// By default, build settings are applicable for all platforms and build +/// configurations. Use the `.when` modifier to define a build +/// setting for a specific condition. Invalid usage of `.when` emits an error during +/// manifest parsing. For example, it's invalid to specify a `.when` condition with /// both parameters as `nil`. /// -/// Here is an example usage of build setting conditions with various APIs: +/// The following example shows how to use build setting conditions with various APIs: /// -/// ... -/// .target( -/// name: "MyTool", -/// dependencies: ["Utility"], -/// cSettings: [ -/// .headerSearchPath("path/relative/to/my/target"), -/// .define("DISABLE_SOMETHING", .when(platforms: [.iOS], configuration: .release)), -/// ], -/// swiftSettings: [ -/// .define("ENABLE_SOMETHING", .when(configuration: .release)), -/// ], -/// linkerSettings: [ -/// .linkLibrary("openssl", .when(platforms: [.linux])), -/// ] -/// ), +/// ... +/// .target( +/// name: "MyTool", +/// dependencies: ["Utility"], +/// cSettings: [ +/// .headerSearchPath("path/relative/to/my/target"), +/// .define("DISABLE_SOMETHING", .when(platforms: [.iOS], configuration: .release)), +/// ], +/// swiftSettings: [ +/// .define("ENABLE_SOMETHING", .when(configuration: .release)), +/// ], +/// linkerSettings: [ +/// .linkLibrary("openssl", .when(platforms: [.linux])), +/// ] +/// ), public struct BuildSettingCondition: Encodable { private let platforms: [Platform]? @@ -63,8 +63,8 @@ public struct BuildSettingCondition: Encodable { /// At least one parameter is mandatory. /// /// - Parameters: - /// - platforms: The platforms for which this condition will be applied. - /// - configuration: The build configuration for which this condition will be applied. + /// - platforms: The applicable platforms for this build setting condition. + /// - configuration: The applicable build configuration for this build setting condition. public static func when( platforms: [Platform]? = nil, configuration: BuildConfiguration? = nil @@ -84,7 +84,7 @@ fileprivate struct BuildSettingData: Encodable { /// The value of the build setting. let value: [String] - /// A condition which will restrict when the build setting applies. + /// A condition that restricts the application of the build setting. let condition: BuildSettingCondition? } @@ -99,7 +99,7 @@ public struct CSetting: Encodable { /// Provide a header search path relative to the target's directory. /// /// Use this setting to add a search path for headers within your target. - /// Absolute paths are disallowed and this setting can't be used to provide + /// You can't use absolute paths and you can't use this setting to provide /// headers that are visible to other targets. /// /// The path must be a directory inside the package. @@ -107,21 +107,22 @@ public struct CSetting: Encodable { /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. - /// - condition: A condition which will restrict when the build setting applies. + /// - path: The path of the directory that contains the headers. The path is relative to the target's directory. + /// - condition: A condition that restricts the application of the build setting. public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CSetting { return CSetting(name: "headerSearchPath", value: [path], condition: condition) } - /// Defines a value for a macro. If no value is specified, the macro value will - /// be defined as 1. + /// Defines a value for a macro. + /// + /// If you don't specify a value, the macro's default value is 1. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: /// - name: The name of the macro. /// - value: The value of the macro. - /// - condition: A condition which will restrict when the build setting applies. + /// - condition: A condition that restricts the application of the build setting. public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CSetting { var settingValue = name if let value = value { @@ -133,19 +134,19 @@ public struct CSetting: Encodable { /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. /// /// As the usage of the word "unsafe" implies, the Swift Package Manager - /// can't safely determine if the build flags will have any negative - /// side-effect to the build since certain flags can change the behavior of + /// can't safely determine if the build flags have any negative + /// side effect on the build since certain flags can change the behavior of /// how a build is performed. /// - /// As some build flags could be exploited for unsupported or malicious + /// As some build flags can be exploited for unsupported or malicious /// behavior, the use of unsafe flags make the products containing this /// target ineligible to be used by other packages. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - flags: The flags to set. - /// - condition: A condition which will restrict when the build setting applies. + /// - flags: The unsafe flags to set. + /// - condition: A condition that restricts the application of the build setting. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CSetting { return CSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -159,10 +160,10 @@ public struct CXXSetting: Encodable { self.data = BuildSettingData(name: name, value: value, condition: condition) } - /// Provide a header search path relative to the target's root directory. + /// Provide a header search path relative to the target's directory. /// /// Use this setting to add a search path for headers within your target. - /// Absolute paths are disallowed and this setting can't be used to provide + /// You can't use absolute paths and you can't use this setting to provide /// headers that are visible to other targets. /// /// The path must be a directory inside the package. @@ -170,21 +171,22 @@ public struct CXXSetting: Encodable { /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - path: The path of the directory that should be searched for headers. The path is relative to the target's directory. - /// - condition: A condition which will restrict when the build setting applies. + /// - path: The path of the directory that contains the headers. The path is relative to the target's directory. + /// - condition: A condition that restricts the application of the build setting. public static func headerSearchPath(_ path: String, _ condition: BuildSettingCondition? = nil) -> CXXSetting { return CXXSetting(name: "headerSearchPath", value: [path], condition: condition) } - /// Defines a value for a macro. If no value is specified, the macro value will - /// be defined as 1. + /// Defines a value for a macro. + /// + /// If you don't specify a value, the macro's default value is 1. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: /// - name: The name of the macro. /// - value: The value of the macro. - /// - condition: A condition which will restrict when the build setting applies. + /// - condition: A condition that restricts the application of the build setting. public static func define(_ name: String, to value: String? = nil, _ condition: BuildSettingCondition? = nil) -> CXXSetting { var settingValue = name if let value = value { @@ -196,19 +198,18 @@ public struct CXXSetting: Encodable { /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. /// /// As the usage of the word "unsafe" implies, the Swift Package Manager - /// can't safely determine if the build flags will have any negative - /// side-effect to the build since certain flags can change the behavior of + /// can't safely determine if the build flags have any negative + /// side effect on the build since certain flags can change the behavior of /// how a build is performed. /// - /// As some build flags could be exploited for unsupported or malicious - /// behavior, the use of unsafe flags make the products containing this - /// target ineligible to be used by other packages. + /// As some build flags can be exploited for unsupported or malicious + /// behavior, a product can't be used as a dependency in another package if one of its targets uses unsafe flags. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - flags: The flags to set. - /// - condition: A condition which will restrict when the build setting applies. + /// - flags: The unsafe flags to set. + /// - condition: A condition that restricts the application of the build setting. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> CXXSetting { return CXXSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -224,13 +225,13 @@ public struct SwiftSetting: Encodable { /// Define a compilation condition. /// - /// Compilation conditons are used inside to conditionally compile - /// statements. For example, the Swift compiler will only compile the + /// Use compilation conditions to only compile statements if a certain condition is true. + /// For example, the Swift compiler will only compile the /// statements inside the `#if` block when `ENABLE_SOMETHING` is defined: /// - /// #if ENABLE_SOMETHING - /// ... - /// #endif + /// #if ENABLE_SOMETHING + /// ... + /// #endif /// /// Unlike macros in C/C++, compilation conditions don't have an /// associated value. @@ -239,7 +240,7 @@ public struct SwiftSetting: Encodable { /// /// - Parameters: /// - name: The name of the macro. - /// - condition: A condition which will restrict when the build setting applies. + /// - condition: A condition that restricts the application of the build setting. public static func define(_ name: String, _ condition: BuildSettingCondition? = nil) -> SwiftSetting { return SwiftSetting(name: "define", value: [name], condition: condition) } @@ -247,19 +248,18 @@ public struct SwiftSetting: Encodable { /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. /// /// As the usage of the word "unsafe" implies, the Swift Package Manager - /// can't safely determine if the build flags will have any negative - /// side-effect to the build since certain flags can change the behavior of + /// can't safely determine if the build flags have any negative + /// side effect on the build since certain flags can change the behavior of /// how a build is performed. /// - /// As some build flags could be exploited for unsupported or malicious - /// behavior, the use of unsafe flags make the products containing this - /// target ineligible to be used by other packages. + /// As some build flags can be exploited for unsupported or malicious + /// behavior, a product can't be used as a dependency in another package if one of its targets uses unsafe flags. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - flags: The flags to set. - /// - condition: A condition which will restrict when the build setting applies. + /// - flags: The unsafe flags to set. + /// - condition: A condition that restricts the application of the build setting.. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> SwiftSetting { return SwiftSetting(name: "unsafeFlags", value: flags, condition: condition) } @@ -276,14 +276,14 @@ public struct LinkerSetting: Encodable { /// Declare linkage to a system library. /// /// This setting is most useful when the library can't be linked - /// automatically (for example, C++ based libraries and non-modular - /// libraries). + /// automatically, such as C++ based libraries and non-modular + /// libraries. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: /// - library: The library name. - /// - condition: A condition which will restrict when the build setting applies. + /// - condition: A condition that restricts the application of the build setting. public static func linkedLibrary(_ library: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "linkedLibrary", value: [library], condition: condition) } @@ -291,14 +291,14 @@ public struct LinkerSetting: Encodable { /// Declare linkage to a framework. /// /// This setting is most useful when the framework can't be linked - /// automatically (for example, C++ based frameworks and non-modular - /// frameworks). + /// automatically, such as C++ based frameworks and non-modular + /// frameworks. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: /// - framework: The framework name. - /// - condition: A condition which will restrict when the build setting applies. + /// - condition: A condition that restricts the application of the build setting. public static func linkedFramework(_ framework: String, _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "linkedFramework", value: [framework], condition: condition) } @@ -306,19 +306,18 @@ public struct LinkerSetting: Encodable { /// Set unsafe flags to pass arbitrary command-line flags to the corresponding build tool. /// /// As the usage of the word "unsafe" implies, the Swift Package Manager - /// can't safely determine if the build flags will have any negative - /// side-effect to the build since certain flags can change the behavior of + /// can't safely determine if the build flags have any negative + /// side effect on the build since certain flags can change the behavior of /// how a build is performed. /// - /// As some build flags could be exploited for unsupported or malicious - /// behavior, the use of unsafe flags make the products containing this - /// target ineligible to be used by other packages. + /// As some build flags can be exploited for unsupported or malicious + /// behavior, a product can't be used as a dependency in another package if one of its targets uses unsafe flags. /// /// - Since: First available in PackageDescription 5.0 /// /// - Parameters: - /// - flags: The flags to set. - /// - condition: A condition which will restrict when the build setting applies. + /// - flags: The unsafe flags to set. + /// - condition: A condition that restricts the application of the build setting. public static func unsafeFlags(_ flags: [String], _ condition: BuildSettingCondition? = nil) -> LinkerSetting { return LinkerSetting(name: "unsafeFlags", value: flags, condition: condition) } diff --git a/Sources/PackageDescription4/LanguageStandardSettings.swift b/Sources/PackageDescription4/LanguageStandardSettings.swift index 2bf53dc024f..b32904bd949 100644 --- a/Sources/PackageDescription4/LanguageStandardSettings.swift +++ b/Sources/PackageDescription4/LanguageStandardSettings.swift @@ -8,7 +8,7 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// Support C language standards. +/// The supported C language standard to use for compiling C sources in the package. public enum CLanguageStandard: String, Encodable { case c89 case c90 @@ -24,7 +24,7 @@ public enum CLanguageStandard: String, Encodable { case gnu11 } -/// Supported C++ language standards. +/// The supported C++ language standards to use for compiling C++ sources in the package. public enum CXXLanguageStandard: String, Encodable { case cxx98 = "c++98" case cxx03 = "c++03" @@ -39,8 +39,7 @@ public enum CXXLanguageStandard: String, Encodable { } #if !PACKAGE_DESCRIPTION_4 -/// Represents the version of the Swift language that should be used for -/// compiling Swift sources in the package. +/// The version of the Swift language to use for compiling Swift sources in the package. public enum SwiftVersion { @available(_PackageDescription, introduced: 4, obsoleted: 5) case v3 @@ -54,13 +53,14 @@ public enum SwiftVersion { @available(_PackageDescription, introduced: 5) case v5 - /// User-defined value of Swift version. + /// A user-defined value for the Swift version. /// - /// The value is passed as-is to Swift compiler's `-swift-version` flag. + /// The value is passed as-is to the Swift compiler's `-swift-version` flag. case version(String) } extension SwiftVersion: Encodable { + public func encode(to encoder: Encoder) throws { let value: String diff --git a/Sources/PackageDescription4/Package.swift b/Sources/PackageDescription4/Package.swift index 76bae326531..51463e92860 100644 --- a/Sources/PackageDescription4/Package.swift +++ b/Sources/PackageDescription4/Package.swift @@ -17,19 +17,23 @@ import ucrt #endif import Foundation -/// The `Package` type is used to configure the name, products, targets, -/// dependencies and various other parts of the package. +/// The configuration of a Swift package. +/// +/// Pass configuration options as parameters to your package's initializer +/// statement to provide the name of the package, its targets, products, +/// dependencies, and other configuration options. /// /// By convention, the properties of a `Package` are defined in a single nested -/// initializer statement, and not modified after initialization. For example: +/// initializer statement, and not modified after initialization. The following package manifest shows the initialization +/// of a simple package object for the MyLibrary Swift package: /// -/// // swift-tools-version:5.0 -/// import PackageDesc ription +/// // swift-tools-version:5.1 +/// import PackageDescription /// /// let package = Package( /// name: "MyLibrary", /// platforms: [ -/// .macOS(.v10_14), +/// .macOS(.v10_15), /// ], /// products: [ /// .library(name: "MyLibrary", targets: ["MyLibrary"]), @@ -43,72 +47,81 @@ import Foundation /// ] /// ) /// -/// # About the Swift Tools Version -/// -/// A Package.swift manifest file must begin with the string `// -/// swift-tools-version:` followed by a version number specifier. -/// -/// Examples: +/// A `Package.swift` manifest file must begin with the string `// +/// swift-tools-version:` followed by a version number specifier. The following code listing shows a few examples of valid declarations of the Swift tools version: /// /// // swift-tools-version:3.0.2 /// // swift-tools-version:3.1 /// // swift-tools-version:4.0 /// // swift-tools-version:5.0 +/// // swift-tools-version:5.1 /// /// The Swift tools version declares the version of the `PackageDescription` /// library, the minimum version of the Swift tools and Swift language /// compatibility version to process the manifest, and the minimum version of the /// Swift tools that are needed to use the Swift package. Each version of Swift -/// can introduce updates to the `PackageDescription` library, but the previous +/// can introduce updates to the `PackageDescription` framework, but the previous /// API version will continue to be available to packages which declare a prior /// tools version. This behavior lets you take advantage of new releases of /// Swift, the Swift tools, and the `PackageDescription` library, without having /// to update your package's manifest or losing access to existing packages. public final class Package { + /// A package dependency of a Swift package. + /// /// A package dependency consists of a Git URL to the source of the package, - /// and a requirement for the version of the package that can be used. + /// and a requirement for the version of the package. /// - /// The Swift Package Manager performs a process called dependency resolution to - /// figure out the exact version of the package dependencies that can be used in - /// your package. The results of the dependency resolution are recorded in the - /// `Package.resolved` file which will be placed in the top-level directory of - /// your package. + /// The Swift Package Manager performs a process called *dependency resolution* to + /// figure out the exact version of the package dependencies that an app or other + /// Swift package can use. The `Package.resolved` file records the results of the + /// dependency resolution and lives in the top-level directory of a Swift package. + /// If you add the Swift package as a package dependency to an app for an Apple platform, + /// you can find the `Package.resolved` file inside your `.xcodeproj` or `.xcworkspace`. public class Dependency: Encodable { - /// The dependency requirement can be defined as one of three different version requirements. + /// An enum that represents the requirement for a package dependency. /// - /// 1. Version-based Requirement + /// The dependency requirement can be defined as one of three different version requirements: /// - /// A requirement which restricts what version of a dependency your - /// package can use based on its available versions. When a new package - /// version is published, it should increment the major version component - /// if it has backwards-incompatible changes. It should increment the - /// minor version component if it adds new functionality in - /// a backwards-compatible manner. And it should increment the patch - /// version if it makes backwards-compatible bugfixes. To learn more about - /// the syntax of semantic versioning syntax, see `Version` or visit - /// https://semver.org (https://semver.org/). + /// A version-based requirement /// - /// 2. Branch-based Requirement + /// Decide whether your project accepts updates to a package dependency up + /// to the next major version or up to the next minor version. To be more + /// restrictive, select a specific version range or an exact version. + /// Major versions tend to have more significant changes than minor + /// versions, and may require you to modify your code when they update. + /// The version rule requires Swift packages to conform to semantic + /// versioning. To learn more about the semantic versioning standard, + /// visit [semver.org](https://semver.org). /// - /// Specify the name of a branch that a dependency will follow. This is - /// useful when developing multiple packages which are closely related, - /// allowing you to keep them in sync during development. Note that - /// packages which use branch-based dependency requirements cannot be - /// depended-upon by packages which use version-based dependency + /// Selecting the version requirement is the recommended way to add a package dependency. It allows you to create a balance between restricting changes and obtaining improvements and features. + /// + /// A branch-based requirement + /// + /// Select the name of the branch for your package dependency to follow. + /// Use branch-based dependencies when you're developing multiple packages + /// in tandem or when you don't want to publish versions of your package dependencies. + /// + /// Note that packages which use branch-based dependency requirements + /// can't be added as dependencies to packages that use version-based dependency /// requirements; you should remove branch-based dependency requirements /// before publishing a version of your package. /// - /// 3. Commit-based Requirement + /// A commit-based requirement + /// + /// Select the commit hash for your package dependency to follow. + /// Choosing this option isn't recommended, and should be limited to + /// exceptional cases. While pinning your package dependency to a specific + /// commit ensures that the package dependency doesn't change and your + /// code remains stable, you don't receive any updates at all. If you worry about + /// the stability of a remote package, consider one of the more + /// restrictive options of the version-based requirement. /// - /// A requirement that restricts a dependency to a specific commit - /// hash. This is useful if you want to pin your package to a specific - /// commit hash of a dependency. Note that packages which use - /// commit-based dependency requirements cannot be depended-upon by - /// packages which use version-based dependency requirements; you - /// should remove commit-based dependency requirements before - /// publishing a version of your package. + /// Note that packages which use commit-based dependency requirements + /// can't be added as dependencies to packages that use version-based + /// dependency requirements; you should remove commit-based dependency + /// requirements before publishing a version of your package. public enum Requirement { #if PACKAGE_DESCRIPTION_4 case exactItem(Version) @@ -134,24 +147,24 @@ public final class Package { } } - /// The url of the dependency. + /// The Git url of the package dependency. public let url: String - /// The dependency requirement. + /// The dependency requirement of the package dependency. public let requirement: Requirement - /// Create a dependency. + /// Initializes and returns a newly allocated requirement with the specified url and requirements. init(url: String, requirement: Requirement) { self.url = url self.requirement = requirement } } - /// The name of the package. + /// The name of the Swift package. public var name: String #if !PACKAGE_DESCRIPTION_4 - /// The list of platforms supported by this package. + /// The list of supported platforms with a custom deployment target. @available(_PackageDescription, introduced: 5) public var platforms: [SupportedPlatform]? { get { return _platforms } @@ -160,28 +173,29 @@ public final class Package { #endif private var _platforms: [SupportedPlatform]? - /// pkgconfig name to use for C Modules. If present, swiftpm will try to - /// search for .pc file to get the additional flags needed for the - /// system target. + /// The name to use for C Modules. + /// + /// If present, the Swift Package Manager searches for a `.pc` file + /// to get the required additional flags for a system target. public var pkgConfig: String? - /// Providers array for System target + /// An array of providers for the system target. public var providers: [SystemPackageProvider]? /// The list of targets. public var targets: [Target] - /// The list of products vended by this package. + /// The list of products that this package vends and that can be run or used by its clients. public var products: [Product] - /// The list of dependencies. + /// The list of package dependencies. public var dependencies: [Dependency] #if PACKAGE_DESCRIPTION_4 - /// The list of swift versions, this package is compatible with. + /// The list of Swift versions that this package is compatible with. public var swiftLanguageVersions: [Int]? #else - /// The list of swift versions, this package is compatible with. + /// The list of Swift versions that this package is compatible with. public var swiftLanguageVersions: [SwiftVersion]? #endif @@ -192,7 +206,18 @@ public final class Package { public var cxxLanguageStandard: CXXLanguageStandard? #if PACKAGE_DESCRIPTION_4 - /// Construct a package. + /// Initializes and returns a newly allocated package object with the provided configuration options. + /// + /// - Parameters: + /// - name: The name of the Swift package. + /// - pkgConfig: Additional flags for a system package. + /// - providers: The package providers for a system package. + /// - products: The list of products that this package vends and that can be run or used by its clients. + /// - dependencies: The list of package dependencies. + /// - targets: The list of targets that are part of this package. + /// - swiftLanguageVersions: The list of Swift versions that this package is compatible with. + /// - cLanguageStandard: The C language standard to use for all C targets in this package. + /// - cxxLanguageStandard: The C++ language standard to use for all C++ targets in this package. public init( name: String, pkgConfig: String? = nil, @@ -216,6 +241,16 @@ public final class Package { registerExitHandler() } #else + /// Initializes and returns a newly allocated package object with the provided configuration options. + /// + /// - Parameters: + /// - name: The name of the Swift package. + /// - products: The list of products that this package vends and that can be run or used by its clients. + /// - dependencies: The list of package dependencies. + /// - targets: The list of targets that are part of this package. + /// - swiftLanguageVersions: The list of Swift versions that this package is compatible with. + /// - cLanguageStandard: The C language standard to use for all C targets in this package. + /// - cxxLanguageStandard: The C++ language standard to use for all C++ targets in this package. @available(_PackageDescription, introduced: 4.2, obsoleted: 5) public init( name: String, @@ -240,7 +275,17 @@ public final class Package { registerExitHandler() } - /// Construct a package. + /// Initializes and returns a newly allocated package object with the specified parameters + /// + /// - Parameters: + /// - name: The name of the Swift package. + /// - platforms: The list of minimum deployment targets per platform. + /// - products: The list of products that this package vends and that can be run or used by its clients. + /// - dependencies: The list of package dependencies. + /// - targets: The list of targets that are part of this package. + /// - swiftLanguageVersions: The list of Swift versions that this package is compatible with. + /// - cLanguageStandard: The C language standard to use for all C targets in this package. + /// - cxxLanguageStandard: The C++ language standard to use for all C++ targets in this package. @available(_PackageDescription, introduced: 5) public init( name: String, @@ -269,7 +314,7 @@ public final class Package { #endif private func registerExitHandler() { - // Add custom exit handler to cause package to be dumped at exit, if + // Add a custom exit handler to cause the package to be dumped at exit, if // requested. // // FIXME: This doesn't belong here, but for now is the mechanism we use @@ -283,7 +328,7 @@ public final class Package { } } -/// Represents system package providers. +/// The system package providers used in this Swift package. public enum SystemPackageProvider { #if PACKAGE_DESCRIPTION_4 @@ -294,8 +339,11 @@ public enum SystemPackageProvider { case _aptItem([String]) #endif - /// Declare the list of packages installable using the homebrew package - /// manager on macOS. + /// Declare the list of installable packages using the homebrew package + /// manager on macOS to create a system package provider instance. + /// + /// - Parameters: + /// - packages: The list of package names. public static func brew(_ packages: [String]) -> SystemPackageProvider { #if PACKAGE_DESCRIPTION_4 return .brewItem(packages) @@ -304,8 +352,11 @@ public enum SystemPackageProvider { #endif } - /// Declare the list of packages installable using the apt-get package - /// manager on Ubuntu. + /// Declare the list of installable packages using the apt-get package + /// manager on Ubuntu to create a system package provider instance. + /// + /// - Parameters: + /// - packages: The list of package names. public static func apt(_ packages: [String]) -> SystemPackageProvider { #if PACKAGE_DESCRIPTION_4 return .aptItem(packages) diff --git a/Sources/PackageDescription4/PackageDependency.swift b/Sources/PackageDescription4/PackageDependency.swift index d854309663d..9138068f20a 100644 --- a/Sources/PackageDescription4/PackageDependency.swift +++ b/Sources/PackageDescription4/PackageDependency.swift @@ -10,22 +10,21 @@ extension Package.Dependency { - /// Add a package dependency that is required from the given minimum version, + /// Create a package dependency that uses the version requirement, starting with the given minimum version, /// going up to the next major version. /// - /// This is the recommend way to specify a remote package dependency because - /// it allows you to specify the minimum version you require and gives - /// explicit opt-in for new major versions, but otherwise provides maximal - /// flexibility on which version is used. This helps to prevent conflicts in - /// your package dependency graph. + /// This is the recommended way to specify a remote package dependency. + /// It allows you to specify the minimum version you require, allows updates that include bug fixes + /// and backward-compatible feature updates, but requires you to explicitly update to a new major version of the dependency. + /// This approach provides the maximum flexibility on which version to use, + /// while making sure you don't update to a version with breaking changes, + /// and helps to prevent conflicts in your dependency graph. /// - /// For example, specifying + /// The following example allows the Swift package manager to select a version + /// like a `1.2.3`, `1.2.4`, or `1.3.0`, but not `2.0.0`. /// /// .package(url: "https://example.com/example-package.git", from: "1.2.3"), /// - /// will allow the Swift package manager to select a version like a "1.2.3", - /// "1.2.4" or "1.3.0" but not "2.0.0". - /// /// - Parameters: /// - url: The valid Git URL of the package. /// - version: The minimum version requirement. @@ -50,14 +49,13 @@ extension Package.Dependency { } /// Add a package dependency starting with a specific minimum version, up to - /// but not including a specific maximum version. + /// but not including a specified maximum version. /// - /// For example + /// The following example allows the Swift package manager to pick + /// versions `1.2.3`, `1.2.4`, `1.2.5`, but not `1.2.6`. /// /// .package(url: "https://example.com/example-package.git", "1.2.3"..<"1.2.6"), /// - /// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, but not 1.2.6. - /// /// - Parameters: /// - url: The valid Git URL of the package. /// - range: The custom version range requirement. @@ -75,12 +73,11 @@ extension Package.Dependency { /// Add a package dependency starting with a specific minimum version, going /// up to and including a specific maximum version. /// - /// For example + /// The following example allows the Swift package manager to pick + /// versions 1.2.3, 1.2.4, 1.2.5, as well as 1.2.6. /// /// .package(url: "https://example.com/example-package.git", "1.2.3"..."1.2.6"), /// - /// will allow the Swift package manager to pick versions 1.2.3, 1.2.4, 1.2.5, as well as 1.2.6. - /// /// - Parameters: /// - url: The valid Git URL of the package. /// - range: The closed version range requirement. @@ -100,10 +97,10 @@ extension Package.Dependency { #if !PACKAGE_DESCRIPTION_4 /// Add a dependency to a local package on the filesystem. /// - /// The package dependency is used as-is and no source control access is - /// performed. Local package dependencies are especially useful during - /// development of a new package or when working on multiple tightly-coupled - /// packages. + /// The Swift Package Manager uses the package dependency as-is + /// and does not perform any source control access. Local package dependencies + /// are especially useful during development of a new package or when working + /// on multiple tightly coupled packages. /// /// - Parameter path: The path of the package. public static func package( diff --git a/Sources/PackageDescription4/PackageRequirement.swift b/Sources/PackageDescription4/PackageRequirement.swift index 1e96a29a2c9..b6f22024388 100644 --- a/Sources/PackageDescription4/PackageRequirement.swift +++ b/Sources/PackageDescription4/PackageRequirement.swift @@ -12,16 +12,17 @@ extension Package.Dependency.Requirement: Encodable { /// Returns a requirement for the given exact version. /// - /// Specifying exact version requirements are usually not recommended, as - /// they can cause conflicts in your package dependency graph when a package - /// is depended on by multiple other packages. + /// Specifying exact version requirements are not recommended as + /// they can cause conflicts in your dependency graph when multiple other packages depend on a package. + /// As Swift packages follow the semantic versioning convention, + /// think about specifying a version range instead. /// - /// Example: + /// The following example defines a version requirement that requires version 1.2.3 of a package. /// /// .exact("1.2.3") /// /// - Parameters: - /// - version: The exact version to be specified. + /// - version: The exact version of the dependency for this requirement. public static func exact(_ version: Version) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .exactItem(version) @@ -30,20 +31,19 @@ extension Package.Dependency.Requirement: Encodable { #endif } - /// Returns a requirement for a source control revision. This is usually - /// specified with the hash of a commit. + /// Returns a requirement for a source control revision such as the hash of a commit. /// - /// Note that packages which use commit-based dependency requirements - /// cannot be depended-upon by packages which use version-based dependency + /// Note that packages that use commit-based dependency requirements + /// can't be depended upon by packages that use version-based dependency /// requirements; you should remove commit-based dependency requirements /// before publishing a version of your package. /// - /// Example: + /// The following example defines a version requirement for a specific commit hash. /// /// .revision("e74b07278b926c9ec6f9643455ea00d1ce04a021") /// /// - Parameters: - /// - ref: The Git revision, usually a hash of the commit. + /// - ref: The Git revision, usually a commit hash. public static func revision(_ ref: String) -> Package.Dependency.Requirement { #if PACKAGE_DESCRIPTION_4 return .revisionItem(ref) @@ -54,12 +54,13 @@ extension Package.Dependency.Requirement: Encodable { /// Returns a requirement for a source control branch. /// - /// Note that packages which use branch-based dependency requirements - /// cannot be depended-upon by packages which use version-based dependency + /// Note that packages that use branch-based dependency requirements + /// can't be depended upon by packages that use version-based dependency /// requirements; you should remove branch-based dependency requirements /// before publishing a version of your package. /// - /// Example: + /// The following example defines a version requirement that accepts any + /// change in the develop branch. /// /// .branch("develop") /// @@ -74,7 +75,7 @@ extension Package.Dependency.Requirement: Encodable { } /// Returns a requirement for a version range, starting at the given minimum - /// version and going up to the next major version. + /// version and going up to the next major version. This is the recommended version requirement. /// /// - Parameters: /// - version: The minimum version for the version range. diff --git a/Sources/PackageDescription4/Product.swift b/Sources/PackageDescription4/Product.swift index c1d35d3d783..d40d8ed01f5 100644 --- a/Sources/PackageDescription4/Product.swift +++ b/Sources/PackageDescription4/Product.swift @@ -8,23 +8,23 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// Defines a package product. +/// The object that defines a package product. /// -/// A package product defines an externally visible build artifact that is +/// A package product defines an externally visible build artifact that's /// available to clients of a package. The product is assembled from the build /// artifacts of one or more of the package's targets. /// /// A package product can be one of two types: /// -/// 1. Library +/// Library /// -/// A library product is used to vend library targets containing the public -/// APIs that will be available to clients. +/// Use a library product to vend library targets. This makes a target's public APIs +/// available to clients that integrate the Swift package. /// -/// 2. Executable +/// Executable /// -/// An executable product is used to vend an executable target. This should -/// only be used if the executable needs to be made available to clients. +/// Use an executable product to vend an executable target. +/// Use this only if you want to make the executable available to clients. /// /// The following example shows a package manifest for a library called "Paper" /// that defines multiple products: @@ -63,14 +63,14 @@ public class Product: Encodable { case type = "product_type" } - /// The name of the product. + /// The name of the package product. public let name: String init(name: String) { self.name = name } - /// Represents an executable product. + /// The executable product of a Swift package. public final class Executable: Product { private enum ExecutableCodingKeys: CodingKey { case targets @@ -93,14 +93,14 @@ public class Product: Encodable { } } - /// Represents a library product. + /// The library product of a Swift package. public final class Library: Product { private enum LibraryCodingKeys: CodingKey { case type case targets } - /// The type of library product. + /// The different types of a library product. public enum LibraryType: String, Encodable { case `static` case `dynamic` @@ -111,7 +111,8 @@ public class Product: Encodable { /// The type of the library. /// - /// If the type is unspecified, package manager will automatically choose a type. + /// If the type is unspecified, the Swift Package Manager automatically + /// chooses a type based on the client's preference. public let type: LibraryType? init(name: String, type: LibraryType? = nil, targets: [String]) { @@ -130,12 +131,13 @@ public class Product: Encodable { } } - /// Create a library product that can be used by clients that depend on this package. + /// Create a library product to allow clients that declare a dependency on this package + /// to use the package's functionality. /// - /// A library's product can either be statically or dynamically linked. It - /// is recommended to not declare the type of library explicitly to let the - /// Swift Package Manager choose between static or dynamic linking depending - /// on the consumer of the package. + /// A library's product can either be statically or dynamically linked. + /// If possible, don't declare the type of library explicitly to let + /// the Swift Package Manager choose between static or dynamic linking based + /// on the preference of the package's consumer. /// /// - Parameters: /// - name: The name of the library product. @@ -151,11 +153,11 @@ public class Product: Encodable { return Library(name: name, type: type, targets: targets) } - /// Create an executable product. + /// Create an executable package product that clients can run. /// /// - Parameters: /// - name: The name of the executable product. - /// - targets: The targets that are bundled into an executable product. + /// - targets: The targets to bundle into an executable product. public static func executable( name: String, targets: [String] diff --git a/Sources/PackageDescription4/SupportedPlatforms.swift b/Sources/PackageDescription4/SupportedPlatforms.swift index 8124b3a86a4..9e8398ddd5e 100644 --- a/Sources/PackageDescription4/SupportedPlatforms.swift +++ b/Sources/PackageDescription4/SupportedPlatforms.swift @@ -8,8 +8,8 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// Represents a platform that usually corresponds to an operating system such as -/// macOS or Linux. +/// A platform that usually corresponds to an operating system such as +/// iOS, macOS, or Linux. public struct Platform: Encodable { /// The name of the platform. @@ -19,6 +19,7 @@ public struct Platform: Encodable { self.name = name } + /// FIXME: add documentation public static let macOS: Platform = Platform(name: "macos") public static let iOS: Platform = Platform(name: "ios") public static let tvOS: Platform = Platform(name: "tvos") @@ -26,22 +27,22 @@ public struct Platform: Encodable { public static let linux: Platform = Platform(name: "linux") } -/// Represents a platform supported by the package. +/// A platform that the Swift package supports. /// /// By default, the Swift Package Manager assigns a predefined minimum deployment -/// version for each supported platforms unless configured using the `platforms` -/// API. This predefined deployment version will be the oldest deployment target -/// version supported by the installed SDK for a given platform. One exception -/// to this rule is macOS, for which the minimum deployment target version will -/// start from 10.10. Packages can choose to configure the minimum deployment +/// version for each supported platforms unless you configure supported platforms using the `platforms` +/// API. This predefined deployment version is the oldest deployment target +/// version that the installed SDK supports for a given platform. One exception +/// to this rule is macOS, for which the minimum deployment target version +/// starts from 10.10. Packages can choose to configure the minimum deployment /// target version for a platform by using the APIs defined in this struct. The -/// Swift Package Manager will emit appropriate errors when an invalid value is -/// provided for supported platforms, i.e., an empty array, multiple declarations -/// for the same platform or an invalid version specification. +/// Swift Package Manager emits appropriate errors when an invalid value is +/// provided for supported platforms, such as an empty array, multiple declarations +/// for the same platform, or an invalid version specification. /// /// The Swift Package Manager will emit an error if a dependency is not -/// compatible with the top-level package's deployment version; the deployment -/// target of dependencies must be lower than or equal to top-level package's +/// compatible with the top-level package's deployment version. The deployment +/// target of a package's dependencies must be lower than or equal to the top-level package's /// deployment target version for a particular platform. public struct SupportedPlatform: Encodable { @@ -67,14 +68,13 @@ public struct SupportedPlatform: Encodable { } /// Configure the minimum deployment target version for the macOS platform - /// using a custom version string. + /// using a version string. /// - /// The version string must be a series of 2 or 3 dot-separated integers, for - /// example "10.10" or "10.10.1". + /// The version string must be a series of two or three dot-separated integers, such as "10.10" or "10.10.1". /// /// - Since: First available in PackageDescription 5.0 /// - /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "10.10.1". + /// - Parameter versionString: The minimum deployment target as a string representation of two or three dot-separated integers, such as "10.10.1". public static func macOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .macOS, version: SupportedPlatform.MacOSVersion(string: versionString).version) } @@ -91,12 +91,11 @@ public struct SupportedPlatform: Encodable { /// Configure the minimum deployment target version for the iOS platform /// using a custom version string. /// - /// The version string must be a series of 2 or 3 dot-separated integers, for - /// example "8.0" or "8.0.1". + /// The version string must be a series of two or three dot-separated integers, such as "8.0" or "8.0.1". /// /// - Since: First available in PackageDescription 5.0 /// - /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "8.0.1". + /// - Parameter versionString: The minimum deployment target as a string representation of two or three dot-separated integers, such as "8.0.1". public static func iOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .iOS, version: SupportedPlatform.IOSVersion(string: versionString).version) } @@ -113,12 +112,11 @@ public struct SupportedPlatform: Encodable { /// Configure the minimum deployment target version for the tvOS platform /// using a custom version string. /// - /// The version string must be a series of 2 or 3 dot-separated integers, for - /// example "9.0" or "9.0.1". + /// The version string must be a series of two or three dot-separated integers,such as "9.0" or "9.0.1". /// /// - Since: First available in PackageDescription 5.0 /// - /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "9.0.1". + /// - Parameter versionString: The minimum deployment target as a string representation of two or three dot-separated integers, such as "9.0.1". public static func tvOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .tvOS, version: SupportedPlatform.TVOSVersion(string: versionString).version) } @@ -135,18 +133,17 @@ public struct SupportedPlatform: Encodable { /// Configure the minimum deployment target version for the watchOS platform /// using a custom version string. /// - /// The version string must be a series of 2 or 3 dot-separated integers, for - /// example "2.0" or "2.0.1". + /// The version string must be a series of two or three dot-separated integers, such as "2.0" or "2.0.1". /// /// - Since: First available in PackageDescription 5.0 /// - /// - Parameter versionString: The minimum deployment target as a string representation of 2 or 3 dot-separated integers, e.g. "3.0.1". + /// - Parameter versionString: The minimum deployment target as a string representation of two or three dot-separated integers, such as "2.0.1". public static func watchOS(_ versionString: String) -> SupportedPlatform { return SupportedPlatform(platform: .watchOS, version: SupportedPlatform.WatchOSVersion(string: versionString).version) } } -/// Extension to SupportedPlaftorm to define major platform versions. +/// An extension to the SupportedPlatform struct that defines major platform versions. extension SupportedPlatform { /// The macOS version. public struct MacOSVersion: Encodable, AppleOSVersion { @@ -160,32 +157,32 @@ extension SupportedPlatform { self.version = version } - /// macOS 10.10 + /// The value that represents macOS 10.10. /// /// - Since: First available in PackageDescription 5.0 public static let v10_10: MacOSVersion = .init(string: "10.10") - /// macOS 10.11 + /// The value that represents macOS 10.11. /// /// - Since: First available in PackageDescription 5.0 public static let v10_11: MacOSVersion = .init(string: "10.11") - /// macOS 10.12 + /// The value that represents macOS 10.12. /// /// - Since: First available in PackageDescription 5.0 public static let v10_12: MacOSVersion = .init(string: "10.12") - /// macOS 10.13 + /// The value that represents macOS 10.13. /// /// - Since: First available in PackageDescription 5.0 public static let v10_13: MacOSVersion = .init(string: "10.13") - /// macOS 10.14 + /// The value that represents macOS 10.14. /// /// - Since: First available in PackageDescription 5.0 public static let v10_14: MacOSVersion = .init(string: "10.14") - /// macOS 10.15 + /// The value that represents macOS 10.15. /// /// - Since: First available in PackageDescription 5.1 @available(_PackageDescription, introduced: 5.1) @@ -203,27 +200,27 @@ extension SupportedPlatform { self.version = version } - /// tvOS 9.0 + /// The value that represents tvOS 9.0. /// /// - Since: First available in PackageDescription 5.0 public static let v9: TVOSVersion = .init(string: "9.0") - /// tvOS 10.0 + /// The value that represents tvOS 10.0. /// /// - Since: First available in PackageDescription 5.0 public static let v10: TVOSVersion = .init(string: "10.0") - /// tvOS 11.0 + /// The value that represents tvOS 11.0. /// /// - Since: First available in PackageDescription 5.0 public static let v11: TVOSVersion = .init(string: "11.0") - /// tvOS 12.0 + /// The value that represents tvOS 12.0. /// /// - Since: First available in PackageDescription 5.0 public static let v12: TVOSVersion = .init(string: "12.0") - /// tvOS 13.0 + /// The value that represents tvOS 13.0. /// /// - Since: First available in PackageDescription 5.1 @available(_PackageDescription, introduced: 5.1) @@ -241,32 +238,32 @@ extension SupportedPlatform { self.version = version } - /// iOS 8.0 + /// The value that represents iOS 8.0. /// /// - Since: First available in PackageDescription 5.0 public static let v8: IOSVersion = .init(string: "8.0") - /// iOS 9.0 + /// The value that represents iOS 9.0. /// /// - Since: First available in PackageDescription 5.0 public static let v9: IOSVersion = .init(string: "9.0") - /// iOS 10.0 + /// The value that represents iOS 10.0. /// /// - Since: First available in PackageDescription 5.0 public static let v10: IOSVersion = .init(string: "10.0") - /// iOS 11.0 + /// The value that represents iOS 11.0. /// /// - Since: First available in PackageDescription 5.0 public static let v11: IOSVersion = .init(string: "11.0") - /// iOS 12.0 + /// The value that represents iOS 12.0. /// /// - Since: First available in PackageDescription 5.0 public static let v12: IOSVersion = .init(string: "12.0") - /// iOS 13.0 + /// The value that represents iOS 13.0. /// /// - Since: First available in PackageDescription 5.1 @available(_PackageDescription, introduced: 5.1) @@ -284,27 +281,27 @@ extension SupportedPlatform { self.version = version } - /// watchOS 2.0 + /// The value that represents watchOS 2.0. /// /// - Since: First available in PackageDescription 5.0 public static let v2: WatchOSVersion = .init(string: "2.0") - /// watchOS 3.0 + /// The value that represents watchOS 3.0. /// /// - Since: First available in PackageDescription 5.0 public static let v3: WatchOSVersion = .init(string: "3.0") - /// watchOS 4.0 + /// The value that represents watchOS 4.0. /// /// - Since: First available in PackageDescription 5.0 public static let v4: WatchOSVersion = .init(string: "4.0") - /// watchOS 5.0 + /// The value that represents watchOS 5.0. /// /// - Since: First available in PackageDescription 5.0 public static let v5: WatchOSVersion = .init(string: "5.0") - /// watchOS 6.0 + /// The value that represents watchOS 6.0. /// /// - Since: First available in PackageDescription 5.1 @available(_PackageDescription, introduced: 5.1) diff --git a/Sources/PackageDescription4/Target.swift b/Sources/PackageDescription4/Target.swift index f60df6d235e..297c0e13215 100644 --- a/Sources/PackageDescription4/Target.swift +++ b/Sources/PackageDescription4/Target.swift @@ -8,24 +8,22 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// Targets are the basic building blocks of a package. +/// A target, the basic building block of a Swift package. /// -/// Each target contains a set of source files that are compiled into a module or -/// test suite. Targets can be vended to other packages by defining products that -/// include them. +/// Each target contains a set of source files that are compiled into a module or test suite. +/// You can vend targets to other packages by defining products that include the targets. /// -/// Targets may depend on targets within the same package and on products vended -/// by its package dependencies. +/// A target may depend on other targets within the same package and on products vended by the package's dependencies. public final class Target { - /// The type of this target. + /// The different types of a target. public enum TargetType: String, Encodable { case regular case test case system } - /// Represents a target's dependency on another entity. + /// The different types of a target's dependency on another entity. public enum Dependency { #if PACKAGE_DESCRIPTION_4 case targetItem(name: String) @@ -43,54 +41,59 @@ public final class Target { /// The path of the target, relative to the package root. /// - /// If nil, a directory with the target's name will be searched in the - /// predefined search paths. The predefined search paths are the following - /// directories under the package root: - /// - for regular targets: Sources, Source, src, srcs - /// - for test targets: Tests, Sources, Source, src, srcs + /// If the path is `nil`, the Swift Package Manager looks for a targets source files at predefined search paths + /// and in a subdirectory with the target's name. + /// + /// The predefined search paths are the following directories under the package root: + /// - For regular targets: `Sources`, `Source`, `src`, and `srcs` + /// - For test targets: `Tests`, `Sources`, `Source`, `src`, `srcs` + /// + /// For example, the Swift Package Manager will look for source files inside the `[PackageRoot]/Sources/[TargetName]` directory. + /// + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid. public var path: String? /// The source files in this target. /// - /// If nil, all valid source files found in the target's path will be included. - /// - /// This can contain directories and individual source files. Directories - /// will be searched recursively for valid source files. + /// If this property is `nil`, all valid source files in the target's path will be included and specified paths are relative to the target path. /// - /// Paths specified are relative to the target path. + /// A path can be a path to a directory or an individual source file. In case of a directory, the Swift Package Manager searches for valid source files + /// recursively inside it. public var sources: [String]? - /// List of paths to be excluded from source inference. + /// The paths you want to exclude from source inference. /// - /// Exclude paths are relative to the target path. - /// This property has more precedence than sources property. + /// Excluded paths are relative to the target path. + /// This property has precedence over the `sources` property. public var exclude: [String] - /// If this is a test target. + /// A boolean value that indicates if this is a test target. public var isTest: Bool { return type == .test } - /// Dependencies on other entities inside or outside the package. + /// The target's dependencies on other entities inside or outside the package. public var dependencies: [Dependency] - /// The path to the directory containing public headers of a C language target. + /// The path to the directory containing public headers of a C-family target. /// - /// If a value is not provided, the directory will be set to "include". + /// If this is `nil`, the directory will be set to `include`. public var publicHeadersPath: String? - /// The type of target. + /// The type of the target. public let type: TargetType - /// `pkgconfig` name to use for system library target. If present, swiftpm will try to - /// search for .pc file to get the additional flags needed for the + /// The `pkgconfig` name to use for a system library target. + /// + /// If present, the Swift Package Manager tries to + /// search for the `.pc` file to get the additional flags needed for the /// system target. public let pkgConfig: String? - /// Providers array for the System library target. + /// The providers array for a system library target. public let providers: [SystemPackageProvider]? - /// C build settings. + /// The target's C build settings. @available(_PackageDescription, introduced: 5) public var cSettings: [CSetting]? { get { return _cSettings } @@ -98,7 +101,7 @@ public final class Target { } private var _cSettings: [CSetting]? - /// C++ build settings. + /// The target's C++ build settings. @available(_PackageDescription, introduced: 5) public var cxxSettings: [CXXSetting]? { get { return _cxxSettings } @@ -106,7 +109,7 @@ public final class Target { } private var _cxxSettings: [CXXSetting]? - /// Swift build settings. + /// The target's Swift build settings. @available(_PackageDescription, introduced: 5) public var swiftSettings: [SwiftSetting]? { get { return _swiftSettings } @@ -114,7 +117,7 @@ public final class Target { } private var _swiftSettings: [SwiftSetting]? - /// Linker build settings. + /// The target's linker settings. @available(_PackageDescription, introduced: 5) public var linkerSettings: [LinkerSetting]? { get { return _linkerSettings } @@ -161,20 +164,23 @@ public final class Target { /// Create a library or executable target. /// - /// A target can either contain Swift or C-family source files. You cannot + /// A target can either contain Swift or C-family source files and you can't /// mix Swift and C-family source files within a target. A target is /// considered to be an executable target if there is a `main.swift`, - /// `main.m`, `main.c` or `main.cpp` file in the target's directory. All + /// `main.m`, `main.c`, or `main.cpp` file in the target's directory. All /// other targets are considered to be library targets. /// /// - Parameters: /// - name: The name of the target. - /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from package dependencies. - /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. - /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. - /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. - /// - sources: An explicit list of source files. - /// - publicHeadersPath: The directory containing public headers of a C-family family library target. + /// - dependencies: The dependencies of the target. A dependency can be another target in the package or a product from a package dependency. + /// - path: The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, + /// such as `[PackageRoot]/Sources/[TargetName]`. + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid. + /// - exclude: A list of paths to files or directories that should not be considered source files. This path is relative to the target's directory. + /// This parameter has precedence over the `sources` parameter. + /// - sources: An explicit list of source files. In case of a directory, the Swift Package Manager searches for valid source files + /// recursively. + /// - publicHeadersPath: The path to the directory containing public headers of a C-family target. @available(_PackageDescription, introduced: 4, obsoleted: 5) public static func target( name: String, @@ -197,19 +203,22 @@ public final class Target { /// Create a library or executable target. /// - /// A target can either contain Swift or C-family source files. You cannot + /// A target can either contain Swift or C-family source files. You can't /// mix Swift and C-family source files within a target. A target is /// considered to be an executable target if there is a `main.swift`, - /// `main.m`, `main.c` or `main.cpp` file in the target's directory. All + /// `main.m`, `main.c`, or `main.cpp` file in the target's directory. All /// other targets are considered to be library targets. /// /// - Parameters: /// - name: The name of the target. - /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from package dependencies. - /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. - /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. - /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. - /// - sources: An explicit list of source files. + /// - dependencies: The dependencies of the target. A dependency can be another target in the package or a product from a package dependency. + /// - path: The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, + /// such as `[PackageRoot]/Sources/[TargetName]`. + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid.. + /// - exclude: A list of paths to files or directories that should not be considered source files. This path is relative to the target's directory. + /// This parameter has precedence over the `sources` parameter. + /// - sources: An explicit list of source files. In case of a directory, the Swift Package Manager searches for valid source files + /// recursively. /// - publicHeadersPath: The directory containing public headers of a C-family family library target. /// - cSettings: The C settings for this target. /// - cxxSettings: The C++ settings for this target. @@ -245,16 +254,19 @@ public final class Target { /// Create a test target. /// - /// Test targets are written using the XCTest testing framework. Test targets - /// generally declare target dependency on the targets they test. + /// Write test targets using the XCTest testing framework. + /// Test targets generally declare a dependency on the targets they test. /// /// - Parameters: /// - name: The name of the target. - /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from other packages. - /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. - /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. - /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. - /// - sources: An explicit list of source files. + /// - dependencies: The dependencies of the target. A dependency can be another target in the package or a product from a package dependency. + /// - path: The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, + /// such as `[PackageRoot]/Sources/[TargetName]`. + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid. + /// - exclude: A list of paths to files or directories that should not be considered source files. This path is relative to the target's directory. + /// This parameter has precedence over the `sources` parameter. + /// - sources: An explicit list of source files. In case of a directory, the Swift Package Manager searches for valid source files + /// recursively. @available(_PackageDescription, introduced: 4, obsoleted: 5) public static func testTarget( name: String, @@ -276,16 +288,19 @@ public final class Target { /// Create a test target. /// - /// Test targets are written using the XCTest testing framework. Test targets - /// generally declare target dependency on the targets they test. + /// Write test targets using the XCTest testing framework. + /// Test targets generally declare a dependency on the targets they test. /// /// - Parameters: /// - name: The name of the target. - /// - dependencies: The dependencies of the target. These can either be other targets in the package or products from other packages. - /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. - /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. - /// - exclude: A list of paths to exclude from being considered source files. This path is relative to the target's directory. - /// - sources: An explicit list of source files. + /// - dependencies: The dependencies of the target. A dependency can be another target in the package or a product from a package dependency. + /// - path: The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, + /// such as `[PackageRoot]/Sources/[TargetName]`. + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid. + /// - exclude: A list of paths to files or directories that should not be considered source files. This path is relative to the target's directory. + /// This parameter has precedence over the `sources` parameter. + /// - sources: An explicit list of source files. In case of a directory, the Swift Package Manager searches for valid source files + /// recursively. /// - cSettings: The C settings for this target. /// - cxxSettings: The C++ settings for this target. /// - swiftSettings: The Swift settings for this target. @@ -320,18 +335,17 @@ public final class Target { #if !PACKAGE_DESCRIPTION_4 /// Create a system library target. - /// - /// System library targets are used to adapt a library installed on the system to - /// work with Swift packages. Such libraries are generally installed by system - /// package managers (such as Homebrew and APT) and exposed to Swift packages by - /// providing a modulemap file along with other metadata such as the library's - /// pkg-config name. + /// + /// Use system library targets to adapt a library installed on the system to work with Swift packages. + /// Such libraries are generally installed by system package managers (such as Homebrew and apt-get) + /// and exposed to Swift packages by providing a `modulemap` file along with other metadata such as the library's `pkgConfig` name. /// /// - Parameters: /// - name: The name of the target. - /// - path: The custom path for the target. By default, targets will be looked up in the /Sources/ directory. - /// Do not escape the package root, i.e. values like "../Foo" or "/Foo" are invalid. - /// - pkgConfig: The name of the pkg-config file for this system library. + /// - path: The custom path for the target. By default, a targets sources are expected to be located in the predefined search paths, + /// such as `[PackageRoot]/Sources/[TargetName]`. + /// Do not escape the package root; that is, values like `../Foo` or `/Foo` are invalid. + /// - pkgConfig: The name of the `pkg-config` file for this system library. /// - providers: The providers for this system library. public static func systemLibrary( name: String, @@ -402,7 +416,10 @@ extension Target: Encodable { } extension Target.Dependency { - /// A dependency on a target in the same package. + /// Creates a dependency on a target in the same package. + /// + /// - parameters: + /// - name: The name of the target. public static func target(name: String) -> Target.Dependency { #if PACKAGE_DESCRIPTION_4 return .targetItem(name: name) @@ -411,7 +428,11 @@ extension Target.Dependency { #endif } - /// A dependency on a product from a package dependency. + /// Creates a dependency on a product from a package dependency. + /// + /// - parameters: + /// - name: The name of the product. + /// - package: The name of the package. public static func product(name: String, package: String? = nil) -> Target.Dependency { #if PACKAGE_DESCRIPTION_4 return .productItem(name: name, package: package) @@ -420,8 +441,11 @@ extension Target.Dependency { #endif } - // A by-name dependency that resolves to either a target or a product, - // as above, after the package graph has been loaded. + /// Creates a by-name dependency that resolves to either a target or a product but + /// after the package graph has been loaded. + /// + /// - parameters: + /// - name: The name of the dependency, either a target or a product. public static func byName(name: String) -> Target.Dependency { #if PACKAGE_DESCRIPTION_4 return .byNameItem(name: name) @@ -434,6 +458,11 @@ extension Target.Dependency { // MARK: ExpressibleByStringLiteral extension Target.Dependency: ExpressibleByStringLiteral { + + /// Creates a target dependency instance with the given value. + /// + /// - parameters: + /// - value: A string literal. public init(stringLiteral value: String) { #if PACKAGE_DESCRIPTION_4 self = .byNameItem(name: value) diff --git a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift index 7aeecee4784..fb5e0fb7df0 100644 --- a/Sources/PackageDescription4/Version+StringLiteralConvertible.swift +++ b/Sources/PackageDescription4/Version+StringLiteralConvertible.swift @@ -10,6 +10,10 @@ extension Version: ExpressibleByStringLiteral { + /// Initializes and returns a newly allocated version struct for the provided string literal. + /// + /// - Parameters: + /// - version: A string literal to use for creating a new version object. public init(stringLiteral value: String) { if let version = Version(value) { self.init(version) @@ -23,10 +27,18 @@ extension Version: ExpressibleByStringLiteral { } } + /// Initializes and returns a newly allocated version struct for the provided extended grapheme cluster. + /// + /// - Parameters: + /// - version: An extended grapheme cluster to use for creating a new version object. public init(extendedGraphemeClusterLiteral value: String) { self.init(stringLiteral: value) } + /// Initializes and returns a newly allocated version struct for the provided Unicode string. + /// + /// - Parameters: + /// - version: A Unicode string to use for creating a new version object. public init(unicodeScalarLiteral value: String) { self.init(stringLiteral: value) } @@ -34,6 +46,10 @@ extension Version: ExpressibleByStringLiteral { extension Version { + /// Initializes and returns a newly allocated version struct for the provided version. + /// + /// - Parameters: + /// - version: A version object to use for creating a new version object. public init(_ version: Version) { major = version.major minor = version.minor @@ -42,6 +58,10 @@ extension Version { buildMetadataIdentifiers = version.buildMetadataIdentifiers } + /// Initializes and returns a newly allocated version struct for the provided version string. + /// + /// - Parameters: + /// - version: A version string to use for creating a new version object. public init?(_ versionString: String) { let prereleaseStartIndex = versionString.index(of: "-") let metadataStartIndex = versionString.index(of: "+") diff --git a/Sources/PackageDescription4/Version.swift b/Sources/PackageDescription4/Version.swift index 293bb8a68c4..e93e84b30f7 100644 --- a/Sources/PackageDescription4/Version.swift +++ b/Sources/PackageDescription4/Version.swift @@ -8,52 +8,63 @@ See http://swift.org/CONTRIBUTORS.txt for Swift project authors */ -/// A struct representing a Semantic Version. +/// A semantic version. /// -/// Semantic versioning is a specification that proposes a set of rules and +/// A package's version must conform to the semantic versioning standard in order to ensure +/// that your package behaves in a predictable manner once developers update their +/// package dependency to a newer version. To achieve predictability, the semantic versioning specification proposes a set of rules and /// requirements that dictate how version numbers are assigned and incremented. -/// To learn more about the semantic versioning specification, visit -/// www.semver.org. /// -/// # Semantic Versioning (SemVer) 2.0.0 +/// A package version is a three period-separated integer. An example is `1.0.0`. /// -/// ## The Major Version -/// -/// The major version signifies breaking changes to the API which requires -/// updating existing clients. For example, renaming an existing type, removing -/// a method or changing a method’s signature are considered breaking changes. -/// This also includes any backwards incompatible bugfixes or behaviour changes -/// of existing API. +/// **The Major Version** /// -/// ## The Minor Version +/// The first digit of a version, or *major version*, signifies breaking changes to the API that require +/// updates to existing clients. For example, the semantic versioning specification +/// considers renaming an existing type, removing a method, or changing a method's signature +/// breaking changes. This also includes any backward-incompatible bug fixes or +/// behavioral changes of the existing API. /// -/// Update the minor version if functionality is added in a backward compatible -/// manner. For example, adding a new method or type without changing any other -/// API is considered backward-compatible. +/// **The Minor Version** +// +/// Update the second digit of a version, or *minor version*, if you add functionality in a backward-compatible manner. +/// For example, the semantic versioning specification considers adding a new method +/// or type without changing any other API to be backward-compatible. /// /// ## The Patch Version /// -/// Increase the patch version if you are making a backward-compatible bugfix. -/// This allows clients to benefit from bugfixes to your package without -/// incurring any maintenance burden. +/// Increase the third digit of a version, or *patch version* if you are making a backward-compatible bug fix. +/// This allows clients to benefit from bugfixes to your package without incurring +/// any maintenance burden. +/// +/// To learn more about the semantic versioning specification, visit +/// [semver.org](www.semver.org). public struct Version { - /// The major version. + /// The major version according to the semantic versioning standard. public let major: Int - /// The minor version. + /// The minor version according to the semantic versioning standard. public let minor: Int - /// The patch version. + /// The patch version according to the semantic versioning standard. public let patch: Int - /// The pre-release identifier. + /// The pre-release identifier according to the semantic versioning standard, such as `-beta.1`. public let prereleaseIdentifiers: [String] - /// The build metadata. + /// The build metadata of this version according to the semantic versioning standard, such as a commit hash. public let buildMetadataIdentifiers: [String] - /// Create a version object. + /// Initializes and returns a newly allocated version struct + /// for the provided components of a semantic version. + /// + /// - Parameters: + /// - major: The major version numner. + /// - minor: The minor version number. + /// - patch: The patch version number. + /// - prereleaseIdentifiers: The pre-release identifier. + /// - buildMetaDataIdentifiers: Build metadata that identifies a build. public init( _ major: Int, _ minor: Int, @@ -111,6 +122,7 @@ extension Version: Comparable { } extension Version: CustomStringConvertible { + /// A textual description of the version object. public var description: String { var base = "\(major).\(minor).\(patch)" if !prereleaseIdentifiers.isEmpty { From e43bae3c5214c239a3baf82dca1602b7b001601e Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Mon, 24 Jun 2019 13:15:21 -0700 Subject: [PATCH 65/67] [bootstrap] Pass sdk when creating libPackageDescription --- Utilities/bootstrap | 1 + 1 file changed, 1 insertion(+) diff --git a/Utilities/bootstrap b/Utilities/bootstrap index 3c5d1d2c489..b6343c3f8f9 100755 --- a/Utilities/bootstrap +++ b/Utilities/bootstrap @@ -666,6 +666,7 @@ def process_runtime_libraries(build, args, lib_path): runtime_lib_path, "-Xlinker", "-all_load", input_lib_path, + "-sdk", args.sysroot, "-target", "x86_64-apple-macosx10.10"] else: # We include an RPATH entry so that the Swift libraries can be found From 682c8b939184317299ccae5068468b2350ea8cdb Mon Sep 17 00:00:00 2001 From: Boris Bielik Date: Tue, 25 Jun 2019 20:49:37 +0100 Subject: [PATCH 66/67] Update libSwiftPM.md Fixes path to libSwiftPM example project in libSwiftPM.md --- Documentation/libSwiftPM.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Documentation/libSwiftPM.md b/Documentation/libSwiftPM.md index c2482eb8640..0ee8bfea995 100644 --- a/Documentation/libSwiftPM.md +++ b/Documentation/libSwiftPM.md @@ -12,9 +12,8 @@ package: ```sh $ git clone https://github.com/apple/swift-package-manager -$ cd swift-package-manager/Examples/package-stats -$ make build-runtimes -$ swift build +$ cd swift-package-manager/Examples/package-info +$ make build $ swift run ``` From 6ebfec3fedd58bfadd672fc4981eea3d7d4bba75 Mon Sep 17 00:00:00 2001 From: Ankit Aggarwal Date: Wed, 26 Jun 2019 11:43:58 -0700 Subject: [PATCH 67/67] [Xcodeproj] Add $(inherited) to OTHER_SWIFT_FLAGS https://bugs.swift.org/browse/SR-10804 --- Sources/Xcodeproj/{generate().swift => generate.swift} | 0 Sources/Xcodeproj/{pbxproj().swift => pbxproj.swift} | 9 +++++---- 2 files changed, 5 insertions(+), 4 deletions(-) rename Sources/Xcodeproj/{generate().swift => generate.swift} (100%) rename Sources/Xcodeproj/{pbxproj().swift => pbxproj.swift} (99%) diff --git a/Sources/Xcodeproj/generate().swift b/Sources/Xcodeproj/generate.swift similarity index 100% rename from Sources/Xcodeproj/generate().swift rename to Sources/Xcodeproj/generate.swift diff --git a/Sources/Xcodeproj/pbxproj().swift b/Sources/Xcodeproj/pbxproj.swift similarity index 99% rename from Sources/Xcodeproj/pbxproj().swift rename to Sources/Xcodeproj/pbxproj.swift index 36b8d85bc34..e4f84c5f061 100644 --- a/Sources/Xcodeproj/pbxproj().swift +++ b/Sources/Xcodeproj/pbxproj.swift @@ -126,6 +126,10 @@ func xcodeProject( // paths so that all the products can be found. projectSettings.common.DYLIB_INSTALL_NAME_BASE = "@rpath" + // Set the `Xcode` build preset in Swift to let code conditionalize on + // being built in Xcode. + projectSettings.common.OTHER_SWIFT_FLAGS = ["$(inherited)", "-DXcode"] + // Add any additional compiler and linker flags the user has specified. if !options.flags.cCompilerFlags.isEmpty { projectSettings.common.OTHER_CFLAGS = options.flags.cCompilerFlags @@ -134,12 +138,9 @@ func xcodeProject( projectSettings.common.OTHER_LDFLAGS = options.flags.linkerFlags } if !options.flags.swiftCompilerFlags.isEmpty { - projectSettings.common.OTHER_SWIFT_FLAGS = options.flags.swiftCompilerFlags + projectSettings.common.OTHER_SWIFT_FLAGS += options.flags.swiftCompilerFlags } - // Also set the `Xcode` build preset in Swift to let code conditionalize on - // being built in Xcode. - projectSettings.common.OTHER_SWIFT_FLAGS += ["-DXcode"] projectSettings.common.MACOSX_DEPLOYMENT_TARGET = "10.10" // Prevent Xcode project upgrade warnings.