MantisBT - CMake
View Issue Details
0011295CMakeCMakepublic2010-10-06 20:462014-01-02 15:05
Richard Bateman 
David Cole 
normalfeaturealways
closedfixed 
CMake-2-8 
CMake 2.8.5CMake 2.8.5 
0011295: Support for "CFBundle" (.plugin) types on Mac OS
CFBundle types are used to create web browser plugins. In particular, this is needed for the FireBreath project (http://firebreath.googlecode.com/ [^]).

The CFBundle type most closely matches a MODULE_SHARED type.
I have implemented and tested this feature; attached is the patch. It adds the feature for both XCode and Makefiles on Mac OS X
No tags attached.
related to 0013797closed Clinton Stimpson OS X CFBundle PREFIX and SUFFIX are set too late 
related to 0014671closed Kitware Robot install TARGETS with BUNDLE does not work for target that have the BUNDLE property set 
patch cmake_CFBundle.patch (12,493) 2010-10-06 20:46
https://public.kitware.com/Bug/file/3433/cmake_CFBundle.patch
patch cmake_CFBundle_2.patch (952) 2010-10-06 23:48
https://public.kitware.com/Bug/file/3434/cmake_CFBundle_2.patch
gz CFBundleTest.tar.gz (4,001) 2010-10-06 23:51
https://public.kitware.com/Bug/file/3435/CFBundleTest.tar.gz
patch 0001-Added-fix-for-issue-11295.patch (24,408) 2010-11-30 21:49
https://public.kitware.com/Bug/file/3540/0001-Added-fix-for-issue-11295.patch
Issue History
2010-10-06 20:46Richard BatemanNew Issue
2010-10-06 20:46Richard BatemanFile Added: cmake_CFBundle.patch
2010-10-06 21:11Bill HoffmanNote Added: 0022424
2010-10-06 22:50Richard BatemanNote Added: 0022425
2010-10-06 23:48Richard BatemanFile Added: cmake_CFBundle_2.patch
2010-10-06 23:49Richard BatemanNote Added: 0022426
2010-10-06 23:51Richard BatemanFile Added: CFBundleTest.tar.gz
2010-10-06 23:52Richard BatemanNote Added: 0022427
2010-10-07 02:52Michael WildNote Added: 0022428
2010-10-07 02:53Michael WildNote Edited: 0022428
2010-10-07 09:42Richard BatemanNote Added: 0022431
2010-10-07 11:05Richard BatemanNote Added: 0022436
2010-10-07 12:29Michael WildNote Added: 0022439
2010-10-07 12:44Michael WildNote Edited: 0022439
2010-10-07 13:28Richard BatemanNote Added: 0022440
2010-10-07 14:55Michael WildNote Added: 0022441
2010-10-07 14:59Richard BatemanNote Added: 0022442
2010-10-08 02:51Michael WildNote Added: 0022451
2010-10-08 08:57David ColeNote Added: 0022452
2010-10-08 08:57David ColeStatusnew => assigned
2010-10-08 08:57David ColeAssigned To => David Cole
2010-10-08 09:04Brad KingNote Added: 0022453
2010-10-08 09:07Brad KingNote Edited: 0022453
2010-10-08 09:07Michael WildNote Added: 0022454
2010-10-08 09:10Michael WildNote Edited: 0022454
2010-10-08 11:22Richard BatemanNote Added: 0022456
2010-10-08 15:18Brad KingNote Added: 0022457
2010-10-09 12:20Michael WildNote Added: 0022462
2010-10-11 08:38Brad KingNote Added: 0022471
2010-10-11 08:50Michael WildNote Added: 0022472
2010-11-10 13:05David ColeTarget Version => CMake 2.8.4
2010-11-30 21:49Richard BatemanFile Added: 0001-Added-fix-for-issue-11295.patch
2010-11-30 21:56Richard BatemanNote Added: 0023609
2011-01-11 13:31David ColeNote Added: 0024592
2011-01-11 13:34David ColeNote Added: 0024593
2011-01-11 13:34David ColeStatusassigned => resolved
2011-01-11 13:34David ColeResolutionopen => fixed
2011-01-12 05:53David ColeNote Added: 0024611
2011-02-16 11:43David ColeTarget VersionCMake 2.8.4 => CMake 2.8.5
2011-06-06 18:25David ColeStatusresolved => closed
2011-06-06 18:25David ColeNote Added: 0026718
2011-06-17 18:20David ColeFixed in Version => CMake 2.8.5
2012-12-14 14:40Brad KingRelationship addedrelated to 0013797
2014-01-02 15:05Brad KingRelationship addedrelated to 0014671

Notes
(0022424)
Bill Hoffman   
2010-10-06 21:11   
Can you add a test for your feature?
(0022425)
Richard Bateman   
2010-10-06 22:50   
I am trying to figure out how to do that; are there docs somewhere with the specifics? Does it need to be automated, like a unit test, or just something that can be run and analyzed to confirm that the feature is working correctly?

Not sure how you'd write a unit test for this feature... the only way I know to test it is to generate a project and look to see if it generated correctly.
(0022426)
Richard Bateman   
2010-10-06 23:49   
Found a problem when doing additional testing, cmake_CFBundle_2.patch fixes it.
(0022427)
Richard Bateman   
2010-10-06 23:52   
Created CFBundleTest/ which generates a project. If the files are placed in the right place in the bundle and named correctly, it should be working fine.

README.txt tells what the resulting .plugin/ bundle should look like.

Is this adequate, or do you need something more?
(0022428)
Michael Wild   
2010-10-07 02:52   
(edited on: 2010-10-07 02:53)
I might be missing something, but isn't this basically equivalent to doing the following:

configure_file(fooCFBundle.plist.in
  "${CMAKE_CURRENT_BINARY_DIR}/fooCFBundle.plist")
add_library(foo MODULE foo1.c foo2.c foo3.c)
set_target_properties(foo PROPERTIES
  FRAMEWORK TRUE
  SUFFIX .plugin
  MACOSX_FRAMEWORK_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/fooCFBundle.plist")

(0022431)
Richard Bateman   
2010-10-07 09:42   
Michael: No, for several reasons
1: There is a big difference between a framework bundle and a CFBundle -- logically, it shouldn't work
2: You can't create a framework from a shared module, at least as CMake is currently written
3: Frameworks have the file type "wrapper.framework"; CFBundles have the file type "wrapper.cfbundle"
4: Frameworks have the product type "com.apple.product-type.framework". Bundles have the product type "com.apple.product-type.bundle"
5: Frameworks are linked with -dynamiclib, CFBundles are linked with -bundle

Your code (and I tested it to be certain) results in no bundle and a single file with a prefix and suffix that are undesirable. Granted, the prefix and suffix could be overridden in project-specific code, but the goal is to have it work the way that it would normally be expected, right?
(0022436)
Richard Bateman   
2010-10-07 11:05   
To further explain, what we have been doing up 'til now is creating an application bundle and then using a python script to patch the resulting Xcode project to change the file and product type of that project.

There are several things done to the framework type that are not desirable for a CFBundle -- even if it worked on a SHARED_MODULE type, which it doesn't.
(0022439)
Michael Wild   
2010-10-07 12:29   
(edited on: 2010-10-07 12:44)
Ok, but:

1. Huh? That doesn't explain anything...
2. True. So that is IMHO the way to go for CMake. If a target is a MODULE, make a CFPlugin (NOT a CFBundle! See [1]), otherwise make it a framework.
3. I'd bet that's just for Xcode's sake. It doesn't have to do with what gets produced, just with how Xcode treats it in the GUI.
4. That can be fixed in the Info.plist.
5. That's the only real issue and would be fixed if CMake allowed for MODULE targets having the FRAMEWORK property enabled (perhaps a separate BUNDLE would be more appropriate?)

Also, one should have a way of specifying -bundle_loader, both for external executables and CMake targets, perhaps via a BUNDLE_LOADER property?

To summarise, I think the following should be implemented:

- Add a new target property BUNDLE which relates to MODULE the same way FRAMEWORK relates to SHARED and creates a CFPlugin. This also takes care of using a specific MacOSXCFPluginInfo.plist.in and of Xcode niceties, such as setting wrapper.plug-in (not wrapper.cfbundle).

- Add a new target property BUNDLE_LOADER where one can either specify a FILEPATH or an executable target name which gets expanded at build time.

The advantage of this approach is that the same target can be used to produce loadable libraries (MODULE) on all platforms with a single target, just the same as with SHARED. By setting a a target property (BUNDLE and FRAMEWORK, respectively), one can then decide whether the product should be a simple binary (.so and .dylib, respectively) or a bundle (.plugin or .framework).

[1] https://developer.apple.com/library/mac/#documentation/CoreFoundation/Conceptual/CFPlugIns/Concepts/anatomy.html [^]

(0022440)
Richard Bateman   
2010-10-07 13:28   
Continuing the numbered threaded discussion =]

1. My point is that it would be very confusing if you told it to build a framework in order to build a CFBundle -- or a CFPlugin. I would certainly be okay with using BUNDLE instead of CFBUNDLE, but then again it is the specific type -- CFBundle.
2. Why differentiate when making a CFBundle works for creating both types? Seems silly to restrict it to only creating CFPlugin types when we could support both by just doing a CFBundle (yes, I have tested this on a real project and it works)
3. Not in my experience; if you don't set both product type and file type to the correct values, it does not seem to build correctly.
4. No, it cannot. The product type is set in the XCode project itself, not just the plist. I don't know what exactly happens if they don't match, but those two values are the only difference in an XCode project between an Application Bundle and a CFBundle type.
5. Agreed on a seperate BUNDLE being more appropriate; that is what my patch does, except it uses CFBUNDLE instead of BUNDLE, which seems more descriptive to me.

My experience is that wrapper.cfbundle works fine on all versions of all browsers that support such plugins, so supporting wrapper.plug-in seems pointless; I'm not opposed to it if it works, I've just never seen it so I don't know if it works or not, and it seems unnecessary.

I'm happy to rename CFBUNDLE to BUNDLE if that will make you (or whomever) more comfortable accepting the patch; other than that, I don't see any changes that would be needed to support a BUNDLE target property with the patch that I submitted, unless you know of a reason that we would need to differentiate between wrapper.bundle and wrapper.plug-in. I do not know of any reason this would matter.

I don't understand what the purpose of BUNDLE_LOADER is?

Also, please note that my patch implements this so that it works with Makefiles as well. Specifics of how this change is implemented don't really matter to me, as long as it supports what I need. Just let me know what you'd like me to change so that the patch can be accepted, please =] This would be very helpful for a project I'm working on at Facebook.
(0022441)
Michael Wild   
2010-10-07 14:55   
I based my preference of CFPlugin and wrapper.plug-in on the Apple docs, but I never tried that stuff myself, so it might be irrelevant.

