View Issue Details Jump to Notes ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0014185CMakeCMakepublic2013-06-01 12:322016-06-10 14:31
Reporternic 
Assigned ToKitware Robot 
PrioritynormalSeverityfeatureReproducibilityhave not tried
StatusclosedResolutionmoved 
PlatformOSOS Version
Product VersionCMake 2.8.11 
Target VersionFixed in Version 
Summary0014185: Xcode: Use "Link Binary With Libraries" build phase when possible
DescriptionAccording to the FAQ at [1], the "Link Binary With Libraries" is not used because it does not support flags such as "-lfoo". However, the correct build phase should be used when possible, ie. when the full path to the library is known.

[1]: http://www.cmake.org/Wiki/CMake_FAQ#Why_do_generated_Xcode_projects_have_a_CMake_PostBuild_Rules_phase.3F [^]
Additional InformationThis feature has a huge impact when working with multiple "loosely coupled" projects that are all being developed simultaneously in their respective build trees. Such projects can be combined in a single Xcode workspace. Currently, all projects must be built and updated manually. Using the "Link Binary With Libraries" build phase would automatically take care of updating necessary dependencies.
TagsXcode
Attached Filesdiff file icon xcodeproj.diff [^] (7,067 bytes) 2013-06-02 07:02 [Show Content]
patch file icon cmGlobalXCodeGenerator.cxx.patch [^] (7,665 bytes) 2013-06-02 21:20 [Show Content]

 Relationships

  Notes
(0033167)
nic (reporter)
2013-06-02 07:03
edited on: 2013-06-02 09:10

I added a diff of the cmake-generated project and the corresponding project handling libraries the Xcode way.

EDIT:

I think that Xcode confused the paths to add to the LIBRARY_SEARCH_PATHS setting in the file I uploaded. These should be the same as the paths that were added to the linker flags before, depending on the configuration.

It seems that these paths do not matter when the library is in the project/workspace. The libraries found under LIBRARY_SEARCH_PATHS are used only if they are not part of the project/workspace. Libraries contained in the project/workspace are automatically built and updated as needed.

To summarise:

- Add paths to libraries to LIBRARY_SEARCH_PATHS.
- Add libraries to the "Link Binary With Libraries" build step.

Result:

- Libraries that are not in the project/workspace are found in LIBRARY_SEARCH_PATHS.
- Libraries that are in the project/workspace are built and updated automatically.
- The post-build step is no longer necessary.

(0033171)
nic (reporter)
2013-06-02 21:26

I uploaded a patch for the Xcode generator that links libraries the way native Xcode 4 projects do using the "Link Binary With Libraries" build phase.

A library is added in this way only if it is uniquely present in all build configurations. The path to the library is added to the library search paths of each configuration. The libraries are also listed in the "Libraries" group of the Project Navigator.

This patch does however not modify the existing scripted post-build step in any way. I think that it could be omitted entirely for Xcode 4 projects using this method.
(0033176)
Brad King (manager)
2013-06-03 08:57

The FAQ entry needs to be updated to include other reasons. Prior to CMake 2.6 we split library paths like "/path/to/libfoo.a" into "-L/path/to -lfoo" on link lines. We had no end of problems with ordering of -L entries to ensure the linker finds the proper foo (circular constraints, -Bdynamic v. -Bshared, etc.). Now we always generate the full path to the library when it is known. This patch reverts that improvement because Xcode doesn't know how to generate full paths either.

The *ONLY* solution to this problem is for *Xcode* to be fixed as the FAQ entry requests at the end:

 ...if Xcode were to simply provide a setting to specify link dependencies on arbitrary files...
(0033196)
nic (reporter)
2013-06-03 09:28

The patch only adds a library to the build phase when it has a unique name and exists across all the configurations for a target.

Not specifying the link dependencies per file is what allows Xcode to automagically figure out if the library is an external file, part of your project or part of your workspace, and build other targets and projects as necessary. For a single project this can be emulated with the post-build rule, but it does not scale to workspaces.

So, as to how Xcode works, that's the way it is. Maybe it would be enough to simply print a warning message that Xcode cannot correctly build your project if there are issues. Especially since you end up with those same issues when setting up the project by hand. Being able to effectively use generated projects in workspaces surely outweighs the cases where this causes problems?
(0033197)
Brad King (manager)
2013-06-03 09:31

How does the patch preserve CMake's carefully-generated order of libraries? Order matters when multiple static libraries provide the same symbols.
(0033198)
nic (reporter)
2013-06-03 09:53
edited on: 2013-06-03 09:59

