What the different between SRCROOT and PROJECT_DIR? - ios

In Xcode, we have to configure many paths in the Build Settings, then we will deal with the $(SRCROOT) and $(PROJECT_DIR) , But what the difference between them, can you show me an example, thx a lot.

Exchangeable in practice, while the documentation makes these subtle theoretical distinctions:
SRCROOT
Directory path. Identifies the directory containing the target’s source files: contains the path to the project file that defines the target.
SOURCE_ROOT is an undocumented alias to SRCROOT
PROJECT_DIR
Identifies the directory containing the project (.xcodeproj)
$(PROJECT_DIR)/build is used as the create the default value for:
Intermediate Build Files Path OBJROOT
Build Products Path SYMROOT
Typically these paths are not set per target, but are set per-project or per-user.
PROJECT_FILE_PATH
Identifies the project itself.
Equivalent to $(PROJECT_DIR)/$(PROJECT_NAME).xcodeproj
Conceptually different (#1 is about the project which defines the target while #2 is about the project independently of any target), they are always pointing to the same location since you are, in essence, always building a target.
References
Xcode 8.3 Build Settings reference
Xcode Build System Guide (Retired 2016-09-29)

SRCROOT & PROJECT_DIR are same macros have same effect.PROJECT_DIR makes more sense when talking about frameworks.

Related

Xcode: External build configuration for framework target

We have a Filters framework that contains many image processing filters (written in Swift and Metal) and the resources they require (like ML models and static images). But not every app we have uses all the filters in Filters. Rather we want to only build and bundle the required filters and resources that are needed by the app.
The only way we can think of to achieve that is to create different framework targets in Xcode, one for each app. But that would require that the Filters framework project “knows” all of its consumers (apps) and we would rather like to avoid that. Especially since the filters are in a separate repository.
Is there a way to, for instance, pass some kind of configuration file to the framework that is used at build time to decide which files to build and bundle?
You can use Target Membership to assign files into specific targets. See image below.
Make sure you are on the File Inspector tab on the right side of Xcode. Select the files you want to limit to a target and in the Target Membership area, you can select which target the selected file belongs to or don't belong to. For public resources, make sure to select public for the visibility scope.
For files that don't require compilation, e.g. image files, once you've selected the target membership, the file will be automatically added to the Build Phases' Copy Bundle Resources area.
Alternative One
Alternatively, you can use add a Copy Files Phase in the Build Phases. With the Copy Files Phase, you can copy files to subdirectories instead of the root of the framework bundle.
Alternative Two
Yet another way is to add a Run Script Phase in the Build Phases. The script can be in any language but usually shell script. You can do whatever you need in the script including compiling code manually but you need to know where the files goes by using environment variables and placed the files in the correct location. I think this will be the most manual and most hassle to use for selecting files based on targets.
Alternative Three
If you really want to go fancy, you can even break down all the components into targets and use Aggregate target to tie the different components into the target you are building for. I would not recommend this usually and reserve this for very special needs that other methods could not achieve.

Xcode - changing search path for frameworks

I'm having an issue with frameworks not being recognized:
For some reason the path for the frame work is set to Derived Data folder:
Is there anyway to change this to point the frameworks search the right folder?
Also, what kind of language is this and how would I go about changing the directory to the proper module (in the repo)?
Thank you for any insights you can provide, this is confusing for an amateur like me.
Is there anyway to change this to point the frameworks search the right folder?
Yes, and you seem to have found the Framework Search Paths setting in the project already. Change that setting to include your frameworks folder and Xcode should start seeing your frameworks.
Also, what kind of language is this and how would I go about changing the directory to the proper module
It's not a language at all, its just a list. When you double-click in the right-hand column of the setting, as you've done in the image above, a view opens that lets you edit the list. It's not shown in your image, but at the bottom of that view there are + and - buttons — click the + and you'll add another item to the list. You can add your folder there.
The $DEVELOPER_FRAMEWORKS_DIR item that you see in the list is just the value of the DEVELOPER_FRAMEWORKS_DIR project variable. Each of the settings in the build settings have a corresponding variable that the setting changes — the variable for each setting is listed in the Quick Help panel for that setting. The $(inherited) is a sort of macro within the Xcode build system — it specifies the values that have been inherited for that build setting from other settings levels. See What is $(inherited) in Xcode's search path settings? for more information about inherited.
You shouldn't add an absolute path to the Framework Search Paths setting, e.g. one that starts with /Users/yourname/Library/... because then the project will only build on your machine. Instead, you should specify the path relative to some point in the project, and the various environment variables in Xcode can help. If you want to specify a folder called Frameworks at the top level of the project directory, for example, you could add an item to Framework Search Paths that says $PROJECT_DIR/Frameworks. You can find a list of project variables here: How do I print a list of "Build Settings" in Xcode project?

How does Xcode find implicit target dependencies?

Xcode finds dependencies automatically sometimes. I think is is ok when I am the one who is defining the relationships and when I get lazy ...
But more than often I find myself facing an existent (medium to large size) project with several targets. Since the project has been made by someone else I find it very difficult to understand what targets depends on what since not all the relationships are explicit.
What are the rules Xcode use to find such relationships? ( I hope I can understand the logic so run it in my mind and maybe save me some time in the future) Or What makes a target qualifiable to be implicitly dependant of another?
A target and the product it creates can be related to another target. If a target requires the output of another target in order to build, the first target is said to depend upon the second. If both targets are in the same workspace, Xcode can discover the dependency, in which case it builds the products in the required order. Such a relationship is referred to as an implicit dependency.
Source: iOS Developer Library → Xcode Concepts → Xcode Target
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:
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.
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.
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.
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.
Xcode Implicit Dependency
Xcode Dependency[About] is a dependency required to build a selected target.
Implicit dependency
source code aka Non-compiled dependencies. Xcode allows to add a dependency from the whole workspace. A good example is a Project from GitHub or CocoaPods[About] with source code
closed code aka Precompiled dependencies aka External - external binary, CocoaPods, Carthage with closed code
Implicit dependency is a dependency that is necessary to successfully build a target, but aren’t explicitly defined.
Specified in General -> Framework, Libraries, and Embedded Content or `Embedded Binaries and Linked Frameworks and Libraries[Link vs Embed]
No dependency in Build Phases -> Dependencies || Target Dependencies
To turn on this functionality[No such module]
Edit Scheme -> Build -> Find Implicit Dependencies
[Explicit dependency]
[Vocabulary]

Make Target's Build Products Path in Xcode dependent on Current Scheme

I have an Xcode Project with three targets:
A Mac app to be distributed on the Mac App Store
The same Mac app, but to be distributed as a demo version on my
website
A login helper app that is a target dependency for the first two
targets
The login helper app is copied on build to the target of the current scheme (let's say the first target), which has a build path of
$(BUILD_DIR)/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
When I change the scheme to the second target (the demo), I'd like for the build products path of the third target to be the same, except with _Demo attached to it. Basically, the third target's build path should always be the same as the current scheme's target (either target one or two).
Currently, I do it manually before building, but that's tedious.
Is there no way to make the Per-configuration Build Products Path (and the Per-configuration Intermediate Build Files Path, etc) dependent on the current target?
So when I select the first target, no _Demo gets attached to the path, when I select the second target, _Demo does get attached to the path.
Any pointers would be highly appreciated.
Thank you very much,
Matt
As I understand it, you want the login helper’s building to be aware of which “parent target” it’s being built in. Not sure if that’s possible.
What I’d do in this case, is add a separate “Copy” build step into targets 1 and 2. It sounds like copy is currently a part of building target 3, but it works better if it’s part of building targets 1 and 2.
I have a very similar situation with a command-line helper in one of my tools. Here’s the relevant part of my build settings.

Xcode: Which files need to be members of my target? (Target Membership)

I'm developing an iPhone app in Xcode 4.6.2 that only has one target, and I've noticed that some important files are not members of my target. None of my custom header files are part of the target membership, nor is my Info.plist, my Prefix header, or the product "MyApp.app."
The way I understand targets, these files certainly need to be members of the target.
My question is: why aren't these files members of my target?
After searching around on SO, similar questions have yielded some insight, but not a complete answer to that question. The insight I've gathered is:
Header files are not members of your target because they get linked in the "Copy Headers" Build Phase.
This sounds reasonable, but I don't have a Copy Headers Build Phase
Info.plist and Prefix.pch aren't members of the target because Info.plist gets linked in the "Copy Bundle Resources" Build Phase, and the Info.plist contains a key/value entry that points to the prefix header (Prefix.pch)
I'm not positive that this is actually how it works
Header files are what other source files reference so that they know what the interface for a class is. They aren't needed as part of the binary itself, so they don't need to be included in the final product.
Info.plist is a special case as it defines the application bundle itself, so it is processed separately.
Generally speaking, you want files to be members of your target when they:
Form part of the executable (e.g. implementation (.m) files or libraries), or
Are included as files in the application bundle (e.g. images).
You don't need files to be members of your target if they are only used as part of the build process and aren't needed at runtime. Typically this is any type of header file, including precompiled headers (.pch).
Only .m files and resource files are part of the targets, not .h.
You are right: the Info.plist files and the headers are all referenced in the build settings (which again are target specific).
Headers only need to be copied for a framework target, and only because they are part of the framework release (they allow users to know how to use the framework). Apps don't need the headers because they're compiled stand alone entities. The headers (and the pch file) are used during compilation but aren't required at runtime.
The info.plist is handled differently. It usually can't just be copied because in the project it usually isn't called "Info.plist". It's also mandatory for the file to exist in the app so Xcode doesn't give you the option of not including it.

Resources