On Mar 13, 2017, at 08:37 , Richard Charles <email@hidden> wrote:
By default, Xcode stores derived data for all projects in ~/Library/Developer/Xcode/DerivedData. This means that build products for all configurations are in the same directory (Debug or Release).
I don’t understand what/why you’re saying this. Xcode stores derived data for each project in a separate project-specific subdirectory of DerivedData. It stores build products for different configurations in different sub-sub-…sub-directories of the project-specific subdirectory. If you add the *product* of a custom embedded library to a project, the default location in the file inspector for the library will be “Relative to Group”. Simply change this to “Relative to Build Products” and voila! Build configurations now work as expected for the project, just remember to build the desired library configurations beforehand.
This suggests that Xcode is finding the built libraries relative to the build products of the *library* project, not the app project, which sounds plausible, although it partially invalidates my claim about Xcode’s “understanding” of external build products. The only thing that doesn’t work is archiving. Because archiving has a different build directory structure you will get a library linker error "No such file or directory”.
It’s possible this is because you never *archived* the library before archiving the app, so the necessary files were never built. However, even if you do (or did) archive the library, it may still fail, depending on the structure of the library archive vs. the subdirectory contents Xcode is expecting for the app archiving process.
But there’s something else going on here that complicates understanding. What you open in Xcode is not really a project, but a workspace containing the project. In the simplest case, when you use File -> Open and choose a project, what gets opened is a private/invisible workspace which logically contains the project, although the workspace file (with workspace settings in it) is embedded within the project file package. Xcode actively maintains this fiction, for example by changing the “Workspace Settings” item on the File menu to “Project Settings” when the workspace is embedded in the project privately.
Alternatively, it’s possible to create a freestanding workspace explicitly, then add one or more projects to it. In that case, the workspace file is not embedded within the file packages of any of the projects it contains.
What matters here is that the derived data is per-workspace, not per-project. If you open a project and build it, the build products directory is one subdirectory of DerivedData. If you open a workspace containing the project, the build products directory is a different subdirectory of DerivedData.
The point of all this is that when you have a complex app bundle that contains components from multiple projects, the correct way to do it is to use a workspace that contains each of the projects. The projects remain independent, but they share a base DerivedData subdirectory. Also, Xcode can automatically monitor dependencies between the projects, and it automatically uses the correct per-configuration-per-workspace build products when “Relative to Build Products” is used to locate files.
I think I inadvertently slid past this when originally laying out your workflow choices. That’s because there’s another level of complexity in how you can combine projects:
1. You can drag project B into project A as a nested subproject.
2. You can drag project B into project A as a top-level peer project.
3. You can create a workspace C containing projects A and B as top-level peer projects.
#2 and #3 are really the same thing (AFAIK), the only difference being whether it’s an explicit or an implicit workspace. I have never been able to find out what the difference between #1 and #2 is, if any.
This leads back to what happened when you earlier tried to add your library project as a “subproject” of your app project. That sounds like you tried #1. It’s possible that what you really needed to do was #2 or #3. It’s also possible that you gave up too soon, after you saw that “the build time becomes enormous”. With different projects combined into the same workspace, you’re going to see:
a. Both projects will fully rebuild the first time you build the workspace, because the workspace has its own derived data hierarchy and anything previously built for the projects separately is no longer used.
b. Both projects will fully rebuild at archive time, because the philosophy of archiving is that everything placed in the archive is re-built at the same time.
#b might be “intolerable” as you said, but it’s actually the correct thing to do, at least in general. Xcode does *not* guarantee (AFAIK) that anything it builds during a normal build operation is suitable for inclusion in an archive, only that it’s suitable for building, running locally, and debugging. Indeed, there may be subtle problems in your current workflow of embedding your library’s build products into your app rather than the library’s archive products. (Or not.)
So, I think my advice would be to go back and make an explicit workspace for your 2 projects, investigate any apparent build problems that come from combining the projects, then live with the longer archive time that results. If that’s intolerable, you can continue doing what you’ve arrived at so far, but be aware that the ice you’re standing on might not be quite so thick as you wish.
|