Files
swift-mirror/utils/swift-xcodegen/Sources/SwiftXcodeGen/BuildArgs/RunnableTargets.swift
Rintaro Ishizaki 8d2ac00015 [XcodeGen] Handle 'rule' declarations and generate command line args
* Rename 'BuildRule to 'BuildEdige' because it is the official term
* NinjaParser to handle 'include' and 'rule' directives
* NinjaParser to handle parse "rule name" in 'build' correctly
* Make variable table a simple `[String: String]` and keep any bindings
  to make the substitutions possible.
* Generate command line argumets using 'command' variable in the 'rule'
  and use it as the source of truth, istead of using random known
  bindings like 'FLAGS'.
2025-01-28 10:07:17 -08:00

76 lines
2.2 KiB
Swift

//===--- RunnableTargets.swift --------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2024 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
/// A target that defines a runnable executable.
struct RunnableTarget: Hashable {
var name: String
var ninjaTargetName: String
var path: AbsolutePath
}
struct RunnableTargets {
private var addedPaths: Set<RelativePath> = []
private var targets: [RunnableTarget] = []
init(from buildDir: RepoBuildDir) throws {
for rule in try buildDir.ninjaFile.buildEdges {
tryAddTarget(rule, buildDir: buildDir)
}
}
}
extension RunnableTargets: RandomAccessCollection {
typealias Element = RunnableTarget
typealias Index = Int
var startIndex: Int { targets.startIndex }
var endIndex: Int { targets.endIndex }
func index(_ i: Int, offsetBy distance: Int) -> Int {
targets.index(i, offsetBy: distance)
}
subscript(position: Int) -> RunnableTarget {
targets[position]
}
}
extension RunnableTargets {
private func getRunnablePath(
for outputs: [String]
) -> (String, RelativePath)? {
// We're only interested in rules with the path 'bin/<executable>'.
for output in outputs {
guard case let .relative(r) = AnyPath(output),
r.components.count == 2, r.components.first == "bin"
else { return nil }
return (output, r)
}
return nil
}
private mutating func tryAddTarget(
_ rule: NinjaBuildFile.BuildEdge, buildDir: RepoBuildDir
) {
guard let (name, path) = getRunnablePath(for: rule.outputs),
addedPaths.insert(path).inserted else { return }
let absPath = buildDir.path.appending(path)
guard absPath.exists, absPath.isExecutable else { return }
let target = RunnableTarget(
name: path.fileName, ninjaTargetName: name, path: absPath
)
targets.append(target)
}
}