I have added my own build rule to Xcode, to compile a custom type of file. Let's call it .foo
.
I need to be able to specify that file A should be compiled before file B (since B depends on A). I have already written the logic to calculate these dependencies in a Run Script build phase, which runs before the Compile Sources phase. I can guarantee that there are no cycles (or if there are, it's ok for the build to fail).
How do I tell Xcode about these file dependencies for .foo
files, so that it compiles them in the right order?
Things I've tried:
- outputting a "discovered dependency file" for each
.foo
file, into the derived sources directory, then adding it to my.foo
build rule. I believe the syntax of the file should beB.foo: A.foo
(indicating that A must be compiled before B). I've tried it with both just filenames and with full paths. Xcode is finding the file, but does not seem to act upon it. - Outputting an
xcfilelist
for each.foo
file. This one I can't get to work -- in the "Input file lists" section of my.foo
rule, Xcode doesn't seem to want to expand any build variables that refer to the current file. For example, if I add an item$(DERIVED_SOURCES_DIR)/$(INPUT_FILE_NAME).deps
to the "input file lists" section, Xcode will expand "DERIVED_SOURCES_DIR" but will not expand "INPUT_FILE_NAME". From this I conclude that you can't have a per-file input file list, you can only have one single list for the whole.foo
build rule. Is this assumption correct?
What am I missing? There must be a way of telling Xcode about file dependencies, right?
Specific questions about .d
files:
In a "discovered dependency file" (i.e. a .d
file), as I understand it the syntax is <target>: <dep> <dep> <dep>
.
- Should the
target
be a full path or just a filename? - Should the
target
refer to my.foo
file (the thing I'm building, inside my source folder), or my.foo.out
file (the thing it builds, inside my derived files folder)? - The deps, i.e. the things that need to be built before the target: same question regarding full path, and do they refer to the source or the built output?
I have looked in Xcode's build timeline, and all my .foo
files are building in parallel, it doesn't seem to be paying attention to anything I put in the .d
files. So I suspect I'm getting the syntax wrong somehow.
I have added my own build rule to Xcode, to compile a custom type of file. Let's call it .foo
.
I need to be able to specify that file A should be compiled before file B (since B depends on A). I have already written the logic to calculate these dependencies in a Run Script build phase, which runs before the Compile Sources phase. I can guarantee that there are no cycles (or if there are, it's ok for the build to fail).
How do I tell Xcode about these file dependencies for .foo
files, so that it compiles them in the right order?
Things I've tried:
- outputting a "discovered dependency file" for each
.foo
file, into the derived sources directory, then adding it to my.foo
build rule. I believe the syntax of the file should beB.foo: A.foo
(indicating that A must be compiled before B). I've tried it with both just filenames and with full paths. Xcode is finding the file, but does not seem to act upon it. - Outputting an
xcfilelist
for each.foo
file. This one I can't get to work -- in the "Input file lists" section of my.foo
rule, Xcode doesn't seem to want to expand any build variables that refer to the current file. For example, if I add an item$(DERIVED_SOURCES_DIR)/$(INPUT_FILE_NAME).deps
to the "input file lists" section, Xcode will expand "DERIVED_SOURCES_DIR" but will not expand "INPUT_FILE_NAME". From this I conclude that you can't have a per-file input file list, you can only have one single list for the whole.foo
build rule. Is this assumption correct?
What am I missing? There must be a way of telling Xcode about file dependencies, right?
Specific questions about .d
files:
In a "discovered dependency file" (i.e. a .d
file), as I understand it the syntax is <target>: <dep> <dep> <dep>
.
- Should the
target
be a full path or just a filename? - Should the
target
refer to my.foo
file (the thing I'm building, inside my source folder), or my.foo.out
file (the thing it builds, inside my derived files folder)? - The deps, i.e. the things that need to be built before the target: same question regarding full path, and do they refer to the source or the built output?
I have looked in Xcode's build timeline, and all my .foo
files are building in parallel, it doesn't seem to be paying attention to anything I put in the .d
files. So I suspect I'm getting the syntax wrong somehow.
2 Answers
Reset to default 0I’ve dealt with this before when adding a custom build rule in Xcode. Getting the file dependencies to work took some experimenting, but here’s what finally worked for me:
1. Use Absolute Paths in the .d Files
Both the target (the file you’re building) and its dependencies need to have full absolute paths, not just filenames or relative paths.
2. Target Should Be the Output File
In the.d file, the target must refer to the output of your build rule (e.g., A.foo.out), not the source file (A.foo).
Example:
/path/to/DerivedData/B.foo.out: /path/to/DerivedData/A.foo.out
This informs Xcode that B.foo.out is dependent on A.foo.out.
3. Inform Xcode About the.d File
In your build rule settings:
Add the.d file under Output Files
Example: $(DERIVED_SOURCES_DIR)/$(INPUT_FILE_BASE).d
Mark the box that indicates it's a dependency file.
4. Create Clean Build
Do a clean build after having this set up. Xcode caching can conceal problems otherwise.
In Short:
Use absolute paths.
Targets and dependencies are output files, not sources.
Register the.d files correctly in the build rule.
This made Xcode compile my files in the correct order. Hope this helps!
Generate .d Files with Absolute Paths
In your Run Script phase, output a .d file for each .foo file using absolute paths to the output files (not source files). For example, if B.foo depends on A.foo:
CollapseWrapCopy
/path/to/DerivedData/.../B.foo.out: /path/to/DerivedData/.../A.foo.out
Use build variables like $(DERIVED_FILE_DIR) to compute paths dynamically, e.g.:
bash
CollapseWrapCopy
echo "$(DERIVED_FILE_DIR)/B.foo.out: $(DERIVED_FILE_DIR)/A.foo.out" > "$(DERIVED_SOURCES_DIR)/B.d"
Configure the .foo Build Rule
In your custom build rule for *.foo files:
Output Files:
Add the compiled output: $(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).foo.out
Add the .d file: $(DERIVED_SOURCES_DIR)/$(INPUT_FILE_BASE).d
Check “Use Discovered Dependency File” and set it to $(DERIVED_SOURCES_DIR)/$(INPUT_FILE_BASE).d.
Ensure your script compiles $(INPUT_FILE_PATH) to $(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).foo.out.
Ensure Proper Build Order
Since your Run Script runs before Compile Sources, it should generate the .d files in time for the build rule (which runs during Compile Sources). Verify this in the Build Phases tab.
Clean and Test
Do a Clean Build Folder (Cmd+Shift+K) to clear caches. Check the build timeline to confirm A.foo compiles before B.foo.
Xcode respects .d files when they’re tied to a build rule’s output and use absolute paths to output files. Previous (e.g., source-to-source deps like B.foo: A.foo) didn’t work because Xcode needs the dependency chain based on compiled outputs.