Skip to content

Commit 156b8f3

Browse files
committed
feat(ios): support Swift package macros
1 parent c24c682 commit 156b8f3

2 files changed

Lines changed: 57 additions & 4 deletions

File tree

lib/services/ios/xcodebuild-args-service.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,11 +167,17 @@ export class XcodebuildArgsService implements IXcodebuildArgsService {
167167
// Introduced in Xcode 14+
168168
// ref: https://forums.swift.org/t/telling-xcode-14-beta-4-to-trust-build-tool-plugins-programatically/59305/5
169169
const skipPackageValidation = "-skipPackagePluginValidation";
170-
170+
// Introduced in Xcode 15+ to trust Swift macros (compiler plugins)
171+
// non-interactively. Required for SPM packages that ship macros
172+
// (e.g. apple/RealityKitScripting), otherwise the build fails with:
173+
// "Macro '...' from package '...' must be enabled before it can be used"
174+
// ref: https://developer.apple.com/documentation/xcode/writing-swift-macros
175+
const skipMacroValidation = "-skipMacroValidation";
171176
const extraArgs: string[] = [
172177
"-scheme",
173178
projectData.projectName,
174179
skipPackageValidation,
180+
skipMacroValidation,
175181
];
176182

177183
const BUILD_SETTINGS_FILE_PATH = path.join(
@@ -187,6 +193,22 @@ export class XcodebuildArgsService implements IXcodebuildArgsService {
187193
// references: https://medium.com/@iostechset/why-cocoapods-eats-app-icons-79fe729808d4
188194
// https://github.com/CocoaPods/CocoaPods/issues/7003
189195

196+
// Xcode 26 makes Swift "explicitly built modules" the default. A
197+
// regression there prevents macro/compiler-plugin SPM targets from
198+
// resolving their swift-syntax module dependencies, failing with:
199+
// "Unable to resolve module dependency: 'SwiftSyntax'" (and SwiftParser,
200+
// SwiftSyntaxMacros, SwiftCompilerPlugin, SwiftDiagnostics).
201+
// Passed as a command-line build setting so it overrides ALL targets,
202+
// including the package targets we don't control.
203+
// ref: https://forums.swift.org/t/xcode-26-unable-to-find-module-dependency/80516
204+
const explicitModulesProperty = "SWIFT_ENABLE_EXPLICIT_MODULES";
205+
const explicitModulesValue =
206+
this.$xcconfigService.readPropertyValue(
207+
BUILD_SETTINGS_FILE_PATH,
208+
explicitModulesProperty,
209+
) || "NO";
210+
extraArgs.push(`${explicitModulesProperty}=${explicitModulesValue}`);
211+
190212
const deployTargetProperty = "IPHONEOS_DEPLOYMENT_TARGET";
191213
const deployTargetVersion = this.$xcconfigService.readPropertyValue(
192214
BUILD_SETTINGS_FILE_PATH,

test/services/ios/xcodebuild-args-service.ts

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ function createTestInjector(data: {
1111
logLevel: string;
1212
hasProjectWorkspace: boolean;
1313
connectedDevices?: any[];
14+
buildXcconfigContent?: string;
1415
}): IInjector {
1516
const injector = new Yok();
1617
injector.register("devicePlatformsConstants", DevicePlatformsConstants);
@@ -19,8 +20,11 @@ function createTestInjector(data: {
1920
getDevicesForPlatform: () => data.connectedDevices || [],
2021
});
2122
injector.register("fs", {
22-
exists: () => data.hasProjectWorkspace,
23-
readText: () => "",
23+
exists: (filePath: string) =>
24+
filePath.endsWith("build.xcconfig")
25+
? data.buildXcconfigContent !== undefined
26+
: data.hasProjectWorkspace,
27+
readText: () => data.buildXcconfigContent || "",
2428
});
2529
injector.register("logger", {
2630
getLevel: () => data.logLevel,
@@ -49,7 +53,13 @@ function getCommonArgs() {
4953
}
5054

5155
function getXcodeProjectArgs(data?: { hasProjectWorkspace: boolean }) {
52-
const extraArgs = ["-scheme", projectName, "-skipPackagePluginValidation"];
56+
const extraArgs = [
57+
"-scheme",
58+
projectName,
59+
"-skipPackagePluginValidation",
60+
"-skipMacroValidation",
61+
"SWIFT_ENABLE_EXPLICIT_MODULES=NO",
62+
];
5363
return data && data.hasProjectWorkspace
5464
? [
5565
"-workspace",
@@ -72,6 +82,27 @@ function getBuildLoggingArgs(logLevel: string): string[] {
7282
}
7383

7484
describe("xcodebuildArgsService", () => {
85+
describe("getXcodeProjectArgs", () => {
86+
it("should allow SWIFT_ENABLE_EXPLICIT_MODULES to be overridden from build.xcconfig", () => {
87+
const injector = createTestInjector({
88+
logLevel: "INFO",
89+
hasProjectWorkspace: false,
90+
buildXcconfigContent: "SWIFT_ENABLE_EXPLICIT_MODULES = YES",
91+
});
92+
const xcodebuildArgsService: IXcodebuildArgsService = injector.resolve(
93+
"xcodebuildArgsService",
94+
);
95+
96+
const actualArgs = xcodebuildArgsService.getXcodeProjectArgs(
97+
<any>{ projectRoot, normalizedPlatformName },
98+
<any>{ projectName, appResourcesDirectoryPath },
99+
);
100+
101+
assert.include(actualArgs, "SWIFT_ENABLE_EXPLICIT_MODULES=YES");
102+
assert.notInclude(actualArgs, "SWIFT_ENABLE_EXPLICIT_MODULES=NO");
103+
});
104+
});
105+
75106
describe("getBuildForSimulatorArgs", () => {
76107
_.each([true, false], (hasProjectWorkspace) => {
77108
_.each(["INFO", "TRACE"], (logLevel) => {

0 commit comments

Comments
 (0)