I think I misunderstood your patch, I'm sorry for that. I thought it was implementing a new library type (as in add_library(foo CFBUNDLE src1.c src2.c)) instead of a target property, am I right? In that case I'd be totally fine and somebody with more authoritative experience should be asked on the CFBundle vs. CFPlugin issue.
(0022442)
Richard Bateman   
2010-10-07 14:59   
the code used would be something like: (this is from the test uploaded above)

add_library( ${PROJECT_NAME} MODULE
    ${SOURCES}
    )

set_target_properties(CFBundleTest PROPERTIES
    CFBUNDLE 1
    XCODE_ATTRIBUTE_WRAPPER_EXTENSION plugin #sets the extension to .plugin
    XCODE_ATTRIBUTE_MACH_O_TYPE mh_bundle
    XCODE_ATTRIBUTE_INFOPLIST_FILE ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
    MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist
    LINK_FLAGS "-Wl,-exported_symbols_list,${CMAKE_CURRENT_SOURCE_DIR}/ExportList_plugin.txt")

So no, I'm certainly not suggesting a new target type; the MODULE type is already close to what we need, I just added a target property CFBUNDLE, similar to the FRAMEWORK or MACOSX_BUNDLE properties used in shared and executable modes.
(0022451)
Michael Wild   
2010-10-08 02:51   
Sorry again for misreading the patch. One little nit-pick I'm not happy with is using an Xcode-attribute to set the bundle extension. That breaks if you're using a different generator (e.g. a Makefile based one). I'd prefer a property, e.g. CFBUNDLE_EXTENSION which defaults to .bundle, but can be overriden, in your case .plugin.

