Xcode: What Is a Target and Scheme in Plain Language

Xcode: What is a target and scheme in plain language?

I've added in Workspace and Project too!

  • Workspace - Contains one or more projects. These projects usually relate to one another
  • Project - Contains code and resources, etc. (You'll be used to these!)
  • Target - Each project has one or more targets.
    • Each target defines a list of build settings for that project
    • Each target also defines a list of classes, resources, custom scripts etc to include/ use when building.
    • Targets are usually used for different distributions of the same project.
      • For example, my project has two targets, a "normal" build and an "office" build that has extra testing features and may contain several background music tracks and a button to change the track (as it currently does).
      • You'll be used to adding classes and resources to your default target as you add them.
      • You can pick and choose which classes / resources are added to which target.
        • In my example, I have a "DebugHandler" class that is added to my office build
      • If you add tests, this also adds a new target.
  • Scheme - A scheme defines what happens when you press "Build", "Test", "Profile", etc.
    • Usually, each target has at least one scheme
    • You can autocreate schemes for your targets by going to Scheme > Manage Schemes and pressing "Autocreate Schemes Now"

In Xcode, what exactly is a scheme?

From Xcode's Help:

scheme

A scheme is a collection of settings that specify the targets to build for a project, the build configuration to use, and the executable environment to use when the product is launched. When you open an existing project (or create a new one), Xcode automatically creates a scheme for each target. The default scheme is named after your project.

Here, "build configuration" is what you're calling "Debug" and "Release" above.

What are targets in Xcode?

It means the product you want to build. You may have multiple targets in a single project if you build different products from the same source code (e.g. an app, a framework and a unit test bundle). You may even have several targets of the same kind (e.g. two apps sharing the same code but branded differently).

Here you have only one target and by the way its icon looks it is an executable (an OS X command-line tool, probably).

This question might give you more details: Xcode: What is a target and scheme in plain language?


Actually, there's a whole lot of questions here answering your very question.

  • What exactly is an Target in Xcode?
  • What is the difference between Targets, Executables and Products in Xcode
  • Xcode Targets, projects and tests?

Some others might help you understand better the value you can get from several targets:

  • What is the meaning of separate settings for project/target in xcode?

How do I run a preferred target in Xcode?

If you have more than one app target, you have more than one scheme. If you have more than one scheme, you can pick a scheme from the scheme menu (at the top of the project window). Then when you run, that scheme will be what builds and runs (on the corresponding destination).

In this screen shot, I have two app targets and hence two schemes ("backgroundPlayer" and "interrupter"):

Sample Image

As you can see, "backgroundPlayer" is checked. So if I build and run now, I build and run "backgroundPlayer". But if I choose "interrupter", then it will be checked, so if I then build and run, I build and run "interrupter".

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.

Where do all the Project Name and Target Names appear to a user in an Xcode extension?

First, I'll define the following:

  • AppTarget: The Application's target, which was created when the new macOS application was created.
  • ExtensionTarget: The extension's target, which was created after adding the "Xcode Source Editor" target.

And, I'll assume you named the Application "MyApp" and the Extension "MyExtension".

This sets up a project with the following options:

  • AppTarget > info.plist:
    • CFBundleName = $(PRODUCT_NAME)
  • AppTarget > Build Settings:
    • Product Name = $(TARGET_NAME) (i.e. MyApp)
  • ExtensionTarget/info.plist:
    • CFBundleName = $(PRODUCT_NAME) (i.e. MyExtension)
    • CFBundleDisplayName = MyExtension

Here are all the places a user might see these names:

  • Application:

    • AppTarget/BuildSettings/ProductName

      This is the container .app the user installs/runs to get the extension.

  • System Preferences > Extensions:

    • AppTarget/BuildSettings/ProductName, in "Added Extensions".
    • AppTarget/BuildSettings/ProductName, underneath "Xcode Source Editor".
    • ExtensionTarget/info.plist/CFBundleDisplayName, in "Xcode Source Editor".
  • Xcode > Editor menu:

    • ExtensionTarget/info.plist/CFBundleName.

Some key things to note:

  • CFBundleName and CFBundleDisplayName for the ExtensionTarget appear in two different places, so they should probably be the same.
  • From the user's perspective, they just care about the extension. However, due to how extensions must be shipped with a .app, we must expose both an app and an extension to the user. They will therefore see both of those names in various places. You might want to keep these name consistent as well.
  • Attempting to modify AppTarget/info.plist/CFBundleName directly appears to have no effect in what the user sees. You must use the Product Name setting instead.


Related Topics



Leave a reply



Submit