Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions test/internal/custom_toolchain/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# buildifier: disable=bzl-visibility
load("//xcodeproj/internal:custom_toolchain.bzl", "custom_toolchain")

# Example swiftc override for testing
filegroup(
name = "test_swiftc",
srcs = ["test_swiftc.sh"],
visibility = ["//visibility:public"],
)

# Test target for custom_toolchain
custom_toolchain(
name = "test_toolchain",
overrides = {
":test_swiftc": "swiftc",
},
toolchain_name = "TestCustomToolchain",
)

# Add a simple test rule that depends on the toolchain
sh_test(
name = "custom_toolchain_test",
srcs = ["custom_toolchain_test.sh"],
args = ["$(location :test_toolchain)"],
data = [":test_toolchain"],
)
46 changes: 46 additions & 0 deletions test/internal/custom_toolchain/custom_toolchain_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#!/bin/bash

set -euo pipefail

# The first argument should be the path to the toolchain directory
TOOLCHAIN_DIR="$1"

echo "Verifying toolchain at: $TOOLCHAIN_DIR"

# Check that the toolchain directory exists
if [[ ! -d "$TOOLCHAIN_DIR" ]]; then
echo "ERROR: Toolchain directory does not exist: $TOOLCHAIN_DIR"
exit 1
fi

# Check that ToolchainInfo.plist exists
if [[ ! -f "$TOOLCHAIN_DIR/ToolchainInfo.plist" ]]; then
echo "ERROR: ToolchainInfo.plist not found in toolchain"
exit 1
fi

# Check for correct identifiers in the plist
if ! grep -q "TestCustomToolchain" "$TOOLCHAIN_DIR/ToolchainInfo.plist"; then
echo "ERROR: ToolchainInfo.plist doesn't contain TestCustomToolchain"
exit 1
fi

# Check that our custom swiftc is properly linked/copied
if [[ ! -f "$TOOLCHAIN_DIR/usr/bin/swiftc" ]]; then
echo "ERROR: swiftc not found in toolchain"
exit 1
fi

# Ensure swiftc is executable
if [[ ! -x "$TOOLCHAIN_DIR/usr/bin/swiftc" ]]; then
echo "ERROR: swiftc is not executable"
exit 1
fi

# Test if the swiftc actually runs
if ! "$TOOLCHAIN_DIR/usr/bin/swiftc" --version > /dev/null 2>&1; then
echo "WARN: swiftc doesn't run correctly, but this is expected in tests"
fi

echo "Custom toolchain validation successful!"
exit 0
11 changes: 11 additions & 0 deletions test/internal/custom_toolchain/test_swiftc.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#!/bin/bash

# This is a test script that simulates a custom Swift compiler
# It will be used as an override in the custom toolchain

# Print inputs for debugging
echo "Custom swiftc called with args: $@" >&2