After a lot of poking in the docs it became clear that CFPlugin implements a very limited subset of Microsoft's COM, so most likely it really should be CFBundle, although one might consider having a special target property for those who actually want/need a CFPlugin (although IMHO this could be handled via a custom Info.plist and manually setting SUFFIX).

In hindsight, it probably would have been better to have a single target property BUNDLE to handle application-bundles, frameworks and loadable bundles all at once:

add_executable(foo foo1.c foo2.c)
add_library(bar SHARED bar1.c bar2.c)
add_library(baz MODULE baz1.c baz2.c)
set_target_properties(foo bar baz PROPERTIES
  BUNDLE TRUE # produces foo.app, bar.framework and baz.bundle
  )

PS: To answer the question about BUNDLE_LOADER; the -bundle_loader flag is used to specify the binary that will load the bundle in order to resolve undefined symbols when linking the bundle. This is only necessary if the bundle uses symbols from the loading binary, and avoids the need for "-undefined dynamic_lookup".
(0022452)
David Cole   
2010-10-08 08:57   
This is looking good... I like the discussion here.

One question on the patch: the string ".plugin" is hard coded in the C++ files. Is that something that should be settable by a property, or are all CFBundle bundles required to be named ".plugin"...?

Also, with respect to this comment:
  # note that for some reason, the makefile and xcode generators use a different
  # property to indicate where the Info.plist file is :-/ For that reason, we
  # specify it twice so it will work both places

