NEWS: THIS SCRIPT IS NO LONGER NECESSARY?
2008 Sep 13. Before investing time in this script, please read the top "Significant Bug Fixes from Xcode 3.1" in the Xcode 3.1.1 Release Notes. I haven't tried it yet, but it appears that Apple has identified the problem solved by this script as a bug in Xcode, and fixed it.
PURPOSE
This script can be used in Xcode projects for copying private frameworks to the product's Contents/Frameworks. It replaces the "Copy Files Build Phase" for this purpose, using the same pbxcp tool, but has several advantages, listed below.
1. Copy Files always copys the "Release" configuration regardless of the current configuration being built. (You don't notice this when running products from within Xcode, because some "clever" trickery in Xcode apparently tells the app to load the proper, e.g. Debug, framework, instead of the one in its package.)
This can bite you in at least two ways:
1.1 Although you get the correct framework when running in Xcode, the wrong (packaged) framework runs when running a non-Release product by doubleclicking in the Finder, or after copying it to another Mac. Once, I wanted to find a crash by copying a ReleaseUnstripped configuration of my app on an old Powerbook (PowerPC) running Panther. Instead, without telling me, my test ran with the Release build, which was, at the time, down-rev. Not a happy day.
1.2 If you clean the Release version of a framework and then do a non-Release build of the app, during the Copy Files (to Frameworks) build phase, pbxcp will fail with a source-directory-not-found error. Another unhappy day troubleshooting why my clean-and-build-all-configurations script failed unpredictably.
2. The Copy Files build phase will not accept (as drags) frameworks which are not linked in the main .app. Sometimes I have bundles which use a later minimum deployment OS than the main app, and such a bundle may need frameworks also using the later OS. They cannot be linked into the main app, but still must be copied into Contents/Frameworks.
3. Even in "Release" builds, with -strip-debug-symbols enabled, pbxcp does not strip out the Headers, and the top-level symlinks to the Headers, in the frameworks copied to the product. This script detects when a build is "Release" and does so.
USAGE
If you are copying private frameworks from other Xcode projects, you already know that you must have configured in Xcode Preferences > Building (or at least in all relevant projects) a Customized Location for all of your Build Products. The full path to the this with the current-configuration subdirectory (e.g. "Debug" or "Release") appended is available in Run Shell Script build phases as $BUILT_PRODUCTS_DIR, $TARGET_BUILD_DIR, $CONFIGURATION_BUILD_DIR. (In my projects, the three values have always been identical but there are subtle differences that are explained in Apple's Xcode Build Setting Reference.) I've created a "Scripts" directory relative to that and have placed this script in it. So, in my case, I add a line such as the following to my Run Script Build Phase:
"$BUILT_PRODUCTS_DIR/../../Scripts/cpframeworks.pl" "$BUILT_PRODUCTS_DIR" "$PRODUCT_NAME.app" MyPrivateFramework1 MyPrivateFramework2 MyPrivateFramework3 etc.
DOWNLOAD
I think that unzipping preserves permissions, but if it doesn't, remember to set the permissions to something like octal 0777.
Download cpframeworks.pl (16 KB).