All unresolved libraries from OTHER_LD_FLAGS go first. The order of resolved libraries (-l<lib>) is the same as before, so I assume the issue is with the linker paths (-L<path>). The problems then could occur, if I understand you correctly, if there are two libraries

/other/path/libA.a
/usr/local/lib/libA.a

and I want to use /usr/local/lib/libA.a even though -L/other/path is first in the LIBRARY_SEARCH_PATHS. And it seems that this simply cannot be done with Xcode's way of handling libraries.

(0033200)
Brad King (manager)
2013-06-03 10:03

> it seems that this simply cannot be done with Xcode's way of handling libraries

That's why we use OTHER_LDFLAGS!

Visual Studio supports an "AdditionalDependencies" field for its link rules. That's all we ask from Xcode.

There is also the issue of order of the libraries themselves: "-lfoo -lbar" is different from "-lbar -lfoo" when both libfoo.a and libbar.a have an object file providing the same symbols.
(0033201)
nic (reporter)
2013-06-03 10:12
edited on: 2013-06-03 10:13

The order of the -l flags from the build phase is preserved though.

And as for the limitations of Xcode, I was simply arguing for accepting it as "not possible" when using this generator. It's not an issue with cmake after all! Instead of working around the functionality needlessly for what I would assume is the vast, vast majority of cases, and "crippling" a core feature of workspaces, cmake could warn (or simply refuse) when generating Xcode projects with an unsupported setup.

(0033202)
Brad King (manager)
2013-06-03 10:18

The order cannot be preserved across the split between the build phase and OTHER_LDFLAGS.

Someone really needs to push on the Xcode developers for this. The feature we request is generally useful and not CMake-specific.
(0033205)
nic (reporter)
2013-06-03 10:32

Actually, I found that you can add arbitrary -lfoo flags to the build phase as well by adding items with name = "libfoo.a" path = "libfoo.a. These need not be referenced anywhere else. In this way, the total order of libraries can be preserved.

I agree wholeheartedly on Xcode. The linker management is a joke.
(0033211)
Brad King (manager)
2013-06-03 11:11

Re 0014185:0033205: Oh, nice! Does putting a full path there work too? IIUC we can use this to replace use of OTHER_LDFLAGS for generating the full link line and use the build phase instead. I wonder if it will take the "path=..." and check dependencies on the "..." part.
(0033212)
nic (reporter)
2013-06-03 11:23

Unfortunately (*), it seems that the path of the referenced library is not used for anything during linking. Specifically, Xcode seems to work like this:

- If the path is not found, mark the file as missing (red).
- If the library is not referenced in the source list, show with transparent icon.
- Use the name (ie. libfoo.a) to add a -lfoo linker flag.

This is corroborated by the fact that Xcode itself simply appends the path to LIBRARY_SEARCH_PATHS when a random library is added from disk.

So to recap: I suggest cmake does as Xcode does. Add all libraries in correct order to the build phase. Add known paths for libraries in best possible order to LIBRARY_SEARCH_PATHS. And in the rare case that this causes an issue, treat it as a limitation of Xcode.

---

(*) Actually, that appears to be a hack in itself. It allows Xcode to pick the correct library for the current configuration, since the build phase is per-target and not per-configuration, unlike LIBRARY_SEARCH_PATHS.
(0033217)
Brad King (manager)
2013-06-03 14:00

This will be a fairly significant change to the generator's behavior. Likely there will be corner cases that are not compatible with the old behavior. This needs a more broad discussion and may need some follow-up work. Please join the developer list:

 http://www.cmake.org/mailman/listinfo/cmake-developers [^]

and bring this issue up there.
(0033240)
Brad King (manager)
2013-06-05 08:17

For reference, discussion on cmake-developers is here:

 http://thread.gmane.org/gmane.comp.programming.tools.cmake.devel/7031 [^]
(0039945)
Roger (reporter)
2015-12-03 07:14
edited on: 2015-12-04 06:32

I'd like to add to this discussion that the current situation is problematic for developers working on OSX-applications intended for the Appstore.

For the appstore submission you need to set Entitlements in the "Capabilities"-tab. Assume we want to support gamecenter, you need to :
1. Add the GameKit entitlement to your appID
2. Link the GameKit.framework
3. Add the GameKit key to your info .plist.

#1 and 0000003 are no problem.
However 0000002 is not possible with CMake. Adding the GameKit to your libraries is not enough. It only works correctly if GameKit.framework is added to the "Link with Binary" step.

Basically it leads to two options:
1. Don't use CMake for projects you want to release in the appstore
2. Generate the XCodeProj, then run XCode and "fix it" by manually adding the "Link with Binary Step"... This also means that CI-builds with, e.g. Jenkis, just aren't possible.

