How Does Xcode Find Implicit Target Dependencies

How does Xcode find implicit target dependencies?

This answer applies to Xcode 8.x, and I think for Xcode 9.0.

First off, you need to be sure that "Find Implicit Dependencies" is enabled in the the Build panel of the Scheme that you are attempting to build.

A target "A" can be made "implicitly" dependent on target "B" in two ways:

  1. Target A has a "Link Binary With Libraries" build phase that has a library in its list that has the same name as a Product of B. This product can either be in the same project or another project in the workspace. Note that I said "same name". Just because you chose libA.a from target A doesn't mean that implicit dependencies will build it if you have another libA.a product in a different target. See below for details.
  2. Target A has a "Copy Files Phase" that copies a file with a base name that matches a product of B. Normally a "Copy files" build phase cannot refer to a file that isn't in the same project as its target, but you can set up a dependency across projects if you create a dummy file for the "copy file" phase to copy that has the same name as a product of B. For example, if you have a workspace that contains two projects ProjectA and ProjectB. ProjectA has TargetA that creates libA.a, and ProjectB has TargetB that creates libB.a. TargetA could get TargetB to build libB.a by having a "fake" zero byte file as part of TargetA that happened to be named libB.a, and this would be sufficient to get libB.a made, even though the libB.a referred to in the "Copy Files" phase is a totally different file than the product output of the TargetB build. If you check the "Copy Only When Installing" box, Xcode won't actually perform the copy, but will still resolve the dependency. You can actually delete the fake file off your drive that you created solely to have something to put in the "Copy Files" phase (but you must leave it in your project).

So why would anyone ever want to do the horror that is "2"? I can come up with a couple of reasons.

  1. TargetA needs some some files copied/generated by TargetB, but TargetB doesn't generate a library to link to. You could probably work around this by having TargetB generate up a small dummy library, but that may be painful for other reasons.
  2. Let's say I had projectA, targetA and libA.a (and equivalents for project B, C and D), and libA.a depended on libB.a and libC.a which both needed libD.a to be built first (possibly some headers and/or sources generated). You could do it all using the "Link With Libraries" phase (aka solution #1) but in that case you would end up with two copies of the .o files in libD in the final linked version of libA. If you do this deep enough (eg a workspace that has 40 projects that have varying levels of dependencies on one another) you will quickly end up with huge library files with several identical .o files in them, and your link times will become horrific.

If you think these are contrived situations, I'm currently hitting both of them moving some legacy code from a series of explicit dependencies to implicit dependencies. Why am I moving to implicit dependencies? Because explicit dependencies in Xcode require project nesting, and once you get enough explicit dependencies, the project browser gets extremely slow, and you will see a lot of beachballs inside of Xcode for random things.

What happens if you happen to have two targets inside the same workspace that generate products with the same name and depend upon them from a third target? Implicit dependencies will pick one. It appears to do a match based on the base name of the product (so foo/bar.a and baz/bar.a are the same), and will pick the first one it finds.

How should I manage dependencies across projects in an Xcode workspace?

I’ve just set a test project up, pretty much as you describe in version 3, by creating a new workspace and dragging the two Xcode project into it, nested as shown.

You can delete the sibling project if you have it already.

Hitting build on this and it just works, as far as I can see.

Scheme Settings
Project Layout

I imagine there is internal path-confusion if you have two projects, and I’d be inclined to fiddle with location settings in "View"->"Utilities"->"File Inspector" and see what effect that has.

Sample Image
Sample Image

Another thing to try is to set your paths up in Xcode "Preferences…"->"Source Trees" and refer to them that way, as described here: Easy, Modular Code Sharing Across iPhone Apps: Static Libraries and Cross-Project References

HTH. Andy W.

How do you get implicit dependencies to work with workspaces in Xcode 4?

I have just spent the best part of two days building and rebuilding our project, struggling with just this very issue. Whilst I now have a project that builds and links correctly AND has working codesense I am not 100% happy with one of the steps as it seems to be a bit of a hack and certainly doesn't fit my concept of "Automatic implicit dependencies".

FWIW here are the steps I took:

  1. Create a new Workspace in Xcode.
  2. Add a new project to the workspace for your static library. You can also add an existing project, I found this to work too.
  3. Test that the library builds as expected.
  4. Add a new project to the workspace for your main project. Again I managed to add an existing one, but importantly it did not have any build settings already that linked to the library. If you add a new project its fairly easy to just add existing source files to it. My particular situation was complicated by a very large pre-existing SVN repository that I did not want to restructure.
  5. At this stage I am going to assume that your source code already contains imports of headers from the static library.
  6. In the build phases for the main project, expand the "link binary with libraries" section and click the + symbol. Select the target from your static library project.
  7. If you want at this stage you can build the main project to confirm that it fails as shown in the OP screen shots with "No such file..." errors for the header imports.
  8. Now this is the bit I don't really like. In your main project create a new group and call it Dependent Headers or whatever. Now in the project navigator drag any used headers from your static project to this new group. In the options pop up I just left it as the default settings.
  9. You may also need to link your main project with any dependent libraries used by your static library. For example my static library makes use of libxml2 and CFNetwork and even though my main project does not use them directly I had compile errors if I did not add them to the "link binary with libraries" build phase.
  10. Your main project should now (hopefully) build.

I really don't like steps 8 and 9. This really feels like XCode is not doing what it is advertised to do. However if and when it gets fixed at least these steps are fairly easy to back out so that it works correctly.

I think "implicit dependencies" should work without needing to go past step 6, maybe even step 5 but that might be a little bit too automagical for a lot of people's taste.

Target Dependency between two projects in the same workspace

I ran into something similar but with static libs.

  • Do what you did to build the framework, build your app (even if it fails, the framework should build)
  • Remove the reference to the framework in your app target's link build phase
  • Locate the built framework in the Finder (the one built by your app workspace).
  • drag/drop it into the app project that uses it. Notice that this time it appears with black color (not red)
  • click it, and make sure the Xcode inspector shows "relative to built products" (you may need to change it reference type), and that the path is just the myframework.framework.
  • check that it has been added to the app link phase (it should)
  • that's the one you can use in the copy/build phase.

Prevent Xcode from building subprojects every time

It would seem you have Xcode 4's "Find Implicit Dependencies" enabled. Note that this is enabled by default.

  • Product > Edit Scheme…
  • Build (in left column)
  • UNCHECK "Find Implicit Dependencies"

Xcode will then only build the dependencies which are out of date and specified as dependencies (or dependencies of a dependency).

If you find that is not the case, then you may want to investigate what causes the build to retrigger (e.g. generated sources, relinking against dependencies which needed to be rebuilt, etc.).

Xcode does not run test targets in the order specified in Target Dependencies

Target Dependencies specified in Build Phases determine the order in which Xcode builds targets.

To change the order in which Xcode runs test bundles in a Test action, you'll need to change scheme settings. Choose Product > Scheme > Edit Scheme... and select the Test action:

test action editor

In there you'll find a list of the test bundles built by your separate test targets ("Mac_Calc_Tests" and "SampleCalcTests" in the screenshot). To change the order tests run in, drag the bundles up and down to reorder the list.



Related Topics



Leave a reply



Submit