I have a multi target project where every target relies on a built "web bundle" which is basically a collection of html, optimized images, and optimized javascript.
Right now that web bundle is built in a pre build step by running a script. The script takes awhile to run and outputs to a folder that is referenced into the project via a PBXFileReference which is then referenced in the Copy Bundle Resources step.
96516AC22BF928DD00576562 /* build */ = {isa = PBXFileReference; lastKnownFileType = folder; name = build; path = "../web-ui/build"; sourceTree = "<group>"; }
....
96516AC32BF928DD00576562 /* build in Resources */ = {isa = PBXBuildFile; fileRef = 96516AC22BF928DD00576562 /* build */; };
As a step, I wrote an aggregate target that can also run this script. I specified its input and output files and turned off sandboxing. It does exactly what I need it to. Critically it is ran based on dependency analysis. If I modify any file in web-ui it rebuilds, if I dont I can repeatedly build the aggregate target and it will not re-run the script. This is perfect.
A97590172E419CBA00741928 /* Build Web Bundle */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 12;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"$(SRCROOT)/xcodescripts/build-web-bundle.bash",
"$(SRCROOT)/web-ui/index.html",
"$(SRCROOT)/web-ui/vite-env.d.ts",
"$(SRCROOT)/web-ui/vite.config.ts",
"$(SRCROOT)/web-ui/tsconfig.json",
"$(SRCROOT)/web-ui/stats.html",
"$(SRCROOT)/web-ui/postcss.config.js",
"$(SRCROOT)/web-ui/package.json",
"$(SRCROOT)/web-ui/justfile",
"$(SRCROOT)/web-ui/src/",
);
name = "Build Web Bundle";
outputFileListPaths = (
);
outputPaths = (
"$(SRCROOT)/web-ui/build/",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "exec \"${SCRIPT_INPUT_FILE_0}\"\n";
};
You may notice I reference a src file. This is made possible via a flag USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES
which allows Xcode to check folder dependencies recursively.
The problem is that my other targets do not automatically recognize that they need to run the "WebBundle" aggregate target in order to update a resource they copy in their "Copy bundle resources" phase.
So I tried adding it as a Target Dependency.
A9DE685B2E41C9A8005EF4E0 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = A97590132E419C1200741928 /* WebBundle */;
targetProxy = A9DE685A2E41C9A8005EF4E0 /* PBXContainerItemProxy */;
};
Unfortunately this breaks whatever magic was allowing the script to be run only when there are web bundle changes. Every build it runs the "Build Web Bundle" script.
I think what I am missing is a way to specify in these other targets that a resource they are used to copying from the Xcode PBXFileReference is produced by the aggregate target. This way they can start to reason about the dependencies.
Other possibilities are that I should be building the web bundle to a separate location. Or that these references are somehow broken in another way. To be clear the folder format is as thus
project/
iOS/
client.xcodeproj
web-ui/
build/ (web bundle build is output here and referenced relatively)
src/
index.html (and other things)