# In a real override, you would do something meaningful with the args
# For testing, just exit successfully
exit 0
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,8 @@ def write_pbxproj_prefix_test_suite(name):
"some/path/to/index_import",
# resolvedRepositoriesFile
"some/path/to/resolved_repositories_file",
# customToolchainID
"com.rules_xcodeproj.BazelRulesXcodeProj.16B40",
# minimumXcodeVersion
"14.2.1",
# importIndexBuildIndexstores
Expand Down Expand Up @@ -342,6 +344,8 @@ def write_pbxproj_prefix_test_suite(name):
"some/path/to/index_import",
# resolvedRepositoriesFile
"some/path/to/resolved_repositories_file",
# customToolchainID
"com.rules_xcodeproj.BazelRulesXcodeProj.16B40",
# minimumXcodeVersion
"14.2.1",
# importIndexBuildIndexstores
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ extension Generator.CreateBuildFileObject {
settings = #"settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; "#
case .compileStub, .source:
settings = ""
case .product, .watchKitExtension:
case .product, .watchKitExtension, .framework:
// Handled in `CreateProductBuildFileObject` and
// `CreateProductObject`
preconditionFailure()
Expand Down
2 changes: 2 additions & 0 deletions tools/generators/lib/PBXProj/src/BuildPhase.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ public enum BuildPhase {
case sources
case copySwiftGeneratedHeader
case embedAppExtensions
case linkBinaryWithLibraries

public var name: String {
switch self {
Expand All @@ -16,6 +17,7 @@ Copy Bazel Outputs / Generate Bazel Dependencies (Index Build)
case .sources: return "Sources"
case .copySwiftGeneratedHeader: return "Copy Swift Generated Header"
case .embedAppExtensions: return "Embed App Extensions"
case .linkBinaryWithLibraries: return "Frameworks"
}
}
}
13 changes: 13 additions & 0 deletions tools/generators/lib/PBXProj/src/Identifiers.swift
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,9 @@ FF01000000000000000001\#(byteHexStrings[index]!) \#
/// The product reference for a target.
case product = "P"

/// The framework reference for a target in libraries to link build phase.
case framework = "f"

/// A normal file referenced in a `BuildPhase.sources` build phase.
case source = "0"

Expand Down Expand Up @@ -186,6 +189,14 @@ FF01000000000000000001\#(byteHexStrings[index]!) \#
return #"""
\#(subIdentifier.shard)00\#(subIdentifier.hash)0000000000FF \#
/* \#(subIdentifier.path.path) */
"""#

case .framework:
let basename = subIdentifier.path.path
.split(separator: "/").last!
return #"""
\#(subIdentifier.shard)A8\#(subIdentifier.hash) \#
/* \#(basename) in Frameworks */
"""#

case .compileStub:
Expand Down Expand Up @@ -535,6 +546,7 @@ private extension Identifiers.BuildFiles.FileType {
var buildPhase: BuildPhase {
switch self {
case .product: preconditionFailure() // product reference used as build file
case .framework: return .linkBinaryWithLibraries
case .source: return .sources
case .nonArcSource: return .sources
case .compileStub: return .sources
Expand Down Expand Up @@ -566,6 +578,7 @@ extension BuildPhase {
case .sources: return "06"
case .copySwiftGeneratedHeader: return "07"
case .embedAppExtensions: return "08"
case .linkBinaryWithLibraries: return "09"
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,24 @@ extension Generator.CalculatePlatformVariantBuildSettings {
)
}

buildSettings.append(
.init(
key: "LIBRARY_SEARCH_PATHS",
value: (
platformVariant.librarySearchPaths
.map {
let path = $0.path.split(separator: "/").dropFirst().joined(separator: "/")
return "\"$(BAZEL_OUT)/\(path)\""
} + [
"\"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/16/lib/darwin\""
]
)
.sorted()
.joined(separator: " ")
.pbxProjEscaped
)
)

buildSettings.append(contentsOf: platformVariant.buildSettingsFromFile)

return buildSettings
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ extension Generator.CalculatePlatformVariants {
) {
var srcs: [[BazelPath]] = []
var nonArcSrcs: [[BazelPath]] = []
var librariesToLinkPaths: [[BazelPath]] = []
var excludableFilesKeysWithValues: [(TargetID, Set<BazelPath>)] = []
for id in ids {
let targetArguments = try targetArguments.value(
Expand All @@ -68,6 +69,7 @@ extension Generator.CalculatePlatformVariants {

srcs.append(targetArguments.srcs)
nonArcSrcs.append(targetArguments.nonArcSrcs)
librariesToLinkPaths.append(targetArguments.librariesToLinkPaths)

excludableFilesKeysWithValues.append(
(
Expand Down Expand Up @@ -134,14 +136,16 @@ extension Generator.CalculatePlatformVariants {
.flatMap { unitTestHosts[$0] },
dSYMPathsBuildSetting:
targetArguments.dSYMPathsBuildSetting.isEmpty ?
nil : targetArguments.dSYMPathsBuildSetting
nil : targetArguments.dSYMPathsBuildSetting,
librarySearchPaths: Set(targetArguments.librarySearchPaths)
)
)
}

let consolidatedInputs = Target.ConsolidatedInputs(
srcs: consolidatePaths(srcs),
nonArcSrcs: consolidatePaths(nonArcSrcs)
nonArcSrcs: consolidatePaths(nonArcSrcs),
librariesToLinkPaths: consolidatePaths(librariesToLinkPaths)
)

return (platformVariants, allConditionalFiles, consolidatedInputs)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ private extension Platform {
}
}

private extension String {
extension String {
var quoteIfNeeded: String {
guard !contains(" ") else {
return #""\#(self)""#
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ extension Generator {
CreateEmbedAppExtensionsBuildPhaseObject
private let createProductBuildFileObject: CreateProductBuildFileObject
private let createSourcesBuildPhaseObject: CreateSourcesBuildPhaseObject
private let createLinkBinaryWithLibrariesBuildPhaseObject:
CreateLinkBinaryWithLibrariesBuildPhaseObject
private let createFrameworkObject: CreateFrameworkObject
private let createFrameworkBuildFileObject: CreateFrameworkBuildFileObject

private let callable: Callable

Expand All @@ -31,6 +35,10 @@ extension Generator {
CreateEmbedAppExtensionsBuildPhaseObject,
createProductBuildFileObject: CreateProductBuildFileObject,
createSourcesBuildPhaseObject: CreateSourcesBuildPhaseObject,
createLinkBinaryWithLibrariesBuildPhaseObject:
CreateLinkBinaryWithLibrariesBuildPhaseObject,
createFrameworkObject: CreateFrameworkObject,
createFrameworkBuildFileObject: CreateFrameworkBuildFileObject,
callable: @escaping Callable = Self.defaultCallable
) {
self.createBazelIntegrationBuildPhaseObject =
Expand All @@ -44,6 +52,9 @@ extension Generator {
createEmbedAppExtensionsBuildPhaseObject
self.createProductBuildFileObject = createProductBuildFileObject
self.createSourcesBuildPhaseObject = createSourcesBuildPhaseObject
self.createLinkBinaryWithLibrariesBuildPhaseObject = createLinkBinaryWithLibrariesBuildPhaseObject
self.createFrameworkObject = createFrameworkObject
self.createFrameworkBuildFileObject = createFrameworkBuildFileObject

self.callable = callable
}
Expand Down Expand Up @@ -86,7 +97,10 @@ extension Generator {
/*createEmbedAppExtensionsBuildPhaseObject:*/
createEmbedAppExtensionsBuildPhaseObject,
/*createProductBuildFileObject:*/ createProductBuildFileObject,
/*createSourcesBuildPhaseObject:*/ createSourcesBuildPhaseObject
/*createSourcesBuildPhaseObject:*/ createSourcesBuildPhaseObject,
/*createLinkBinaryWithLibrariesBuildPhaseObject:*/ createLinkBinaryWithLibrariesBuildPhaseObject,
/*createFrameworkObject:*/ createFrameworkObject,
/*createFrameworkBuildFileObject:*/ createFrameworkBuildFileObject
)
}
}
Expand Down Expand Up @@ -116,7 +130,11 @@ extension Generator.CreateBuildPhases {
_ createEmbedAppExtensionsBuildPhaseObject:
Generator.CreateEmbedAppExtensionsBuildPhaseObject,
_ createProductBuildFileObject: Generator.CreateProductBuildFileObject,
_ createSourcesBuildPhaseObject: Generator.CreateSourcesBuildPhaseObject
_ createSourcesBuildPhaseObject: Generator.CreateSourcesBuildPhaseObject,
_ createLinkBinaryWithLibrariesBuildPhaseObject:
Generator.CreateLinkBinaryWithLibrariesBuildPhaseObject,
_ createFrameworkObject: Generator.CreateFrameworkObject,
_ createFrameworkBuildFileObject: Generator.CreateFrameworkBuildFileObject
) -> (
buildPhases: [Object],
buildFileObjects: [Object],
Expand Down Expand Up @@ -144,7 +162,11 @@ extension Generator.CreateBuildPhases {
createEmbedAppExtensionsBuildPhaseObject:
Generator.CreateEmbedAppExtensionsBuildPhaseObject,
createProductBuildFileObject: Generator.CreateProductBuildFileObject,
createSourcesBuildPhaseObject: Generator.CreateSourcesBuildPhaseObject
createSourcesBuildPhaseObject: Generator.CreateSourcesBuildPhaseObject,
createLinkBinaryWithLibrariesBuildPhaseObject:
Generator.CreateLinkBinaryWithLibrariesBuildPhaseObject,
createFrameworkObject: Generator.CreateFrameworkObject,
createFrameworkBuildFileObject: Generator.CreateFrameworkBuildFileObject
) -> (
buildPhases: [Object],
buildFileObjects: [Object],
Expand Down Expand Up @@ -259,6 +281,48 @@ extension Generator.CreateBuildPhases {
)
}

let libs = consolidatedInputs.librariesToLinkPaths + [
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/16/lib/darwin/libclang_rt.iossim.a"
]
let librariesToLinkSubIdentifiers = libs.map { bazelPath in
return (
bazelPath,
createBuildFileSubIdentifier(
BazelPath(bazelPath.path.split(separator: "/").last.map(String.init)!),
type: .framework,
shard: shard
),
createBuildFileSubIdentifier(
bazelPath,
type: .framework,
shard: shard
)
)
}
librariesToLinkSubIdentifiers
.forEach { bazelPath, buildSubIdentifier, frameworkSubIdentifier in
buildFileObjects.append(
createFrameworkBuildFileObject(
frameworkSubIdentifier: frameworkSubIdentifier,
subIdentifier: buildSubIdentifier
)
)
buildFileObjects.append(
createFrameworkObject(
frameworkPath: bazelPath,
subIdentifier: frameworkSubIdentifier
)
)
}
buildPhases.append(
createLinkBinaryWithLibrariesBuildPhaseObject(
subIdentifier: identifier.subIdentifier,
librariesToLinkIdentifiers: librariesToLinkSubIdentifiers
.map { $0.1 }
.map { Identifiers.BuildFiles.id(subIdentifier: $0) }
)
)

return (buildPhases, buildFileObjects, buildFileSubIdentifiers)
}
}
Expand Down
Loading