Xcode dependencies across different build directories? - xcode

I am trying to set up Xcode for a project which contains multiple executables and static libraries. I have created multiple targets and set up the linking and dependencies, and initially everything works great. The catch...
This is an existing project which already has Visual Studio and Makefile builds. Those builds put the libraries in a lib/Debug directory and the executables in bin/Debug. So in Xcode I changed the Build Products Path to "lib" and "bin" respectively (so we can use one set of documentation for all of the platforms). This puts the compiled targets in the right place, but completely breaks both the linking (Library not found) and the dependencies.
I can fix the linking by adding $(SRCROOT)/lib/Debug to the Library Search Paths for each executable (but it feels like Xcode should be able to figure this out on its own, which makes me think I'm doing something wrong).
But — I can't figure out how to get the dependencies working again. If I change a library source file, the library will rebuild but not the dependent executables. If I force a build of the executable Xcode returns success without doing anything; it thinks the target is up to date. If I clean the target and then rebuild it works.
So, any ideas here? Is Xcode being fundamentally stupid in this regard, or is it me (I'm leaning toward the latter)?
Update: I've posted a sample project to demonstrate the issue at http://share.industriousone.com/XcodeDepsIssue.zip. Build it once, then modify MyStaticLib.c and build it again. The executable will not relink (and it should). Many thanks for any help on this one.

starkos, thanks for publishing your conclusion. It validated my experience as well. This situation really screwed me, so it was nice to know I wasn't just missing something.
I did however discover a workaround that avoids creating multiple projects or keeping the library and its dependent in the same directory. It is a hack, but it does work here.
I know it's a bit late but better than never.
For the dependency library, add a "Copy Files Build Phase", with Absolute Path as the destination, and the path text field should be the directory where the DEPENDENT target lives. Then click on Products, find the dependency library (will end with .a), and drag it into the "Copy Files Build Phase." If you now build, this will put the library into its own directory like before and THEN also copy it into the dependent's target directory.
For the dependent, you can now remove the dependency's output directory from the Library Search Paths. This will cause it to find the library copy. If you do this, the dependent will indeed be relinked each time the dependency .a is relinked.
The negatives are, of course, the extra time for the copy, and the necessity to specify (in the Copy phase) the target directory for each dependent of your library. Beats the hell out of the alternatives though....

Xcode doesn't automatically set up dependencies based on use of build products; you have to set up explicit target dependencies yourself.
Project > Edit Target Settings, General tab, + button, add any targets that are prerequisites to building the selected target. That should get you going again.

I've researched this some more and the answer is no, Xcode 3.x doesn't track dependencies between targets that live in different directories. You can work around it by giving each library its own project, and adding each of those to a master project. Or you can keep all of your targets in one directory. Pick your poison.

Here is my solution for this weird behavior in xcode 4.3.1. You have to add build pre-action in scheme:
rm -f ${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}
and choose which build settings to use for this script. Each time before build, target executable will be removed and rebuild completely. It helped for me, and i hope it helps you.
NOTE: Have tried to put this script in project build phase, and result was negative - debugger could not connect process to start debugging.
Good luck!

OK, it would help to have the text of the Linking... build line that's failing. But a couple of things:
1) You shouldn't be linking to anything in $(SRCROOT). That's your project sources. The two places to find things to link are $(SYMROOT) (the Build Products directory) or $(DSTROOT) (the Installed Products directory).
One thing you could do is to have a common Build Directory, then use 'xcodebuild install' action to install the products in the Installation Directory. The other is to use a Copy Files build phase to copy them after building, so you can link against them in $(SYMROOT) but still have them where your Windows compatriots expect them.
THere is probably a way to set up the per-target build products directories correctly, but I'd really have to see the project itself to figure it out.

Related

Building different targets in different folders - Xcode

I have two targets in the same xcode project, as bundle plugins, and I want the executable files within the binary to have the same name for both targets.
Is there a way I can either:
A) Define the executable file for each binary without affecting the .bundle name (or first target overwrites the second target as they're building).
B) Build both files in their own folder.
They are in the same project, so the build end-results are automatically placed in the same folder. One overwrites the other, as the .bundle name always ends up the same (because I want the same executable name). They share a lot of code, so they are in the same project, to build everything again at once, to make sure everything always has the latest code across all versions.
Would anybody know a way of doing this? I tried various options in the build settings. Or would anybody maybe have any "build phase" workaround ideas? Please don't ignore that the executable name needs to be the same for all binaries.
Thanks in advance!
I created a project for each slightly different built, with flags in the build settings for each target making each target distinct (with use of macros in the actual code).
Regarding in ensuring code is always the up-to-date, partially shared, code for each build/project, they share the source code by adding it to the project, without selecting the "copy to project folder" option. Annoying workaround, but it'll do until I work something better out...
Why don't you use targets with different names? Or a script after build, that copies the target to a different name?
This should copy each target to a unique name after build, without each build overwriting the other. (If things are linear)

