1

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 be B.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>.

  1. Should the target be a full path or just a filename?
  2. 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)?
  3. 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 2

0

I’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!

Sign up to request clarification or add additional context in comments.

4 Comments

When you say "Mark the box that indicates it's a dependency file", where is this box? In my output files list there's nothing else in the column but the path. (I'm generating the .d file in a Run Script phase, not a build rule, fwiw). Or do you mean the "Use Discovered Dependency File" box -- I thought that was for the input .d file for the rule?
When I said "mark the box," I was referring to the "Use Discovered Dependency File" checkbox in the custom Build Rule setup. It's not available in a Run Script phase—Xcode only processes .d files automatically if you use a Build Rule and check that box. If you’re generating the .d file in a Run Script, Xcode won’t automatically use it unless it’s tied to a Build Rule.
But it's ok to generate the .d in a script phase, then use it in a build rule?
Yes, it's fine to generate the .d file in a script phase, as long as a later Build Rule consumes it and has "Use Discovered Dependency File" checked. Just make sure the .d file exists before the rule runs and uses correct paths.
0
  1. 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"

  2. 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.

  3. 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.

  4. 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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.