xcodebuild: simulator or device? - iphone

How do I specify to xcodebuild (the command line tool) whether I want to build for the simulator or device?

An Xcode build from the command line looks like:
xcodebuild -configuration ${BUILD_TYPE} -target ${TARGET_NAME} -arch ${CPU_ARCHITECTURE} -sdk ${SIMULATOR_OR_IOS_SDK}
BUILD_TYPE is something like "Release" or "Debug" (those are the defaults, you may have added others to the project)
TARGET_NAME is the name of the target you are building (by default the same name as your project)
CPU_ARCHITECTURE is the CPU you are building for, one of:
i386, armv6, armv7
Use i386 for simulator builds, and use either armv6 or armv7 for device builds - note that some other devices cannot run armv7 code, so usually when building libraries it's a good idea to build all of these architectures and then glue them together using lipo.
SIMULATOR_OR_IOS_SDK is what you are looking for, it's either iphoneos or iphonesimulator. Those values use the latest version of the SDK that the installed Xcode supports, you can get a list of supported SDK's with:
xcodebuild -showsdks
Which returns a list like:
Mac OS X SDKs:
Current Mac OS -sdk
Mac OS X 10.6 -sdk macosx10.6
iOS SDKs:
iOS 4.2 -sdk iphoneos4.2
iOS Simulator SDKs:
Simulator - iOS 3.2 -sdk iphonesimulator3.2
Simulator - iOS 4.0 -sdk iphonesimulator4.0
Simulator - iOS 4.1 -sdk iphonesimulator4.1
Simulator - iOS 4.2 -sdk iphonesimulator4.2
xcodebuild has more flags than that, but those are the ones you'd commonly use after using Xcode to set up the build properties. You don't have to use all of them, but it's probably a good idea to be clear about what you are building - otherwise I believe your last settings are used.

i find the -xcconfig flag quite useful. this option allows you to specify a path to an xcconfig (build settings file). within an xcconfig, you may #include other xcconfig files.

Related

Swift private Framework with backward xcode version compatibility

This is my first framework using Swift language and it's private framework. It's worked as expected until new Xcode 9.3 release. After upgrading newer Xcode got an issue like this Module compiled with Swift 4.0.3 cannot be imported in Swift 4.1.
After that only I realized framework doesn't support auto version (Xcode/Swift) upgrade, Did some search found there is a Universal or Fat Binary Framework single build instead of separate build for real device and simulator which I missed in previously.
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Next, work out if we're in SIM or DEVICE
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
BUILD_PRODUCTS="${SYMROOT}/../../../../Products"
cp -R "${BUILD_PRODUCTS}/Debug-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_PRODUCTS}/Debug-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
fi
At Edit Scheme -> Archive -> Post-Action -> Run Script
This time I am used Swift Compiler - Language -> Swift 3.3
And I got expected output this time too in Xcode 9.3 with Swift 4.1
When I try to run the project with this framework at Xcode 9.2 it's show error like this
Module compiled with Swift 4.1 cannot be imported in Swift 3.2.3:
Try to resolve with backward compatibility and I didn't find. How can I run this framework in Xcode 9.2
Framework support: Swift and Objective C, Min OS iOS 8.0
**Update**
Also got something like this error
compiled with newer version of Swift language (unknown ABI version 0x06) than previous files (4.0) file 'MAC location' for architecture armv7
And tried this to my project

Swift fat framework w/Objective-C Cocoapod