...wouldn't it be better to fix it so that the Xcode generator automatically sets up the XCODE_ATTRIBUTE_INFOPLIST_FILE with the value of MACOSX_BUNDLE_INFO_PLIST?

Also, is it required to use XCODE_ATTRIBUTE stuff, or will it "work" by default without specifying any of those... It might be very difficult to figure out how to use this if those are required, but somebody leave them off.

There's no documentation or guidance (but by example) on adding tests to CMake. The best place to start learning about it is in CMake/Tests/CMakeLists.txt. Most subdirs of CMake/Tests are built using "ctest --build-and-test" -- it should be fairly easy to adapt your attached test and add it as a subdir of CMake/Tests.
(0022453)
Brad King   
2010-10-08 09:04   
(edited on: 2010-10-08 09:07)
You two are making good progress toward a solution and both have much more Mac experience than I do. Thanks!

I will point out that CMake already supports "linking" a plugin to its loader and passing the -bundle_loader flag. It happens in the "Plugin" and "ExportImport" tests already. Look at Source/cmComputeLinkInformation.cxx for use of the "LoaderFlag" member to see the implementation. Basically a MODULE library can link to an executable:

 add_executable(someexe IMPORTED)
 set_target_properties(someexe PROPERTIES
   IMPORTED_LOCATION /path/to/bin/someexe # location on disk
   ENABLE_EXPORTS 1 # tell CMake it exports symbols -> make it linkable
   )
 add_library(myplugin MODULE ...)
 target_link_libraries(myplugin someexe)

When "myplugin" builds it will be given "-bundle_loader" and the path to "someexe". It also works if the executable is built within the project so long as it has the ENABLE_EXPORTS property set (which on windows is used to create the import library for the symbols exported by the executable).

(0022454)
Michael Wild   
2010-10-08 09:07   
(edited on: 2010-10-08 09:10)
@David:
No, ".plugin" is purely by convention. Some applications use e.g. ".bundle", and the official Apple docs only say that these two are common (and treated in a special way by Finder) but are not required. So it would be good to have a property for that.

Yes, IMHO the generator should be fixed. There are also other issues with it (e.g. http://www.vtk.org/Bug/view.php?id=10552 [^]).

@Brad:
That's pretty cool, but definitely needs documentation. I would NEVER have guessed this usage.

(0022456)
Richard Bateman   
2010-10-08 11:22   
@David - agreed that the bundle extension should be configurable. I merely copied the configurations from other bundle types, so I didn't fully consider that aspect; I will try to find a few minutes to create another patch this weekend to fix that, though I may not have time.

on the question of combining XCODE_ATTRIBUTE_INFOPLIST_FILE and MACOSX_BUNDLE_INFO_PLIST I fully agree that this should be resolved, but I believe it should be a seperate issue. Since there is a workaround that is adequate for now, I don't really have time to figure it out myself; this has been my first attempt to modify CMake code directly. As I mentioned earlier, I have been using the python patch workaround for a year, so I really should have done this long ago.

The XCODE_ATTRIBUTE list I copied from an example online; I think it works without those, but I haven't taken the time to do so. I will check while I'm working on it next.

As per the tests, could someone else possibly finish the test generation? I have never used ctest, and I am already spending more time on this than I have to spend, but I really don't want to just let it slide and not make it into a release.
(0022457)
Brad King   
2010-10-08 15:18   
http://www.cmake.org/cmake/help/cmake-2-8-docs.html#prop_tgt:ENABLE_EXPORTS [^]
(0022462)
Michael Wild   
2010-10-09 12:20   
Ooops, and I keep telling people to RTFM ;-) Although, it might help to mention -bundle_loader and Mac OS X.
(0022471)
Brad King   
2010-10-11 08:38   
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=abb6e755 [^]
(0022472)
Michael Wild   
2010-10-11 08:50   
Thanks a lot!
(0023609)
Richard Bateman   
2010-11-30 21:56   
I finally pulled out a few minutes to work on this. I uploaded the file 0001-Added-fix-for-issue-11295.patch which is a properly formatted patch with git format-patch; you can look at the changes in a more convenient manner here: https://github.com/firebreath/cmake/commit/9419918db8d8b9797b775f7a665686cf12365ae7 [^]