I tried re-applying Nic's patch, but ran into issues with the paths. Since this issue is open since 2013, it's a reasonable assumption that nothing will change - and we can assume that the xcode-developers won't make any changes which were mentioned here either.

So one alternative I though of is to use sed and "search & replace" the necessary sections in the codeproj.
Other people running into this limitation are bound to find this bugreport, so posting it here as an alternative:

-----
s#\/\* Begin PBXBuildFile section \*\/#\/\* Begin PBXBuildFile section \*\/\
        26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks \*\/ = {isa = PBXBuildFile; fileRef = 26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/; };#g
 
 
s#\/\* Begin PBXFileReference section \*\/#\/\* Begin PBXFileReference section \*\/\
        26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GameKit.framework; path = System\/Library\/Frameworks\/GameKit.framework; sourceTree = SDKROOT; };#g


s#\/\* End PBXFileReference section \*\/#\/\* End PBXFileReference section \*\/\
\
\/\* Begin PBXFrameworksBuildPhase section \*\/\
        26B12A9F1C10543B00A9A2BA \/\* Frameworks \*\/ = {\
            isa = PBXFrameworksBuildPhase;\
            buildActionMask = 2147483647;\
            files = (\
                26B12AA11C10544700A9A2BA \/\* GameKit.framework in Frameworks xxx\*\/,\
            );\
            runOnlyForDeploymentPostprocessing = 0;\
        };\
\/\* End PBXFrameworksBuildPhase section \*\/\
#g


s#\/\* CMake PostBuild Rules \*\/,#\/\* CMake PostBuild Rules \*\/,\
                26B12A9F1C10543B00A9A2BA \/\* Frameworks xxx\*\/,#g


s#\/\* Products \*\/,#\/\* Products \*\/,\
                26B12AA01C10544700A9A2BA \/\* GameKit.framework xxx\*\/,#g
    
---

save that to a file "xcode-gamekit.sed" and run it like this:
sed -f gamekit.sed XRebirth.xcodeproj/project.pbxproj > XRebirth.xcodeproj/project.pbxprojx

Then go into the XCodeProj, backup the .pbxproj and rename the .pbxprojx to .pbxproj.
Open the project and - in XCode 6.3.1 - you will now have the "Link with Library" with gamekit.

Warning: You'll probably have to adapt the above fragment to suit your needs, it may not work with different versions of XCode, and just pray that the unique identifier really is unique. Generally this is probably a bad idea, but it's *a* idea, and as such better than nothing.

(0042293)
Kitware Robot (administrator)
2016-06-10 14:28

Resolving issue as `moved`.

This issue tracker is no longer used. Further discussion of this issue may take place in the current CMake Issues page linked in the banner at the top of this page.

 Issue History
Date Modified Username Field Change
2013-06-01 12:32 nic New Issue
2013-06-01 13:13 nic Tag Attached: Xcode
2013-06-02 07:02 nic File Added: xcodeproj.diff
2013-06-02 07:03 nic Note Added: 0033167
2013-06-02 09:10 nic Note Edited: 0033167
2013-06-02 21:20 nic File Added: cmGlobalXCodeGenerator.cxx.patch
2013-06-02 21:26 nic Note Added: 0033171
2013-06-03 08:57 Brad King Note Added: 0033176
2013-06-03 08:57 Brad King Status new => backlog
2013-06-03 09:28 nic Note Added: 0033196
2013-06-03 09:31 Brad King Note Added: 0033197
2013-06-03 09:53 nic Note Added: 0033198
2013-06-03 09:59 nic Note Edited: 0033198
2013-06-03 10:03 Brad King Note Added: 0033200
2013-06-03 10:12 nic Note Added: 0033201
2013-06-03 10:13 nic Note Edited: 0033201
2013-06-03 10:18 Brad King Note Added: 0033202
2013-06-03 10:32 nic Note Added: 0033205
2013-06-03 11:11 Brad King Note Added: 0033211
2013-06-03 11:23 nic Note Added: 0033212
2013-06-03 14:00 Brad King Note Added: 0033217
2013-06-05 08:17 Brad King Note Added: 0033240
2015-12-03 07:14 Roger Note Added: 0039945
2015-12-04 06:24 Roger Note Edited: 0039945
2015-12-04 06:32 Roger Note Edited: 0039945
2016-06-10 14:28 Kitware Robot Note Added: 0042293
2016-06-10 14:28 Kitware Robot Status backlog => resolved
2016-06-10 14:28 Kitware Robot Resolution open => moved
2016-06-10 14:28 Kitware Robot Assigned To => Kitware Robot
2016-06-10 14:31 Kitware Robot Status resolved => closed


Copyright © 2000 - 2018 MantisBT Team