I have an Xcode project with many targets. Six of them are aggregates which build final release products (static libraries, frameworks) using Run Scripts under Build Phases. I can build them each individually fine, but I can't find any way to hit "one button" to build them all.
Approach #1
First I tried using -alltargets from the command line, like so:
xcodebuild -project MyProject.xcodeproj -alltargets
With that I get errors on my test targets, claiming that they aren't built for testing. I don't know what that means because they normally "test" correctly. Something is different when attempted this way. But technically it's including targets I'm not interested in. I wouldn't mind much if it worked.
Approach #2
Next I tried making an aggregate which had a run script that individually built each aggregate target, like so:
xcodebuild -project MyProject.xcodeproj -target FirstAggregateTarget
xcodebuild -project MyProject.xcodeproj -target SecondAggregateTarget
xcodebuild -project MyProject.xcodeproj -target ThirdAggregateTarget
xcodebuild -project MyProject.xcodeproj -target FourthAggregateTarget
xcodebuild -project MyProject.xcodeproj -target FifthAggregateTarget
xcodebuild -project MyProject.xcodeproj -target SixthAggregateTarget
It doesn't get any errors from Xcode's point of view, but several of the aggregates just don't build properly. Somehow the run scripts in the individual aggregates were influenced by the top-level aggregate, I guess.
Approach #3
Next I then tried making a new "RELEASE_PRODUCTS" scheme that in the build section had the six aggregates listed. With that I got errors like this:
There were also other obscure errors about build products not being found where they were expected to be.
Approach #4
Next I created a script that I run completely outside of Xcode, like so:
#!/bin/bash
# Builds all release products
xcodebuild -project MyProject.xcodeproj -target FirstAggregateTarget
xcodebuild -project MyProject.xcodeproj -target SecondAggregateTarget
xcodebuild -project MyProject.xcodeproj -target ThirdAggregateTarget
xcodebuild -project MyProject.xcodeproj -target FourthAggregateTarget
xcodebuild -project MyProject.xcodeproj -target FifthAggregateTarget
xcodebuild -project MyProject.xcodeproj -target SixthAggregateTarget
That seems to be the only thing that works. But I wish I could get this to work from within Xcode, preferably as something I could hit from the command line if I wanted to, because then I wouldn't have to leave the IDE and it could report to be success or fail.
You could make a dummy target that depends on the other six. Use Target Dependencies in the Build Phases tab
Inspired by sansumbrella's answer in another forum.
Create a new target in your project (I chose to use a CLI tool since my project is CLI based).
According to sansumbrella, you can create an application and delete its plist. My approach does not rely on any special (or non-existent) plists.
Give your target a name, such as ALL, satisfy the remaining fields, and press "Finish".
Click on the new target's Build Phases link and:
Delete the entry in the Compile Sources, which will be main.c if you're doing it how I did.
Open the Target Dependencies and add all the other targets by clicking the + or dragging targets into this space.
You can now build and clean your whole project when you have this target selected as the active schema.
Related
When you open a Package.swift file, Xcode will generate a workspace with the path: .swiftpm/xcode/package.xcworkspace.
I'd like to use xcodebuild to build this but it does not seem to work. The error messages are not helpful, just tells me that clang failed.
The actual command I'm running is:
xcodebuild -workspace .swiftpm/xcode/package.xcworkspace -scheme MyLibrary-Package -sdk iphonesimulator OTHER_SWIFT_FLAGS="-D SWIFT_PACKAGE"
Funny enough, trying to build a scheme that describes an individual target works:
xcodebuild -workspace .swiftpm/xcode/package.xcworkspace -scheme SpecificTarget -sdk iphonesimulator OTHER_SWIFT_FLAGS="-D SWIFT_PACKAGE"
Am I missing some build flags needed to build the combination scheme? Has anyone else struggled with this and have any advice?
Note:
The ultimate goal here is to be able to verify that my Swift Package builds in CI. If there is an easier way to achieve this goal then I'm happy to go another route. (The easier might just be multiple commands to build the individual targets but this is less robust)
Let's say I do the following:
Open Xcode 7
File | New | Project | Cocoa Touch Framework
Create "TestFramework" with the Swift language
Create a file Hello.swift with public func hello() { print("Hello") }.
From here, I can build a debug build of the framework (inside the Debug-iphoneos folder), but I cannot figure out how to build the release version of the framework (inside Release-iphoneos). I thought Archive might do it, but it doesn't. Pointers please?
To get a release build, you need to change your scheme settings:
Alternatively, create a new scheme for release builds.
Ensure you have a device selected. Not the simulator.
Build your project and you should see that it gets added to this location:
(Click the arrow to navigate there in finder)
And after drilling down, you should be able to find the release folder with your release framework inside.
This works for me:
Select your framework target then click Product -> Archive. If organizer window does not pop up after successful build of your framework then go to "Build Settings" of your framework target, look for the option "Skip Install" and change it to "No" (and after that Archive again).
An alternative to building a framework via the Xcode IDE is to build it from the command line.
You can produce a release build of your framework for iphoneos devices with the following command:
xcodebuild -workspace TestSDK.xcworkspace -scheme TestSDK -configuration Release -sdk iphoneos
You can change the value of the -configuration argument from Release to Debug in order to produce a debug build, or change the value of the -sdk argument from iphoneos to iphonesimulator in order to produce a build for Simulator devices.
Note that you may need to provide the -project argument instead of -workspace if your target is part of an Xcode project only and not part of an Xcode workspace. Run the xcodebuild -help command for the full list of xcodebuild options.
If you prefer to archive, you can do that from the command line also, as follows:
xcodebuild archive -workspace TestSDK.xcworkspace -scheme TestSDK -configuration Release -sdk iphoneos -archivePath "TestSDK_Release_iphoneos.xcarchive" SKIP_INSTALL=NO
Note that you can specify SKIP_INSTALL=NO as part of your project or target's Build Settings instead if you prefer.
Lastly, if you want to join up your iphoneos and iphonesimulator builds into a single binary, you can do that with the xcodebuild -create-xcframework command as follows:
xcodebuild -create-xcframework \
-framework "TestSDK_Release_iphoneos.xcarchive/Products/Library/Frameworks/TestSDK.framework" \
-framework "TestSDK_Release_iphonesimulator.xcarchive/Products/Library/Frameworks/TestSDK.framework" \
-output "TestSDK.xcframework"
See here for the official guide to creating an XCFramework.
When you add the framework to your other Xcode project then you have to add "$(BUILT_PRODUCTS_DIR)" to Build Settings -> Framework Search Paths.
This will create Debug when you run project (with Debug) and will create Release version when you archive project.
The archive doesn't will create Release version under Products dir but will create Release in "Intermediates.noindex" folder.
I have a framework project and I'm trying to build a fat file (iphoneos + iphonesimulator) using a script build phase, but it's not working. The script is simple; it checks the platform being currently built, like to:
if [[ "$SF_SDK_PLATFORM" = "iphoneos" ]]
then
SF_OTHER_PLATFORM=iphonesimulator
else
SF_OTHER_PLATFORM=iphoneos
fi
And then uses xcodebuild to build it:
xcrun xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -sdk ${SF_OTHER_PLATFORM} -configuration "${CONFIGURATION}" BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}" $ACTION
Other details on the script have been omited for simplicity.
If I chose the initial target as the simulator, this works fine, and both the simulator and device binaries are generated and I use lipo to get the fat file. The problem happens when I do it the other way around, and build the device file, and as such xcodebuild is called for the iphonesimulator SDK. The build fails with the following error:
CodeSign error: entitlements are required for product type 'Framework' in SDK 'Simulator - iOS 8.4'. Your Xcode installation may be damaged.
If I change the -sdk option I get the build, but not the simulator build, which is what I need. This would be (kinda) fine, but in order to build for release (Archive) I need to set the device as the primary target, or otherwise xcode doesn't give me the option.
What should I do?
It looks like you need to put your script in an aggregate target type. It was designed for exactly such cases: two different targets in one build.
What I do is create a new target (Other->Aggregate type) and add a script to it and use that target to create a fat release product.
Here's the script I'm using:
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -sdk iphonesimulator -configuration Release
xcodebuild -workspace MyApp.xcworkspace -scheme MyApp -sdk iphoneos -configuration Release
mkdir -p ${TARGET_BUILD_DIR}/../MyApp${CURRENT_PROJECT_VERSION}
cp -r ${TARGET_BUILD_DIR}/../Release-iphoneos/ ${TARGET_BUILD_DIR}/../MyApp${CURRENT_PROJECT_VERSION}
lipo -create "${TARGET_BUILD_DIR}/../Release-iphoneos/MyApp.framework/MyApp" "${TARGET_BUILD_DIR}/../Release-iphonesimulator/MyApp.framework/MyApp" -output "${TARGET_BUILD_DIR}/../MyApp${CURRENT_PROJECT_VERSION}/MyApp.framework/MyApp"
Works like a charm. It creates a folder with the version number (you set it in your new target) and a fat framework inside.
EDIT:
Why this didn't work for you.
Developer is free to distribute iOS framework without codesigning it
as Consumer will re-codesign it anyway, but Developer is forced by
Xcode to codesign his framework when he builds for iOS device.
Creating iOS/OSX Frameworks: is it necessary to codesign them before distributing to other developers?
When you're using the device target you're forced to code sign even if you don't have to. That's why it works with the aggregate target -> it's not expected of you to codesign and you don't need to codesign to release a framework.
Selecting the simulator, the process works fine because you are building using the Debug configuration I think.
In the Project navigator, select your project. Now select your target and under the Build Settings tab, check Code Signing Identity settings.
If you expand that, you should see a row for every configuration you set in your project (if you didn't, you should see the default Debug and Release rows).
Now check under the Release row (that is the default used when the Archive command is called) that is set the correct identity (this is based on what you selected under Provisioning Profile).
If you want to know more about provisioning profiles, signing identity and so on, check this link from Apple
I'm trying to build several targets and I already have Build Settings per target in Xcode. I also have a scheme per target. What I'm trying to do is issue one command line instruction to build each target, something like:
xcodebuild -project MyProject.xcodeproj -scheme PRODScheme archive
-archivePath /Users/myUser/Documents/PRODApps/archives/"${PRODUCT_NAME}".xcarchive
-configuration Release
Here, ${PRODUCT_NAME} is the Build Setting variable defined by XCode. I'm thinking on how xcodebuild can make use of the bunch of already defined settings.
Is there a way of reusing those settings in xcodebuild?
Typically you would use the scheme, which would contain the other information you are trying to include:
xcodebuild -scheme PRODScheme build
To use with a configuration file you would use:
xcodebuild -target MyProject.xcodeproj -xcconfig configuration.xcconfig
To build all targets use -alltargets
Command Line tech notes: https://developer.apple.com/library/ios/technotes/tn2339/_index.html
Man xcodebuild: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/xcodebuild.1.html
I am trying to build/run my iOS app from command line. To build the app, the command which I give in shell script is as follows:
PROJECT_DIR="/Users/ingenyous/Desktop/splistV11_test_sh_build/code/app/ios"
TARGET_NAME="splistapp2"
TARGET_SDK="iphoneos5.1"
PROJECT_BUILD_DIR="${PROJECT_DIR}/build/Release-iphoneos"
OUTPUT_DIR="/Users/ingenyous/Desktop/ipa"
# compile project
echo Building Project
cd "${PROJECT_DIR}"
xcodebuild -target "${TARGET_NAME}" -sdk "${TARGET_SDK}" -configuration Release
Here I specify the target name and other parameters. Is it possible to give the target properties like product name and other options in this script itself, which can overwrite the properties given actually in the editor target. or be able to create the target itself from shell script and not needing to create targets from Xcode editor.
You can certainly set the product name using xcodebuild:
xcodebuild -target "${TARGET_NAME}" -configuration Release build PRODUCT_NAME=MyProduct
There can be issues with multiple targets, see this existing SO question
You can set any build setting in this way. A full list of build settings is available on Apple's developer site, and you can also check out the man for xcodebuild.