Add Bazel feature flags functionality
This allows Tulsi to define flags conditional on Swift/non-Swift,
certain project configurations, etc. without impacting the Bazel
analysis cache.
Previously we would directly set Build Settings on the generated
xcodeproj in order to pass down these flags; however, this is
not a valid solution for caching reasons.
PiperOrigin-RevId: 204796507
diff --git a/src/Tulsi.xcodeproj/project.pbxproj b/src/Tulsi.xcodeproj/project.pbxproj
index 7af3111..8f59a39 100644
--- a/src/Tulsi.xcodeproj/project.pbxproj
+++ b/src/Tulsi.xcodeproj/project.pbxproj
@@ -116,6 +116,7 @@
54D8453F20CB121D004F6CF2 /* BazelSettingsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54D8453E20CB121D004F6CF2 /* BazelSettingsProvider.swift */; };
54EA05C81F62E3A700472AB6 /* RuleEntryMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EA05C71F62E3A700472AB6 /* RuleEntryMap.swift */; };
54EC201820D1A8270050AF12 /* TulsiApplicationSupport.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EC201720D1A8270050AF12 /* TulsiApplicationSupport.swift */; };
+ 54EDD24520D9BC27001A1B35 /* BuildSettingsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54EDD24420D9BC26001A1B35 /* BuildSettingsTests.swift */; };
54EF320A1F3E0804009E9C7F /* bazel_build_events.py in Resources */ = {isa = PBXBuildFile; fileRef = 54EF32091F3E0804009E9C7F /* bazel_build_events.py */; };
774F6E9720A2400E00572B76 /* bazel_build_flags.py in Resources */ = {isa = PBXBuildFile; fileRef = 774F6E9620A2400E00572B76 /* bazel_build_flags.py */; };
8B0F78C81BE5BC7E00357561 /* ConfigEditorSourceFilterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B0F78C71BE5BC7E00357561 /* ConfigEditorSourceFilterViewController.swift */; };
@@ -302,6 +303,7 @@
54D8453E20CB121D004F6CF2 /* BazelSettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BazelSettingsProvider.swift; sourceTree = "<group>"; };
54EA05C71F62E3A700472AB6 /* RuleEntryMap.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RuleEntryMap.swift; sourceTree = "<group>"; };
54EC201720D1A8270050AF12 /* TulsiApplicationSupport.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TulsiApplicationSupport.swift; sourceTree = "<group>"; };
+ 54EDD24420D9BC26001A1B35 /* BuildSettingsTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildSettingsTests.swift; sourceTree = "<group>"; };
54EF32091F3E0804009E9C7F /* bazel_build_events.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = bazel_build_events.py; sourceTree = "<group>"; };
774F6E9620A2400E00572B76 /* bazel_build_flags.py */ = {isa = PBXFileReference; lastKnownFileType = text.script.python; name = bazel_build_flags.py; path = TulsiGenerator/Scripts/bazel_build_flags.py; sourceTree = "<group>"; };
8B0F78C71BE5BC7E00357561 /* ConfigEditorSourceFilterViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConfigEditorSourceFilterViewController.swift; sourceTree = "<group>"; };
@@ -414,6 +416,7 @@
isa = PBXGroup;
children = (
3D9DAF541C23604100955CD5 /* BuildLabelTests.swift */,
+ 54EDD24420D9BC26001A1B35 /* BuildSettingsTests.swift */,
3DFB7C4E1C835EFB00376760 /* CommandLineSplitterTests.swift */,
3D9926751C29F0A30094E098 /* Info.plist */,
3DA65B411C68539F0055448E /* Mocks */,
@@ -910,6 +913,7 @@
3D9926811C29F0CC0094E098 /* PBXTargetGeneratorTests.swift in Sources */,
3D9926821C29F0CC0094E098 /* BuildLabelTests.swift in Sources */,
3D9926841C29F0CC0094E098 /* PBXObjectsTests.swift in Sources */,
+ 54EDD24520D9BC27001A1B35 /* BuildSettingsTests.swift in Sources */,
3DA65B621C693B570055448E /* TulsiGeneratorConfigTests.swift in Sources */,
3DA65B3E1C6849140055448E /* XcodeProjectGeneratorTests.swift in Sources */,
54D17A5220D94C4B0028D377 /* PythonableTests.swift in Sources */,
diff --git a/src/Tulsi/TulsiGeneratorConfigDocument.swift b/src/Tulsi/TulsiGeneratorConfigDocument.swift
index 78782f0..2f78247 100644
--- a/src/Tulsi/TulsiGeneratorConfigDocument.swift
+++ b/src/Tulsi/TulsiGeneratorConfigDocument.swift
@@ -441,6 +441,14 @@
}
}
+ private func enabledFeatures(options: TulsiOptionSet) -> Set<BazelSettingFeature> {
+ let workspaceRoot = infoExtractor.workspaceRootURL.path
+ let bazelExecroot = infoExtractor.bazelExecutionRoot
+ return BazelBuildSettingsFeatures.enabledFeatures(options: options,
+ workspaceRoot: workspaceRoot,
+ bazelExecRoot: bazelExecroot)
+ }
+
// Regenerates the sourcePaths array based on the currently selected ruleEntries.
func updateSourcePaths(_ callback: @escaping ([UISourcePath]) -> Void) {
var sourcePathMap = [String: UISourcePath]()
@@ -467,7 +475,8 @@
startupOptions: startupOptions,
buildOptions: buildOptions,
projectGenBuildOptions: projectGenBuildOptions,
- prioritizeSwiftOption: prioritizeSwiftOption)
+ prioritizeSwiftOption: prioritizeSwiftOption,
+ features: self.enabledFeatures(options: optionSet))
} catch TulsiProjectInfoExtractor.ExtractorError.ruleEntriesFailed(let info) {
LogMessage.postError("Label resolution failed: \(info)")
return
@@ -787,11 +796,13 @@
return
}
+ let options = optionSet!
let ruleEntryMap = try infoExtractor.ruleEntriesForLabels(concreteBuildTargetLabels,
- startupOptions: optionSet![.BazelBuildStartupOptionsDebug],
- buildOptions: optionSet![.BazelBuildOptionsDebug],
- projectGenBuildOptions: optionSet![.BazelBuildOptionsProjectGenerationOnly],
- prioritizeSwiftOption: optionSet![.ProjectPrioritizesSwift])
+ startupOptions: options[.BazelBuildStartupOptionsDebug],
+ buildOptions: options[.BazelBuildOptionsDebug],
+ projectGenBuildOptions: options[.BazelBuildOptionsProjectGenerationOnly],
+ prioritizeSwiftOption: options[.ProjectPrioritizesSwift],
+ features: enabledFeatures(options: options))
var unresolvedLabels = Set<BuildLabel>()
var ruleInfos = [UIRuleInfo]()
for label in concreteBuildTargetLabels {
diff --git a/src/TulsiGenerator/BazelAspectInfoExtractor.swift b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
index 49f66c1..d253ab2 100644
--- a/src/TulsiGenerator/BazelAspectInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelAspectInfoExtractor.swift
@@ -67,7 +67,8 @@
startupOptions: [String] = [],
buildOptions: [String] = [],
projectGenerationOptions: [String] = [],
- prioritizeSwift: Bool = false) throws -> RuleEntryMap {
+ prioritizeSwift: Bool = false,
+ features: Set<BazelSettingFeature> = []) throws -> RuleEntryMap {
guard !targets.isEmpty else {
return RuleEntryMap()
}
@@ -76,7 +77,8 @@
startupOptions: startupOptions,
buildOptions: buildOptions,
projectGenerationOptions: projectGenerationOptions,
- prioritizeSwift: prioritizeSwift)
+ prioritizeSwift: prioritizeSwift,
+ features: features)
}
// MARK: - Private methods
@@ -85,7 +87,8 @@
startupOptions: [String],
buildOptions: [String],
projectGenerationOptions: [String],
- prioritizeSwift: Bool) throws -> RuleEntryMap {
+ prioritizeSwift: Bool,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap {
localizedMessageLogger.infoMessage("Build Events JSON file at \"\(buildEventsFilePath)\"")
let progressNotifier = ProgressNotifier(name: SourceFileExtraction,
@@ -105,6 +108,7 @@
buildOptions: buildOptions,
projectGenerationOptions: projectGenerationOptions,
prioritizeSwift: prioritizeSwift,
+ features: features,
progressNotifier: progressNotifier) {
(process: Process, debugInfo: String) -> Void in
defer { semaphore.signal() }
@@ -162,6 +166,7 @@
buildOptions: [String] = [],
projectGenerationOptions: [String] = [],
prioritizeSwift: Bool,
+ features: Set<BazelSettingFeature>,
progressNotifier: ProgressNotifier? = nil,
terminationHandler: @escaping CompletionHandler) -> Process? {
@@ -177,7 +182,8 @@
let tulsiVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String ?? "UNKNOWN"
- let tulsiFlags = bazelSettingsProvider.tulsiFlags(hasSwift: prioritizeSwift).getFlags()
+ let tulsiFlags = bazelSettingsProvider.tulsiFlags(hasSwift: prioritizeSwift,
+ features: features).getFlags()
var arguments = startupOptions
arguments.append(contentsOf: tulsiFlags.startup)
arguments.append("build")
diff --git a/src/TulsiGenerator/BazelBuildSettings.swift b/src/TulsiGenerator/BazelBuildSettings.swift
index 4743124..47e7d21 100644
--- a/src/TulsiGenerator/BazelBuildSettings.swift
+++ b/src/TulsiGenerator/BazelBuildSettings.swift
@@ -185,6 +185,9 @@
public let tulsiSwiftFlagSet: BazelFlagsSet
public let tulsiNonSwiftFlagSet: BazelFlagsSet
+ public let swiftFeatures: [String]
+ public let nonSwiftFeatures: [String]
+
/// Set of targets which depend (in some fashion) on Swift.
public let swiftTargets: Set<String>
@@ -198,6 +201,8 @@
tulsiCacheSafeFlagSet: BazelFlagsSet,
tulsiSwiftFlagSet: BazelFlagsSet,
tulsiNonSwiftFlagSet: BazelFlagsSet,
+ swiftFeatures: [String],
+ nonSwiftFeatures: [String],
projDefaultFlagSet: BazelFlagsSet,
projTargetFlagSets: [String: BazelFlagsSet]) {
self.bazel = bazel
@@ -207,6 +212,8 @@
self.tulsiCacheSafeFlagSet = tulsiCacheSafeFlagSet
self.tulsiSwiftFlagSet = tulsiSwiftFlagSet
self.tulsiNonSwiftFlagSet = tulsiNonSwiftFlagSet
+ self.swiftFeatures = swiftFeatures
+ self.nonSwiftFeatures = nonSwiftFeatures
self.projDefaultFlagSet = projDefaultFlagSet
self.projTargetFlagSets = projTargetFlagSets
}
@@ -222,6 +229,8 @@
\(nestedIndentation)\(tulsiCacheSafeFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiSwiftFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(tulsiNonSwiftFlagSet.toPython(nestedIndentation)),
+\(nestedIndentation)\(swiftFeatures.toPython(nestedIndentation)),
+\(nestedIndentation)\(nonSwiftFeatures.toPython(nestedIndentation)),
\(nestedIndentation)\(projDefaultFlagSet.toPython(nestedIndentation)),
\(nestedIndentation)\(projTargetFlagSets.toPython(nestedIndentation)),
\(indentation))
diff --git a/src/TulsiGenerator/BazelBuildSettingsFeatures.swift b/src/TulsiGenerator/BazelBuildSettingsFeatures.swift
index 1bb7437..7b405f0 100644
--- a/src/TulsiGenerator/BazelBuildSettingsFeatures.swift
+++ b/src/TulsiGenerator/BazelBuildSettingsFeatures.swift
@@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-let bazelBuildSettingsFeatures = [
- // For non-distributed builds.
- // TODO(b/69857078): Replace with normalized debug info when wrapped_clang
- // is updated.
- "TULSI_DIRECT_DBG_PREFIX_MAP",
-]
+public class BazelBuildSettingsFeatures {
+ public static func enabledFeatures(
+ options: TulsiOptionSet,
+ workspaceRoot: String,
+ bazelExecRoot: String
+ ) -> Set<BazelSettingFeature> {
+ return [.DirectDebugPrefixMap(bazelExecRoot, workspaceRoot)]
+ }
+}
diff --git a/src/TulsiGenerator/BazelSettingsProvider.swift b/src/TulsiGenerator/BazelSettingsProvider.swift
index c9524bd..2bb3d61 100644
--- a/src/TulsiGenerator/BazelSettingsProvider.swift
+++ b/src/TulsiGenerator/BazelSettingsProvider.swift
@@ -14,18 +14,100 @@
import Foundation
+/// Bazel feature settings that map to Bazel flags (start up or build options). These flags may
+/// affect Bazel analysis/action caching and therefore should be kept consistent between all
+/// invocations from Tulsi.
+///
+/// If adding a flag that does not impact Bazel caching, it can be added directly to
+/// BazelSettingsProvider directly (either as a cacheableFlag or a configBasedFlag).
+public enum BazelSettingFeature: Hashable, Pythonable {
+
+ /// Feature flag to normalize paths present in debug information via a Clang flag for distributed
+ /// builds (e.g. multiple distinct paths).
+ /// - Mutually exclusive with DirectDebugPrefixMap feature
+ ///
+ /// The use of this flag does not affect any sources built by swiftc. At present time, all Swift
+ /// compiled sources will be built with uncacheable, absolute paths, as the Swift compiler does
+ /// not provide an easy means of similarly normalizing all debug information.
+ case DebugPathNormalization
+
+ /// Feature flag to normalize paths present in debug information via a Clang flag for local
+ /// builds.
+ /// - Mutually exclusive with DebugPathNormalization feature
+ ///
+ /// NOTE: Use of -fdebug-prefix-map leads to producing binaries that cannot be
+ /// reused across multiple machines by a distributed build system, unless the
+ /// absolute paths to files visible to Xcode match perfectly between all of
+ /// those machines.
+ ///
+ /// For this reason, -fdebug-prefix-map is provided as a default for non-distributed purposes.
+ case DirectDebugPrefixMap(String, String)
+
+ public var stringValue: String {
+ switch self {
+ case .DebugPathNormalization:
+ return "DebugPathNormalization"
+ case .DirectDebugPrefixMap:
+ return "DirectDebugPrefixMap"
+ }
+ }
+
+ public var hashValue: Int {
+ return stringValue.hashValue
+ }
+
+ public static func ==(lhs: BazelSettingFeature, rhs: BazelSettingFeature) -> Bool {
+ return lhs.stringValue == rhs.stringValue
+ }
+
+ public var supportsSwift: Bool {
+ switch self {
+ case .DebugPathNormalization:
+ return false
+ case .DirectDebugPrefixMap:
+ return true
+ }
+ }
+
+ public var supportsNonSwift: Bool {
+ switch self {
+ case .DebugPathNormalization:
+ return true
+ case .DirectDebugPrefixMap:
+ return true
+ }
+ }
+
+ /// Start up flags for this feature.
+ public var startupFlags: [String] {
+ return []
+ }
+
+ /// Build flags for this feature.
+ public var buildFlags: [String] {
+ switch self {
+ case .DebugPathNormalization: return ["--features=debug_prefix_map_pwd_is_dot"]
+ case .DirectDebugPrefixMap(let execRoot, let workspaceRoot): return [
+ String(format: "--copt=-fdebug-prefix-map=%@=%@", execRoot, workspaceRoot)
+ ]
+ }
+ }
+
+ func toPython(_ indentation: String) -> String {
+ return stringValue.toPython(indentation)
+ }
+}
+
/// Defines an object that provides flags for Bazel invocations.
protocol BazelSettingsProviderProtocol {
/// All general-Tulsi flags, varying based on whether the project has Swift or not.
- func tulsiFlags(hasSwift: Bool) -> BazelFlagsSet
-
- /// Cache-able Bazel flags based off TulsiOptions, used to generate BazelBuildSettings.
- func optionsBasedFlags(_ options: TulsiOptionSet) -> BazelFlagsSet
+ func tulsiFlags(hasSwift: Bool, features: Set<BazelSettingFeature>) -> BazelFlagsSet
/// Bazel build settings, used during Xcode/user Bazel builds.
func buildSettings(bazel: String,
bazelExecRoot: String,
options: TulsiOptionSet,
+ features: Set<BazelSettingFeature>,
buildRuleEntries: Set<RuleEntry>) -> BazelBuildSettings
}
@@ -57,11 +139,8 @@
/// Flags added by Tulsi for builds which do not contain Swift.
/// - Enable dSYMs only for Release builds.
- /// - Flag for remapping debug symbols.
static let tulsiNonSwiftFlags = BazelFlagsSet(
- release: BazelFlags(build: ["--apple_generate_dsym"]),
- // TODO: Somehow support the open-source version of this which varies based on the exec-root.
- common: BazelFlags(build: ["--features=debug_prefix_map_pwd_is_dot"]))
+ release: BazelFlags(build: ["--apple_generate_dsym"]))
let universalFlags: BazelFlags
let cacheableFlags: BazelFlagsSet
@@ -90,11 +169,40 @@
self.nonSwiftFlags = nonSwiftFlags
}
- func tulsiFlags(hasSwift: Bool) -> BazelFlagsSet {
- let languageFlags = hasSwift ? swiftFlags : nonSwiftFlags
+ func tulsiFlags(hasSwift: Bool, features: Set<BazelSettingFeature>) -> BazelFlagsSet {
+ let languageFlags = (hasSwift ? swiftFlags : nonSwiftFlags) + featureFlags(features,
+ hasSwift: hasSwift)
return BazelFlagsSet(common: universalFlags) + cacheableFlags + nonCacheableFlags + languageFlags
}
+ /// Non-cacheable Bazel flags based off of BazelSettingFeatures for the project.
+ func featureFlags(_ features: Set<BazelSettingFeature>, hasSwift: Bool) -> BazelFlagsSet {
+ let validFeatures = features.filter { return hasSwift ? $0.supportsSwift : $0.supportsNonSwift }
+ let sortedFeatures = validFeatures.sorted { (a, b) -> Bool in
+ return a.stringValue > b.stringValue
+ }
+
+ let startupFlags = sortedFeatures.reduce(into: []) { (arr, feature) in
+ arr.append(contentsOf: feature.startupFlags)
+ }
+ let buildFlags = sortedFeatures.reduce(into: []) { (arr, feature) in
+ arr.append(contentsOf: feature.buildFlags)
+ }
+ return BazelFlagsSet(startupFlags: startupFlags, buildFlags: buildFlags)
+ }
+
+ /// Returns an array of the enabled features' names.
+ func featureNames(_ features: Set<BazelSettingFeature>, hasSwift: Bool) -> [String] {
+ let validFeatures = features.filter { return hasSwift ? $0.supportsSwift : $0.supportsNonSwift }
+ return validFeatures.sorted { (a, b) -> Bool in
+ return a.stringValue > b.stringValue
+ }.map { $0.stringValue }
+ }
+
+ /// Cache-able Bazel flags based off TulsiOptions, used to generate BazelBuildSettings. This
+ /// should only add flags that do not affect Bazel analysis/action caching; flags that are based
+ /// off of TulsiOptions but do affect Bazel caching should instead be added to as
+ /// BazelSettingFeatures.
func optionsBasedFlags(_ options: TulsiOptionSet) -> BazelFlagsSet {
var configBasedTulsiFlags = [String]()
if let continueBuildingAfterError = options[.BazelContinueBuildingAfterError].commonValueAsBool,
@@ -107,6 +215,7 @@
func buildSettings(bazel: String,
bazelExecRoot: String,
options: TulsiOptionSet,
+ features: Set<BazelSettingFeature>,
buildRuleEntries: Set<RuleEntry>) -> BazelBuildSettings {
let projDefaultSettings = getProjDefaultSettings(options)
var targetSettings = [String: BazelFlagsSet]()
@@ -130,13 +239,20 @@
}
let swiftTargets = Set(swiftRuleEntries.map { $0.label.value })
+ let tulsiSwiftFlags = swiftFlags + featureFlags(features, hasSwift: true)
+ let tulsiNonSwiftFlagSet = nonSwiftFlags + featureFlags(features, hasSwift: false)
+ let swiftFeatures = featureNames(features, hasSwift: true)
+ let nonSwiftFeatures = featureNames(features, hasSwift: false)
+
return BazelBuildSettings(bazel: bazel,
bazelExecRoot: bazelExecRoot,
swiftTargets: swiftTargets,
tulsiCacheAffectingFlagsSet: BazelFlagsSet(common: universalFlags) + nonCacheableFlags,
tulsiCacheSafeFlagSet: cacheableFlags + optionsBasedFlags(options),
- tulsiSwiftFlagSet: swiftFlags,
- tulsiNonSwiftFlagSet: nonSwiftFlags,
+ tulsiSwiftFlagSet: tulsiSwiftFlags,
+ tulsiNonSwiftFlagSet: tulsiNonSwiftFlagSet,
+ swiftFeatures: swiftFeatures,
+ nonSwiftFeatures: nonSwiftFeatures,
projDefaultFlagSet: projDefaultSettings,
projTargetFlagSets: targetSettings)
}
diff --git a/src/TulsiGenerator/BazelWorkspaceInfoExtractor.swift b/src/TulsiGenerator/BazelWorkspaceInfoExtractor.swift
index d7f35d7..29623a3 100644
--- a/src/TulsiGenerator/BazelWorkspaceInfoExtractor.swift
+++ b/src/TulsiGenerator/BazelWorkspaceInfoExtractor.swift
@@ -39,6 +39,9 @@
/// Bazel settings provider for all invocations.
let bazelSettingsProvider: BazelSettingsProviderProtocol
+ /// Bazel workspace root URL.
+ let workspaceRootURL: URL
+
/// Fetcher object from which a workspace's path info may be obtained.
private let workspacePathInfoFetcher: BazelWorkspacePathInfoFetcher
@@ -74,6 +77,7 @@
workspaceRootURL: workspaceRootURL,
bazelUniversalFlags: universalFlags,
localizedMessageLogger: localizedMessageLogger)
+ self.workspaceRootURL = workspaceRootURL
}
// MARK: - BazelWorkspaceInfoExtractorProtocol
@@ -86,7 +90,8 @@
startupOptions: TulsiOption,
buildOptions: TulsiOption,
projectGenBuildOptions: TulsiOption,
- prioritizeSwiftOption: TulsiOption) throws -> RuleEntryMap {
+ prioritizeSwiftOption: TulsiOption,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap {
func isLabelMissing(_ label: BuildLabel) -> Bool {
return !ruleEntryCache.hasAnyRuleEntry(withBuildLabel: label)
}
@@ -111,7 +116,8 @@
startupOptions: startupOptions,
buildOptions: buildOptions,
projectGenerationOptions: projectGenerationOptions,
- prioritizeSwift: prioritizeSwift)
+ prioritizeSwift: prioritizeSwift,
+ features: features)
ruleEntryCache = RuleEntryMap(ruleEntryMap)
} catch BazelAspectInfoExtractor.ExtractorError.buildFailed {
throw BazelWorkspaceInfoExtractorError.aspectExtractorFailed("Bazel aspects could not be built.")
diff --git a/src/TulsiGenerator/BazelWorkspaceInfoExtractorProtocol.swift b/src/TulsiGenerator/BazelWorkspaceInfoExtractorProtocol.swift
index 1d26444..04233ab 100644
--- a/src/TulsiGenerator/BazelWorkspaceInfoExtractorProtocol.swift
+++ b/src/TulsiGenerator/BazelWorkspaceInfoExtractorProtocol.swift
@@ -30,7 +30,8 @@
startupOptions: TulsiOption,
buildOptions: TulsiOption,
projectGenBuildOptions: TulsiOption,
- prioritizeSwiftOption: TulsiOption) throws -> RuleEntryMap
+ prioritizeSwiftOption: TulsiOption,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap
/// Extracts labels for the files referenced by the build infrastructure for the given set of
/// BUILD targets.
@@ -51,6 +52,9 @@
/// Absolute path to the Bazel execution root.
var bazelExecutionRoot: String {get}
+ /// The location of the Bazel workspace to be examined.
+ var workspaceRootURL: URL {get}
+
/// Bazel flag provider for all invocations.
var bazelSettingsProvider: BazelSettingsProviderProtocol {get}
}
diff --git a/src/TulsiGenerator/PBXTargetGenerator.swift b/src/TulsiGenerator/PBXTargetGenerator.swift
index b3195bd..f96bb21 100644
--- a/src/TulsiGenerator/PBXTargetGenerator.swift
+++ b/src/TulsiGenerator/PBXTargetGenerator.swift
@@ -1515,15 +1515,6 @@
buildSettings["TARGETED_DEVICE_FAMILY[sdk=iphonesimulator*]"] = "1,4"
}
- // Tell our build script when a Swift dependency has been found. This could be discovered
- // through the aspect instead, but we keep this information here for the sake of our debug info
- // remapping story (for now).
- //
- // TODO(b/77916902): See if we can base this directly on if we have any Swift files indexed.
- // The state of has_swift_dependency is currently computed through our aspect.
- let swiftDependency = entry.attributes[.has_swift_dependency] as? Bool ?? false
- buildSettings["TULSI_SWIFT_DEPENDENCY"] = swiftDependency ? "YES" : "NO"
-
// bazel_build.py uses this to determine if it needs to pass the --xcode_version flag, as the
// flag can have implications for caching even if the user's active Xcode version is the same
// as the flag.
diff --git a/src/TulsiGenerator/Scripts/bazel_build.py b/src/TulsiGenerator/Scripts/bazel_build.py
index 621207d..d3c1beb 100755
--- a/src/TulsiGenerator/Scripts/bazel_build.py
+++ b/src/TulsiGenerator/Scripts/bazel_build.py
@@ -21,6 +21,7 @@
import io
import json
import os
+import pipes
import re
import shutil
import signal
@@ -256,6 +257,10 @@
self.targets[0],
is_debug)
+ def GetEnabledFeatures(self):
+ """Returns a list of enabled Bazel features for the active target."""
+ return self.build_settings.features_for_target(self.targets[0])
+
def GetBazelOptions(self, config):
"""Returns the full set of build options for the given config."""
bazel, start_up, build = self.GetBaseFlagsForTargets(config)
@@ -351,7 +356,8 @@
BUILD_EVENTS_FILE = 'build_events.json'
- def __init__(self):
+ def __init__(self, build_settings):
+ self.build_settings = build_settings
self.verbose = 0
self.build_path = None
self.bazel_bin_path = None
@@ -371,21 +377,10 @@
'earlier Xcode, build %s.' % xcode_build_version)
self.tulsi_version = os.environ.get('TULSI_VERSION', 'UNKNOWN')
- self.swift_dependency = os.environ.get('TULSI_SWIFT_DEPENDENCY',
- 'NO') == 'YES'
# TODO(b/69857078): Remove this when wrapped_clang is updated.
- self.direct_debug_prefix_map = os.environ.get('TULSI_DIRECT_DBG_PREFIX_MAP',
- 'NO') == 'YES'
-
- if self.swift_dependency or self.direct_debug_prefix_map:
- # Disable the normalized debug prefix map as swiftc doesn't support it.
- #
- # In addition, use of the direct_debug_prefix_map preempts the usage of
- # the normalized debug prefix map.
- self.normalized_prefix_map = False
- else:
- self.normalized_prefix_map = True
+ self.direct_debug_prefix_map = False
+ self.normalized_prefix_map = False
self.update_symbol_cache = UpdateSymbolCache()
@@ -472,13 +467,7 @@
sys.stderr.write('Xcode action is %s, ignoring.' % self.xcode_action)
return 0
- build_settings = bazel_build_settings.BUILD_SETTINGS
- if build_settings is None:
- _PrintXcodeError('Unable to resolve build settings. '
- 'Please report a Tulsi bug.')
- return 1
-
- parser = _OptionsParser(build_settings,
+ parser = _OptionsParser(self.build_settings,
self.sdk_version,
self.platform_name,
self.arch)
@@ -492,23 +481,12 @@
self.verbose = parser.verbose
self.bazel_bin_path = os.path.abspath(parser.bazel_bin_path)
self.bazel_executable = parser.bazel_executable
- self.bazel_exec_root = build_settings.bazelExecRoot
+ self.bazel_exec_root = self.build_settings.bazelExecRoot
- # Until wrapped_clang is updated, use -fdebug-prefix-map to have debug
- # symbols match Xcode-visible sources.
- #
- # NOTE: Use of -fdebug-prefix-map leads to producing binaries that cannot be
- # reused across multiple machines by a distributed build system, unless the
- # absolute paths to files visible to Xcode match perfectly between all of
- # those machines.
- #
- # For this reason, -fdebug-prefix-map is provided as a default for non-
- # distributed purposes.
- if self.direct_debug_prefix_map:
- source_map = self._ExtractTargetSourceMap(False)
- if source_map:
- prefix_map = '--copt=-fdebug-prefix-map=%s=%s' % source_map
- parser.common_build_options.append(prefix_map)
+ # Update feature flags.
+ features = parser.GetEnabledFeatures()
+ self.direct_debug_prefix_map = 'DirectDebugPrefixMap' in features
+ self.normalized_prefix_map = 'DebugPathNormalization' in features
self.build_path = os.path.join(self.bazel_bin_path,
os.environ.get('TULSI_BUILD_PATH', ''))
@@ -653,19 +631,6 @@
else:
bazel_command.append('--output_groups=tulsi-outputs,default')
- # A normalized path for -fdebug-prefix-map exists for keeping all debug
- # information as built by Clang consistent for the sake of caching within
- # a distributed build system.
- #
- # This is handled through a wrapped_clang feature flag via the CROSSTOOL.
- #
- # The use of this flag does not affect any sources built by swiftc. At
- # present time, all Swift compiled sources will be built with uncacheable,
- # absolute paths, as the Swift compiler does not present an easy means of
- # similarly normalizing all debug information.
- if self.normalized_prefix_map:
- bazel_command.append('--features=debug_prefix_map_pwd_is_dot')
-
bazel_command.extend(options.targets)
extra_options = bazel_options.BazelOptions(os.environ)
@@ -677,7 +642,7 @@
"""Runs subprocess command, patching output as it's received."""
self._PrintVerbose('Running "%s", patching output for workspace root at '
'"%s" with project path at "%s".' %
- (' '.join(command),
+ (' '.join([pipes.quote(x) for x in command]),
self.workspace_root,
self.project_dir))
# Xcode translates anything that looks like ""<path>:<line>:" that is not
@@ -1663,11 +1628,20 @@
sys.stdout.flush()
+def main(argv):
+ build_settings = bazel_build_settings.BUILD_SETTINGS
+ if build_settings is None:
+ _PrintXcodeError('Unable to resolve build settings. '
+ 'Please report a Tulsi bug.')
+ return 1
+ return BazelBuildBridge(build_settings).Run(argv)
+
+
if __name__ == '__main__':
_LockFileAcquire('/tmp/tulsi_bazel_build.lock')
_logger = tulsi_logging.Logger()
_timer = Timer('Everything', 'complete_build').Start()
signal.signal(signal.SIGINT, _InterruptHandler)
- _exit_code = BazelBuildBridge().Run(sys.argv)
+ _exit_code = main(sys.argv)
_timer.End()
sys.exit(_exit_code)
diff --git a/src/TulsiGenerator/Scripts/bazel_build_settings.py.template b/src/TulsiGenerator/Scripts/bazel_build_settings.py.template
index 1465f51..7536d0b 100644
--- a/src/TulsiGenerator/Scripts/bazel_build_settings.py.template
+++ b/src/TulsiGenerator/Scripts/bazel_build_settings.py.template
@@ -63,6 +63,7 @@
def __init__(self, bazel, bazelExecRoot, swiftTargets,
cacheAffecting, cacheSafe,
swiftOnly, nonSwiftOnly,
+ swiftFeatures, nonSwiftFeatures,
projDefault, projTargetMap):
self.bazel = bazel
self.bazelExecRoot = bazelExecRoot
@@ -71,10 +72,22 @@
self.cacheSafe = cacheSafe
self.swiftOnly = swiftOnly
self.nonSwiftOnly = nonSwiftOnly
+ self.swiftFeatures = swiftFeatures
+ self.nonSwiftFeatures = nonSwiftFeatures
self.projDefault = projDefault
self.projTargetMap = projTargetMap
- def flags_for_target(self, target, is_debug):
+ def features_for_target(self, target, is_swift_override=None):
+ """Returns an array of enabled features for the given target."""
+
+ target = _StandardizeTargetLabel(target)
+ is_swift = target in self.swiftTargets
+ if is_swift_override is not None:
+ is_swift = is_swift_override
+
+ return self.swiftFeatures if is_swift else self.nonSwiftFeatures
+
+ def flags_for_target(self, target, is_debug, is_swift_override=None):
"""Returns (bazel, startup flags, build flags) for the given target."""
target = _StandardizeTargetLabel(target)
@@ -82,7 +95,10 @@
if not target_flag_set:
target_flag_set = self.projDefault
- lang = self.swiftOnly if target in self.swiftTargets else self.nonSwiftOnly
+ is_swift = target in self.swiftTargets
+ if is_swift_override is not None:
+ is_swift = is_swift_override
+ lang = self.swiftOnly if is_swift else self.nonSwiftOnly
cache_affecting = self.cacheAffecting.flags(is_debug)
cache_safe = self.cacheSafe.flags(is_debug)
diff --git a/src/TulsiGenerator/Scripts/user_build.py b/src/TulsiGenerator/Scripts/user_build.py
index cb0a817..244f7f4 100755
--- a/src/TulsiGenerator/Scripts/user_build.py
+++ b/src/TulsiGenerator/Scripts/user_build.py
@@ -17,6 +17,7 @@
import argparse
+import pipes
import subprocess
import sys
from bazel_build_settings import BUILD_SETTINGS
@@ -34,10 +35,11 @@
def _CreateCommand(targets, build_settings, test, release,
- config, xcode_version):
+ config, xcode_version, force_swift):
"""Creates a Bazel command for targets with the specified settings."""
target = _BuildSettingsTargetForTargets(targets)
- bazel, startup, flags = build_settings.flags_for_target(target, not release)
+ bazel, startup, flags = build_settings.flags_for_target(
+ target, not release, is_swift_override=force_swift)
bazel_action = 'test' if test else 'build'
command = [bazel]
@@ -53,6 +55,11 @@
return command
+def _QuoteCommandForShell(cmd):
+ cmd = [pipes.quote(x) for x in cmd]
+ return ' '.join(cmd)
+
+
def _InterruptSafeCall(cmd):
p = subprocess.Popen(cmd)
try:
@@ -75,13 +82,20 @@
parser.add_argument('--norun', dest='run', action='store_false', default=True)
parser.add_argument('--config', help='Bazel --config flag.')
parser.add_argument('--xcode_version', help='Bazel --xcode_version flag.')
+ parser.add_argument('--force_swift', dest='swift', action='store_true',
+ default=None, help='Forcibly treat the given targets '
+ 'as containing Swift.')
+ parser.add_argument('--force_noswift', dest='swift', action='store_false',
+ default=None, help='Forcibly treat the given targets '
+ 'as not containing Swift.')
parser.add_argument('targets', nargs='+')
args = parser.parse_args()
command = _CreateCommand(args.targets, BUILD_SETTINGS, args.test,
- args.release, args.config, args.xcode_version)
+ args.release, args.config, args.xcode_version,
+ args.swift)
if args.print_cmd:
- print ' '.join(command)
+ print _QuoteCommandForShell(command)
if args.run:
return _InterruptSafeCall(command)
diff --git a/src/TulsiGenerator/TulsiProjectInfoExtractor.swift b/src/TulsiGenerator/TulsiProjectInfoExtractor.swift
index 198f261..8373e25 100644
--- a/src/TulsiGenerator/TulsiProjectInfoExtractor.swift
+++ b/src/TulsiGenerator/TulsiProjectInfoExtractor.swift
@@ -29,6 +29,14 @@
set { workspaceInfoExtractor.bazelURL = newValue }
}
+ public var bazelExecutionRoot: String {
+ return workspaceInfoExtractor.bazelExecutionRoot
+ }
+
+ public var workspaceRootURL: URL {
+ return workspaceInfoExtractor.workspaceRootURL
+ }
+
public init(bazelURL: URL,
project: TulsiProject) {
self.project = project
@@ -48,25 +56,29 @@
startupOptions: TulsiOption,
buildOptions: TulsiOption,
projectGenBuildOptions: TulsiOption,
- prioritizeSwiftOption: TulsiOption) throws -> RuleEntryMap {
+ prioritizeSwiftOption: TulsiOption,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap {
return try ruleEntriesForLabels(infos.map({ $0.label }),
startupOptions: startupOptions,
buildOptions: buildOptions,
projectGenBuildOptions: projectGenBuildOptions,
- prioritizeSwiftOption: prioritizeSwiftOption)
+ prioritizeSwiftOption: prioritizeSwiftOption,
+ features: features)
}
public func ruleEntriesForLabels(_ labels: [BuildLabel],
startupOptions: TulsiOption,
buildOptions: TulsiOption,
projectGenBuildOptions: TulsiOption,
- prioritizeSwiftOption: TulsiOption) throws -> RuleEntryMap {
+ prioritizeSwiftOption: TulsiOption,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap {
do {
return try workspaceInfoExtractor.ruleEntriesForLabels(labels,
startupOptions: startupOptions,
buildOptions: buildOptions,
projectGenBuildOptions: projectGenBuildOptions,
- prioritizeSwiftOption: prioritizeSwiftOption)
+ prioritizeSwiftOption: prioritizeSwiftOption,
+ features: features)
} catch BazelWorkspaceInfoExtractorError.aspectExtractorFailed(let info) {
throw ExtractorError.ruleEntriesFailed(info)
}
diff --git a/src/TulsiGenerator/XcodeProjectGenerator.swift b/src/TulsiGenerator/XcodeProjectGenerator.swift
index a13fa8a..4fc6b88 100644
--- a/src/TulsiGenerator/XcodeProjectGenerator.swift
+++ b/src/TulsiGenerator/XcodeProjectGenerator.swift
@@ -495,11 +495,6 @@
}
}
- // Update this project's build settings with the latest feature flags.
- for featureFlag in bazelBuildSettingsFeatures {
- buildSettings[featureFlag] = "YES"
- }
-
if let genRunfiles = config.options[.GenerateRunfiles].commonValueAsBool, genRunfiles {
buildSettings["GENERATE_RUNFILES"] = "YES"
}
@@ -578,11 +573,15 @@
private func loadRuleEntryMap() throws -> RuleEntryMap {
do {
+ let features = BazelBuildSettingsFeatures.enabledFeatures(options: config.options,
+ workspaceRoot: workspaceRootURL.path,
+ bazelExecRoot: workspaceInfoExtractor.bazelExecutionRoot)
return try workspaceInfoExtractor.ruleEntriesForLabels(config.buildTargetLabels,
startupOptions: config.options[.BazelBuildStartupOptionsDebug],
buildOptions: config.options[.BazelBuildOptionsDebug],
projectGenBuildOptions: config.options[.BazelBuildOptionsProjectGenerationOnly],
- prioritizeSwiftOption: config.options[.ProjectPrioritizesSwift])
+ prioritizeSwiftOption: config.options[.ProjectPrioritizesSwift],
+ features: features)
} catch BazelWorkspaceInfoExtractorError.aspectExtractorFailed(let info) {
throw ProjectGeneratorError.labelAspectFailure(info)
}
@@ -952,9 +951,13 @@
let bazelSettingsProvider = workspaceInfoExtractor.bazelSettingsProvider
let bazelExecRoot = workspaceInfoExtractor.bazelExecutionRoot
+ let features = BazelBuildSettingsFeatures.enabledFeatures(options: config.options,
+ workspaceRoot: workspaceRootURL.path,
+ bazelExecRoot: bazelExecRoot)
let bazelBuildSettings = bazelSettingsProvider.buildSettings(bazel: config.bazelURL.path,
bazelExecRoot: bazelExecRoot,
options: config.options,
+ features: features,
buildRuleEntries: buildRuleEntries)
let bundle = Bundle(for: type(of: self))
diff --git a/src/TulsiGeneratorTests/BuildSettingsTests.swift b/src/TulsiGeneratorTests/BuildSettingsTests.swift
new file mode 100644
index 0000000..1d342e3
--- /dev/null
+++ b/src/TulsiGeneratorTests/BuildSettingsTests.swift
@@ -0,0 +1,160 @@
+// Copyright 2018 The Tulsi Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+import XCTest
+@testable import TulsiGenerator
+
+class BuildSettingsTests: XCTestCase {
+
+ func testBazelFlagsEmpty() {
+ XCTAssert(BazelFlags().isEmpty)
+ XCTAssertEqual(BazelFlags().toPython(""), "BazelFlags()")
+ }
+ func testBazelFlagsOperators() {
+ let a = BazelFlags(startupStr: "a b", buildStr: "x y")
+ let b = BazelFlags(startupStr: "c d", buildStr: "z 1")
+ let aExplicit = BazelFlags(startup: ["a", "b"], build: ["x", "y"])
+ let bExplicit = BazelFlags(startup: ["c", "d"], build: ["z", "1"])
+
+ XCTAssertEqual(a, aExplicit)
+ XCTAssertEqual(b, bExplicit)
+
+ let c = a + b
+ XCTAssertEqual(c.startup, ["a", "b", "c", "d"])
+ XCTAssertEqual(c.build, ["x", "y", "z", "1"])
+ XCTAssertNotEqual(c, b + a)
+ }
+ func testBazelFlagsPythonable() {
+ let startup = ["--startup-flag"]
+ let build = ["--build-flag"]
+ XCTAssertEqual(BazelFlags(startup: startup, build: build).toPython(""), """
+BazelFlags(
+ startup = [
+ '--startup-flag',
+ ],
+ build = [
+ '--build-flag',
+ ],
+)
+""")
+ }
+
+ func testBazelFlagsSetEmpty() {
+ XCTAssert(BazelFlagsSet().isEmpty)
+ XCTAssertEqual(BazelFlagsSet().toPython(""), "BazelFlagsSet()")
+ }
+ func testBazelFlagsSetInitializers() {
+ let basicFlagsSet = BazelFlagsSet(startupFlags: ["a"], buildFlags: ["b"])
+ let basicFlags = BazelFlags(startup: ["a"], build: ["b"])
+ XCTAssertEqual(basicFlagsSet.release, basicFlags)
+ XCTAssertEqual(basicFlagsSet.debug, basicFlags)
+ XCTAssertEqual(basicFlagsSet.getFlags(forDebug: true), basicFlagsSet.debug)
+ XCTAssertEqual(basicFlagsSet.getFlags(forDebug: false), basicFlagsSet.release)
+
+ let complexFlagSet = BazelFlagsSet(debug: BazelFlags(startup: ["a"], build: ["b"]),
+ release: BazelFlags(startup: ["x"], build: ["y"]),
+ common: BazelFlags(startup: ["1"], build: ["2"]))
+ XCTAssertEqual(complexFlagSet.debug, BazelFlags(startup: ["a", "1"], build: ["b", "2"]))
+ XCTAssertEqual(complexFlagSet.release, BazelFlags(startup: ["x", "1"], build: ["y", "2"]))
+ }
+ func testBazelFlagsSetPythonable() {
+ let basicFlagsSet = BazelFlagsSet(startupFlags: ["a"], buildFlags: ["b"])
+ XCTAssertEqual(basicFlagsSet.toPython(""), """
+BazelFlagsSet(
+ flags = BazelFlags(
+ startup = [
+ 'a',
+ ],
+ build = [
+ 'b',
+ ],
+ ),
+)
+""")
+ let complexFlagSet = BazelFlagsSet(debug: BazelFlags(startup: ["a"], build: ["b"]),
+ release: BazelFlags(startup: ["x"], build: ["y"]),
+ common: BazelFlags(startup: ["1"], build: ["2"]))
+ XCTAssertEqual(complexFlagSet.toPython(""), """
+BazelFlagsSet(
+ debug = BazelFlags(
+ startup = [
+ 'a',
+ '1',
+ ],
+ build = [
+ 'b',
+ '2',
+ ],
+ ),
+ release = BazelFlags(
+ startup = [
+ 'x',
+ '1',
+ ],
+ build = [
+ 'y',
+ '2',
+ ],
+ ),
+)
+""")
+ }
+
+ func testBazelBuildSettingsPythonable() {
+ let bazel = "/path/to/bazel"
+ let bazelExecRoot = "__MOCK_EXEC_ROOT__"
+ let swiftTargets: Set<String> = [
+ "//dir/swiftTarget:swiftTarget",
+ "//dir/nested/depOnswift:depOnswift"
+ ]
+ let cacheAffecting = BazelFlagsSet(startupFlags: ["--nocacheStartup"],
+ buildFlags: ["--nocacheBuild"])
+ let cacheSafe = BazelFlagsSet(startupFlags: ["--cacheSafeStartup"],
+ buildFlags: ["--cacheSafeBuild"])
+ let swift = BazelFlagsSet(buildFlags: ["--swift-only"])
+ let nonSwift = BazelFlagsSet(startupFlags: ["--non-swift-only"])
+ let projDefaults = BazelFlagsSet()
+ let projTargetFlags = [
+ "//dir/some/customized:target": BazelFlagsSet(buildFlags: ["a", "b"]),
+ ]
+ let swiftFeatures = [BazelSettingFeature.DebugPathNormalization.stringValue]
+ let nonSwiftFeatures = [BazelSettingFeature.DirectDebugPrefixMap("", "").stringValue]
+ let settings = BazelBuildSettings(bazel: bazel,
+ bazelExecRoot: bazelExecRoot,
+ swiftTargets: swiftTargets,
+ tulsiCacheAffectingFlagsSet: cacheAffecting,
+ tulsiCacheSafeFlagSet: cacheSafe,
+ tulsiSwiftFlagSet: swift,
+ tulsiNonSwiftFlagSet: nonSwift,
+ swiftFeatures: swiftFeatures,
+ nonSwiftFeatures: nonSwiftFeatures,
+ projDefaultFlagSet: projDefaults,
+ projTargetFlagSets: projTargetFlags)
+ XCTAssertEqual(settings.toPython(""), """
+BazelBuildSettings(
+ '\(bazel)',
+ '\(bazelExecRoot)',
+ \(swiftTargets.toPython(" ")),
+ \(cacheAffecting.toPython(" ")),
+ \(cacheSafe.toPython(" ")),
+ \(swift.toPython(" ")),
+ \(nonSwift.toPython(" ")),
+ \(swiftFeatures.toPython(" ")),
+ \(nonSwiftFeatures.toPython(" ")),
+ \(projDefaults.toPython(" ")),
+ \(projTargetFlags.toPython(" ")),
+)
+""")
+ }
+}
diff --git a/src/TulsiGeneratorTests/MockWorkspaceInfoExtractor.swift b/src/TulsiGeneratorTests/MockWorkspaceInfoExtractor.swift
index 6e9e01b..fe5d25b 100644
--- a/src/TulsiGeneratorTests/MockWorkspaceInfoExtractor.swift
+++ b/src/TulsiGeneratorTests/MockWorkspaceInfoExtractor.swift
@@ -16,15 +16,15 @@
@testable import TulsiGenerator
class MockBazelSettingsProvider: BazelSettingsProviderProtocol {
- func tulsiFlags(hasSwift: Bool) -> BazelFlagsSet {
+ func tulsiFlags(hasSwift: Bool, features: Set<BazelSettingFeature>) -> BazelFlagsSet {
return BazelFlagsSet()
}
- func optionsBasedFlags(_ options: TulsiOptionSet) -> BazelFlagsSet {
- return BazelFlagsSet()
- }
-
- func buildSettings(bazel: String, bazelExecRoot: String, options: TulsiOptionSet, buildRuleEntries: Set<RuleEntry>) -> BazelBuildSettings {
+ func buildSettings(bazel: String,
+ bazelExecRoot: String,
+ options: TulsiOptionSet,
+ features: Set<BazelSettingFeature>,
+ buildRuleEntries: Set<RuleEntry>) -> BazelBuildSettings {
return BazelBuildSettings(bazel: bazel,
bazelExecRoot: bazelExecRoot,
swiftTargets: [],
@@ -32,6 +32,8 @@
tulsiCacheSafeFlagSet: BazelFlagsSet(),
tulsiSwiftFlagSet: BazelFlagsSet(),
tulsiNonSwiftFlagSet: BazelFlagsSet(),
+ swiftFeatures: [],
+ nonSwiftFeatures: [],
projDefaultFlagSet: BazelFlagsSet(),
projTargetFlagSets: [:])
}
@@ -49,6 +51,7 @@
var bazelURL = URL(fileURLWithPath: "")
var bazelBinPath = "bazel-bin"
var bazelExecutionRoot = "/private/var/tmp/_bazel_localhost/1234567890abcdef1234567890abcdef/execroot/workspace_dir"
+ var workspaceRootURL = URL(fileURLWithPath: "")
func extractRuleInfoFromProject(_ project: TulsiProject) -> [RuleInfo] {
return []
@@ -58,7 +61,8 @@
startupOptions: TulsiOption,
buildOptions: TulsiOption,
projectGenBuildOptions: TulsiOption,
- prioritizeSwiftOption: TulsiOption) throws -> RuleEntryMap {
+ prioritizeSwiftOption: TulsiOption,
+ features: Set<BazelSettingFeature>) throws -> RuleEntryMap {
invalidLabels.removeAll(keepingCapacity: true)
let ret = RuleEntryMap()
for label in labels {
diff --git a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
index 2b2ae87..25b3242 100644
--- a/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
+++ b/src/TulsiGeneratorTests/PBXTargetGeneratorTests.swift
@@ -335,7 +335,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -372,7 +371,6 @@
"PRODUCT_NAME": rule2TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule2BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule2TargetName,
@@ -450,7 +448,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -491,7 +488,6 @@
"SDKROOT": "iphoneos",
"TEST_HOST": "$(BUILT_PRODUCTS_DIR)/\(rule1TargetName).app/\(rule1TargetName)",
"TULSI_BUILD_PATH": rule2BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -564,7 +560,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -605,7 +600,6 @@
"TEST_TARGET_NAME": rule1TargetName,
"TULSI_BUILD_PATH": rule2BuildPath,
"TULSI_TEST_RUNNER_ONLY": "YES",
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule2TargetName,
@@ -682,7 +676,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "macosx",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -723,7 +716,6 @@
"SDKROOT": "macosx",
"TEST_HOST": "$(BUILT_PRODUCTS_DIR)/\(rule1TargetName).app/Contents/MacOS/\(rule1TargetName)",
"TULSI_BUILD_PATH": rule2BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -801,7 +793,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "macosx",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -841,7 +832,6 @@
"SDKROOT": "macosx",
"TEST_TARGET_NAME": rule1TargetName,
"TULSI_BUILD_PATH": rule2BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -909,7 +899,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "macosx",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -979,7 +968,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "macosx",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -1057,7 +1045,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -1099,7 +1086,6 @@
"SDKROOT": "iphoneos",
"TEST_HOST": "$(BUILT_PRODUCTS_DIR)/\(rule1TargetName).app/\(rule1TargetName)",
"TULSI_BUILD_PATH": testRuleBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -1187,7 +1173,6 @@
"SDKROOT": "iphoneos",
"TEST_HOST": "$(BUILT_PRODUCTS_DIR)/\(testHostTargetName).app/\(testHostTargetName)",
"TULSI_BUILD_PATH": testRulePackage,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -1275,7 +1260,6 @@
"SDKROOT": "iphoneos",
"TEST_HOST": "$(BUILT_PRODUCTS_DIR)/\(testHostTargetName).app/\(testHostTargetName)",
"TULSI_BUILD_PATH": testRulePackage,
- "TULSI_SWIFT_DEPENDENCY": "YES",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -1357,7 +1341,6 @@
"PRODUCT_NAME": rule1TargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: rule1TargetName,
@@ -1398,7 +1381,6 @@
"SDKROOT": "iphoneos",
"TEST_TARGET_NAME": rule1TargetName,
"TULSI_BUILD_PATH": testRuleBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
"TULSI_TEST_RUNNER_ONLY": "YES",
]
let expectedTarget = TargetDefinition(
@@ -1523,7 +1505,6 @@
"PRODUCT_NAME": testRuleTargetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": testRuleBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
var testRunnerExpectedBuildSettings = expectedBuildSettings
testRunnerExpectedBuildSettings["DEBUG_INFORMATION_FORMAT"] = "dwarf"
@@ -1591,7 +1572,6 @@
"PRODUCT_NAME": "test-test1-SameName",
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule1BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: "test-test1-SameName",
@@ -1628,7 +1608,6 @@
"PRODUCT_NAME": "test-test2-SameName",
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": rule2BuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: "test-test2-SameName",
@@ -1692,7 +1671,6 @@
"PRODUCT_NAME": targetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": buildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: targetName,
@@ -1755,7 +1733,6 @@
"PRODUCT_NAME": bundleName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": buildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: targetName,
@@ -1847,7 +1824,6 @@
"SDKROOT": "iphoneos",
"IPHONEOS_DEPLOYMENT_TARGET": "9.0",
"TULSI_BUILD_PATH": appBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: appTargetName,
@@ -1886,7 +1862,6 @@
"SDKROOT": "watchos",
"WATCHOS_DEPLOYMENT_TARGET": "2.0",
"TULSI_BUILD_PATH": watchAppBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: watchAppTargetName,
@@ -1925,7 +1900,6 @@
"SDKROOT": "watchos",
"WATCHOS_DEPLOYMENT_TARGET": "2.0",
"TULSI_BUILD_PATH": watchExtBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: watchExtTargetName,
@@ -2014,7 +1988,6 @@
"SDKROOT": "macosx",
"MACOSX_DEPLOYMENT_TARGET": "10.12",
"TULSI_BUILD_PATH": appBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: appTargetName,
@@ -2053,7 +2026,6 @@
"SDKROOT": "macosx",
"MACOSX_DEPLOYMENT_TARGET": "10.12",
"TULSI_BUILD_PATH": macAppExtBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: macAppExtTargetName,
@@ -2092,7 +2064,6 @@
"SDKROOT": "macosx",
"MACOSX_DEPLOYMENT_TARGET": "10.12",
"TULSI_BUILD_PATH": macCLIAppBuildPath,
- "TULSI_SWIFT_DEPENDENCY": "NO",
]
let expectedTarget = TargetDefinition(
name: macCLIAppTargetName,
@@ -2578,7 +2549,6 @@
"PRODUCT_NAME": targetName,
"SDKROOT": "iphoneos",
"TULSI_BUILD_PATH": package,
- "TULSI_SWIFT_DEPENDENCY": "YES",
]
let expectedTarget = TargetDefinition(
name: "TestTarget",