I've built a framework in Swift. The framework uses Cocoapods, one of the pods is written in Objective C.
I also use a custom script to make the framework a fat framework so it supports 32/64 bit systems. (This runs in a separate target on the project and I'm wondering if that has something to do with it?)
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"
// Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
//Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
// Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
// Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
// Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
// Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
fi
When I create this fat framework and put it into a project I'd like to use it on the compiler always fails b/c the project can't see the objective C cocoa pod module.
clang: error: linker command failed with exit code 1 (use -v to see invocation)
ld: framework not found Pusher for architecture x86_64
It is not found for any architecture when I change the build platform.
Any solution where I can produce a framework that I can use in a separate Xcode project (for all iOS or OS X) would be awesome.
You can't run xcodebuild with -target when using CocoaPods. When you use -target, Xcode will only consider the active project and fail to pull in the Pod dependencies, similar to if you just opened the project file in Xcode and tried building.
You should be running xcodebuild -workspace "${PROJECT_NAME}.xcworkspace" -scheme "${PROJECT_NAME}" ..., assuming that CocoaPods generated the workspace and Xcode generated a scheme using the target name. You will also need to make sure your scheme is marked as shared if running this on another device.
Once your framework is built you will need to include it and the frameworks it depends on in apps that will be using it. For your framework, that means including it in General > Embedded Binaries and General > Linked Frameworks and Libraries. For frameworks you depend on, (e.g. AlamoFire), you could instruct users to include it in their Podfile, you could package it and ship it along with your framework, or you could do both and let the user do what works for them.
Apparently you are missing the 64bit architecture for Simulator.
When you build a target from Xcode, depending on what kind of simulator you have selected - the produced library will contains i386 or x86_64 respectively for selected 32bit or 64bit version of the simulator.
I guess that the cli build is producing only i386 version.
You can try to set the architectures in the script:
xcodebuild -target "${PROJECT_NAME}" ARCHS="i386 x86_64" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
As an alternative You can try to build by hand using 64bit simulator (iPhone 5S +), then extract the missing architecture and then put it into the final library using lipo command.

Fat libraries in XCode 5

I've been trying to build a static library and then create a binding project from it in Xamarin. Everything was working fine until iOS 7 hit. I had to grab the latest version of the native library and try and build it in XCode 5, but it's been giving me all kinds of problems. I think it might be related to the build process or possibly some changed setting in XCode 5 (vs. 4) but I'm not sure.
I was using this script to build a universal binary which is based of work in this question:
Build fat static library (device + simulator) using Xcode and SDK 4+
One thing I did notice is that previous, in the old iOS 6.1 version of my binary (built in XCode 4), my binary was about 24 Mb, now with XCode 5 it's ballooned to almost 50 Mb! Which is leading me to think that there is something wrong with the compiling and linking step.
Any ideas? Has anybody else encountered problems with universal binaries in XCode 5 (vs 4)?
I'm using the makefile below for my library and it works flawless even with XCode 5 and the iOS7 SDK.
XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
PROJECT_ROOT=.
PROJECT=$(PROJECT_ROOT)/GIFLibFrontEnd.xcodeproj
TARGET=GIFLibFrontEnd
all: libUniversal.a
libi386.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $#
libArmv7.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $#
libArmv7s.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7s -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $#
libArm64.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch arm64 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $#
libUniversal.a: libi386.a libArmv7.a libArmv7s.a libArm64.a
lipo -create -output lib$(TARGET)Universal.a $^
clean:
-rm -f *.a *.dll
-rm -rf build
Here's a link to a Makefile with the tabs, and I made a little change to separate out the target name from the library name. Thanks very much for this! This solved my problem!

Xcode 5 and iOS 7: Architecture and Valid architectures

I'm starting new project in Xcode 5. I want to develop application using iOS SDK 7 but with deployment target iOS 5.0. As soon as I create new project in Xcode and try to change deployment target to 5.0, I've got this message:
Applications including an arm64 slice are not compatible with versions of iOS
prior to 6.0
Adjust your Architectures build setting to not include arm64 in order to deploy
to releases prior to iOS 6.0.
So changed architectures to Standard (no 64bit). I compiles, runs but I do not really understand what just happend.What's the difference between Architectures and Valid architectures settings in Xcode project Build Settings?If I set Architectures to exclude 64-bit what happens when I run my app on 64-bit iPhone or iOS Simulator (I know it works, I'm just curious what hapens underneath)?Can you explain big mess with new 64-bit architecture?
Set the architecture in build setting to Standard architectures(armv7,armv7s)
iPhone 5S is powered by A7 64bit processor. From apple docs
Xcode can build your app with both 32-bit and 64-bit binaries included. This combined binary requires a minimum deployment target of iOS 7 or later.
Note: A future version of Xcode will let you create a single app that supports the 32-bit runtime on iOS 6 and later, and that supports the 64-bit runtime on iOS 7.
From the documentation what i understood is
Xcode can create both 64bit 32bit binaries for a single app but the
deployment target should be iOS7. They are saying in future it will
be iOS 6.0
32 bit binary will work fine in iPhone 5S(64 bit processor).
Update (Xcode 5.0.1)
In Xcode 5.0.1 they added the support to create 64 bit binary for iOS 5.1.1 onwards.
Xcode 5.0.1 can build your app with both 32-bit and 64-bit binaries included. This combined binary requires a minimum deployment target of iOS 5.1.1 or later. The 64-bit binary runs only on 64-bit devices running iOS 7.0.3 and later.
Update (Xcode 5.1)
Xcode 5.1 made significant change in the architecture section. This answer will be a followup for you.
Check this
My understanding from Apple Docs.
What is Architectures (ARCHS) into Xcode build-settings?
Specifies architecture/s to which the binary is TARGETED. When specified more that one architecture, the generated binary may contain object code for each of the specified architecture.
What is Valid Architectures (VALID_ARCHS) into Xcode build-settings?
Specifies architecture/s for which the binary may be BUILT.
During build process, this list is intersected with ARCHS and the resulting list specifies the architectures the binary can run on.
Example :- One iOS project has following build-settings into Xcode.
ARCHS = armv7 armv7s
VALID_ARCHS = armv7 armv7s arm64
In this case, binary will be built for armv7 armv7s arm64 architectures. But the same binary will run on ONLY ARCHS = armv7 armv7s.
When you set 64-bit the resulting binary is a "Fat" binary, which contains all three Mach-O images bundled with a thin fat header. You can see that using otool or jtool. You can check out some fat binaries included as part of the iOS 7.0 SDK, for example the AVFoundation Framework, like so:
% cd /Developer/Platforms/iPhoneOS.platform/DeviceSupport/7.0\ \(11A465\)/Symbols/System/Library/Frameworks/AVFoundation.framework/
%otool -V -f AVFoundation 9:36
Fat headers
fat_magic FAT_MAGIC
nfat_arch 3
architecture arm64 # The 64-bit version (A7)
cputype CPU_TYPE_ARM64
cpusubtype CPU_SUBTYPE_ARM64_ALL
capabilities 0x0
offset 16384
size 2329888
align 2^14 (16384)
architecture armv7 # A5X - packaged after the arm64version
cputype CPU_TYPE_ARM
cpusubtype CPU_SUBTYPE_ARM_V7
capabilities 0x0
offset 2359296
size 2046336
align 2^14 (16384)
architecture armv7s # A6 - packaged after the armv7 version
cputype CPU_TYPE_ARM
cpusubtype CPU_SUBTYPE_ARM_V7S
capabilities 0x0
offset 4407296
size 2046176
align 2^14 (16384)
As for the binary itself, it uses the ARM64 bit instruction set, which is (mostly compatible with 32-bit, but) a totally different instruction set. This is especially important for graphics program (using NEON instructions and registers). Likewise, the CPU has more registers, which makes quite an impact on program speed. There's an interesting discussion in http://blogs.barrons.com/techtraderdaily/2013/09/19/apple-the-64-bit-question/?mod=yahoobarrons on whether or not this makes a difference; benchmarking tests have so far clearly indicated that it does.
Using otool -tV will dump the assembly (if you have XCode 5 and later), and then you can see the instruction set differences for yourself. Most (but not all) developers will remain agnostic to the changes, as for the most part they do not directly affect Obj-C (CG* APIs notwithstanding), and have to do more with low level pointer handling. The compiler will work its magic and optimizations.
You do not need to limit your compiler to only armv7 and armv7s by removing arm64 setting from supported architectures.
You just need to set Deployment target setting to 5.1.1
Important note: you cannot set Deployment target to 5.1.1 in Build Settings section because it is drop-down only with fixed values. But you can easily set it to 5.1.1 in General section of application settings by just typing the value in text field.
Simple fix:
Targets -> Build Settings -> Build Options -> Enable Bitcode -> No
Works on device with iOS 9.3.3
None of the answers worked and then I was forgetting to set minimum deployment target which can be found in Project -> General -> Deployment Info -> Deployment Target -> 8.0