XCode not linking on dependency (.a) change unless executable is deleted

I have a sub-sub-project (a child of a child of the top level project) in XCode that produces a static library that the top level project links against. The output of the sub-sub-project is in the Build Settings > Link Binary With Libraries list (though not in the Target Dependencies, because XCode will only let you put immediate children in there). If I delete the Executable Unix File in the AppPackage in the Build directory, it does build correctly. It's just not recognizing that the library being changed should cause the executable to link, even though it worked fine this morning. I've checked git and the project files are unchanged. What could be going on? (I'm gonna reboot as soon as I post this)
Edit: Rebooting didn't work. Going to a previous commit didn't work. I'm beginning to wonder if it never worked right.
I have the same problem. Only way to get the app to link to the new version of the static lib is to clean before building. And I even have the static lib project set as a dependency.

Is there a way to list all files and their targets in Xcode?

I am part of a project with multiple developers. The project contains multiple targets. VERY often, files are committed to the Xcode project repository with some targets not-included (careless programmers). So whenever i do a 'svn up', and run the app, my program crashes. I then have to look through all those files and see which one was committed with the missing target, then add the target, and recommit the file to the repository (for that careless programmer)
Is there some way through a script to either automatically add all .m to a particular target?
OR
list all the files that are missing for a particular target?
I have looked at Add files to an XCode project from a script for reference already.
My answer on this other thread shows you how to see all files that are not part of a target:
https://stackoverflow.com/a/12867723/591586
I did as Paul suggested and wrote a python script that inspects the .pbxproj and lists all the files and the targets they are included in.
You could easily modify that script so that it highlights the files that are not included in specific targets.
https://github.com/laurent74/XPFAT
This question has been asked before, but neither did that question got an answer.
As far as I know, XCode does not have any build in support for comparing targets. However, the project is nothing more than an set of XML files... very detailed XML files though.. but still XML.
What you could do (this is not something I recommend though) is read through the XML files of the project and try to understand how they are build.
I know this is not the answer you are looking for, but it might be a workaround.
Update
I read though project.pbxproj of a test project with two targets, and it seems as if the project is build up into references. Which is smart since one wouldn't have a huge file if you have many targets. However, it does mean that its really hard to read.

How to include a bundle in main project xcode 4.1

[UPDATE 03/04/2015]
The question is now 4 years old, and applies to a specific version of XCode which I have now specified in the subject.
I have searched a lot for this argument, but I couldn't find a solution, I even post on stackoverflow, but I soon deleted the question becuase of very little access.
Now I am trying again.
I have a workspace with two distinct projects A and B.
B has two targets, one that build a static library Blib.a, and one that build a bundle B.bundle. All of them get built in the derived directory.
In project A I can easily add the static library from the build phases. However I cannot find a way to include the bundle. B.bundle is not visible from "copy resource" tab in A.
Therefore I need to add manually, with all that implies.
I also thought about using a script, but I would like to use this as a very last option.
Has someone a solution for this ? Did I miss something ?
thanks
After long investigation, it came up there's no easy way of doing this. The B.bundle is never visible to A project, and there's no settings in workspace to change that.
At this point there are three solutions:
Include the bundle manually from "copy resources->other", I started with this, but everytime there's a change you have to drop and include the bundle again
Create a script to be run in build phase, if everything is built into the PRODUCTS dir you can find the bundle easily and having copied automatically into the app.bundle. This is not a bad solution. If you are using svn the script got included in project, and users have it for free without additional work.
As suggested by Apple tech support, use folder references.Build bundle B into a folder and add such folder to project A using the "Create Folder References for any added folders" option. Xcode 4 will update your bundle into that folder every time you built it.
The added folder will appear as blue once included in your project A.
Thats's it, I personally use the script, because this solution is path independent if you use standard xcode reference variable such as BUILT_PRODUCTS_DIR and so on, and the shell script is just a cp -r-f
[UPDATE 03/04/2015]
I would like to point out that the question is now 4 years old. At that time there weren't many "official" options available. I even spoke with Apple Tech Support, which proposed solution 3 as the only available solution. It is of course very likely that things are now changed, and there is a much better solution. Just to speak, I also like to add that the three above are not "hacks" but "solutions", maybe technically outdated, but they can still be used nowadays. I intend a "hack" as a..."hack", which means it probably not going to work in future software release.
Here is how I did it.
Drag and drop B.bundle from Project B → Products → B.bundle into the Copy Bundle Resources build phase of your app in Project A (select the Create groups options when asked). This will add B.bundle at the root of your Project A outline. You can move it into the Frameworks directory near Blib.a if it you prefer.
Select B.bundle and check its Location in the Identity and Type right panel (Utilities area). By default, Xcode chooses Relative to Project. This is wrong, select Relative to Build Products instead.
The path to B.bundle will now look something like ../../../../../../../../Projects/MyApp/B.bundle. This is not what you want, but you can easily fix it. Open ProjectA.xcodeproj/project.pbxproj in a text editor, search for this path and delete everything in it except for B.bundle. Your project.pbxproj should look like this:
explicitFileType = wrapper.cfbundle; name = B.bundle; path = "B.bundle"; sourceTree = BUILT_PRODUCTS_DIR; };
Save your project.pbxproj file. Xcode will automatically reload your project and your app should build just fine.
After searching for a long time and failing many times, I found this resource that has been an absolutely great tutorial to create Static Libraries and include bundles in your main project or even for distribution to 3rd party developers that may consume your library.
Absolutely recommended:
https://github.com/jverkoey/iOS-Framework
In project A, is the product of project B a dependency in your scheme's Build action? I think you might have to set up this dependency (sometimes disabling the automatic dependency discovery option is best) for it to show up and be available for copying into another target. I believe this is because it doesn't really exist (like an image resource file) until it's built and Xcode needs to ensure it's built before working with it from another target.
As of Xcode 5.1.1 I was able to drag and drop B.bundle from the Project Navigator to the Copy Bundle Resources list of project A Build Phases. I assume creating B.bundle target is not an issue.
Switch build to Generic iOS Device. This step is needed to create a non-simulator reference.
Drag the .bundle to the other project's Copy Bundle Resources.
Select the .bundle in the Project navigator of the other project, and change its Location to Relative to Build Products
Make sure your .bundle in added to Target Dependencies of your static library

Generate an xcodeproj

I know this might sound a bit strange but I'd need to generate a xcodeproj automatically.
Basically scanning the filesystem and adding certain files to the project and to a specific target.
The main reason behind this, is that I work in an zero IDE environment. Thus, we have our own build system and source files are added and removed all the time.
I could use "create folder references for any added folders". However, xcode won't ever parse source files if they aren't part of any target. So, no symbols, no code completion...
To me, my only option would be to "auto-update" my xcodeproj with a script...
Thanks in advance for your inputs!
Cmake is one option (see this related question) and there's also Scons which I think can generate Xcode projects. There's also Qt's qmake which can generate the project files, but this is probably overkill unless you're using full Qt.
You can either user AppleScript (or anything OSA-compatible) to automate the process of creating the project in Xcode itself, or you could look at CMake, which is able to generate Xcode project files.

Resources