changes since the last iteration:

* BUNDLE_EXTENSION property sets whether it should be a .plugin or .bundle when built with makefiles

* target property BUNDLE instead of CFBUNDLE

There is still one place where the extension is hardcoded in cmExportInstallFileGenerator.cxx simply because I haven't a clue how to fix it; I simply copied other similar entries.

I'd really like to see this make it into 2.8.4, so please let me know if I can help in some way. I'm usually around on irc.freenode.net in #firebreath; I don't know where to find ya'll, however, since you don't seem to ever be in #cmake =]
(0024592)
David Cole   
2011-01-11 13:31   
Patch modified and applied and just now pushed to 'next' with this commit:
http://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5457b8254cb43e002fe90b7c81ae65134ec12b24 [^]

In the course of verifying and applying this patch, I had to:
- add documentation for the new "BUNDLE_EXTENSION" target property
- remove the mods in the IsFramework chunk (I decided a secondary clean up pass later to refactor and unify .app/.framework/.bundle bundles would be more appropriate...)
- fix line length issues (no lines longer than 78 characters allowed in cxx code)
- fix the test to use "" around its target property LINK_FLAGS so that spaces in path names are ok
- remove trailing white space
- remove leading tabs
- add a call to the test in to Tests/CMakeLists.txt

But the vast majority of the original patch is in the above referenced commit...
(0024593)
David Cole   
2011-01-11 13:34   
I did not get this fix pushed to 'next' in time to make it into the rc1 release candidate for CMake 2.8.4 (I don't think...) The deadline for that was last night
at 8pm Eastern time.

After verification on all the nightly dashboard machines overnight tonight, this commit will be eligible for merging into 'master' -- after which point, it should be ok to get it into either: (a) the next release candidate for 2.8.4, or (b) definitely right after 2.8.4 release and in time for the next CMake release 3 months from now.

So: I am marking this as resolved 'fixed' -- but I will not mark the 'fixed in version' field until I know which version it's going to end up in...
(0024611)
David Cole   
2011-01-12 05:53   
Dashboard results went well last night. The only test failure was on the ancient Xcode 1.5 build that we still do on the 'midworld' dashboard client. I am calling this successful, and simply going to exclude that test on that particular build, as detailed by this cvs commit:

davidcole@qwghlm : DashboardScripts
$ cvs diff
cvs diff: Diffing .
Index: midworld_cmake_XCode.cmake
===================================================================
RCS file: /cvsroot/CMake/DashboardScripts/midworld_cmake_XCode.cmake,v
retrieving revision 1.7
diff -r1.7 midworld_cmake_XCode.cmake
4a5
> set(CTEST_TEST_ARGS EXCLUDE "^CFBundleTest$")

davidcole@qwghlm : DashboardScripts
$ cvs commit -m "Exclude new CFBundleTest on oldest Xcode dashboard alive. Not worth the time to figure it out and fix it on this ancient platform. The test works on *all* other Mac dashboards. Even the Makefile-based one on the same machine." midworld_cmake_XCode.cmake
Committer: David Cole <David.Cole@kitware.com>
/cvsroot/CMake/DashboardScripts/midworld_cmake_XCode.cmake,v <-- midworld_cmake_XCode.cmake
new revision: 1.8; previous revision: 1.7
(0026718)
David Cole   
2011-06-06 18:25   
Closing resolved issues that have not been updated in more than 3 months.