Malformed metadata record for architecture i386

I just upgraded from Xcode 4 to Xcode 4.2 and now I'm getting the following error when building for the Simulator:
ld: in /Users/rstaicut/Library/Developer/Xcode/DerivedData/iphone/Build/Intermediates/iphone.build/QA Server-iphonesimulator/Project iPhone Debug.build/Objects-normal/i386/CartController.o, could not parse object file
/Users/rstaicut/Library/Developer/Xcode/DerivedData/iphone/Build/Intermediates/iphone.build/QA Server-iphonesimulator/Project iPhone Debug.build/Objects-normal/i386/CartController.o:
**Malformed metadata record for architecture i386**
**Command /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin/llvm-gcc-4.2 failed with exit code 1**
One thing to note is that I've changed the compiler to LLVM GCC 4.2 for this upgrade and I'm using armv6 and armv7 for the architectures. I'm only getting this error for the Simulator, the build finishes for the device.
Any ideas what malformed metadata record could mean?
Got the simulator to finally work. These are the things I changed:
Under Project > Build Settings > Architectures > Valid Architectures I took out i386 and left only armv6 and armv7. Under architectures I only have armv6 and armv7
I changed the Compiler from LLVM GCC 4.2 to Apple LLVM compiler 3.0 (Under Project > Build Settings > Build Options > Compiler for C/C++/Objective-C
Changed the iOS Deployment target from iOS 3.1 to iOS 4.0
The last step was to press on "Validate settings" (the button in the middle on the bottom). It's going to ask you to change some settings for the compiler from LLVM GCC to Apple LLVM Compiler 3.0. Hit OK.
My simulator started magically working after that. No errors, though plenty of warnings due to the change in compiler.
Hope this helps anyone else who runs into this issue.