使用Xcode和SDK 4+构建胖静态库(设备+模拟器) [英] Build fat static library (device + simulator) using Xcode and SDK 4+

查看:69
本文介绍了使用Xcode和SDK 4+构建胖静态库(设备+模拟器)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

看来我们理论上可以构建一个包含模拟器,iPhone和iPad的静态库。

It appears that we can - theoretically - build a single static library that includes both simulator and iPhone and iPad.

然而,Apple没有关于此的文档我可以找到,并且Xcode的默认模板没有配置为执行此操作。

However, Apple has no documentation on this that I can find, and Xcode's default templates are NOT configured to do this.

我正在寻找一种可以在Xcode中完成的简单,可移植,可重用的技术。

I'm looking for a simple, portable, re-usable technique that can be done inside Xcode.

一些历史记录:


  • 2008年,我们曾经能够制作单个静态库,包括sim和设备。 Apple禁用了它。

  • 在整个2009年,我们制作了一对静态库 - 一个用于sim,一个用于设备。 Apple现在也禁用了它。

参考文献:


  1. 这是一个好主意,它是一种很好的方法,但它不起作用: http://www.drobnik.com/touch/2010/04/universal-static-libraries/


  • 他的脚本中存在一些错误,这意味着它只能在他的机器上运行 - 他应该使用BUILT_PRODUCTS_DIR和/或BUILD_DIR而不是猜测它们。)

  • Apple的最新的Xcode阻止你做他做的事情 - 由于Xcode处理目标的方式有(记录)改变,它根本不起作用)

另一位SO提问者询问如何在不使用xcode的情况下执行此操作,以及专注于arm6与arm7部分的响应 - 但忽略了i386部分:如何我为armv6,armv7和i386编译一个静态库(胖)

Another SO questioner asked how to do it WITHOUT xcode, and with responses that focussed on the arm6 vs arm7 part - but ignored the i386 part: How do i compile a static library (fat) for armv6, armv7 and i386


  • 由于Apple的最新更改,模拟器部分不是与arm6 / arm7的差异不再相同 - 这是一个不同的问题,见上文)


推荐答案

替代方案:

轻松复制/粘贴最新版本(但安装说明可能会更改 - 请参阅下文!)

Easy copy/paste of latest version (but install instructions may change - see below!)

卡尔的图书馆需要花费更多精力来设置,但更好的长期解决方案(它将您的库转换为框架)。

Karl's library takes much more effort to setup, but much nicer long-term solution (it converts your library into a Framework).

使用此选项,然后调整它以添加对存档构建的支持 - cf @Frederik在下面评论了他用来使存档模式很好地工作的更改。

Use this, then tweak it to add support for Archive builds - c.f. @Frederik's comment below on the changes he's using to make this work nicely with Archive mode.

最近更改:
1.增加了对iOS 10.x的支持(同时保持对旧平台的支持)

RECENT CHANGES: 1. Added support for iOS 10.x (while maintaining support for older platforms)


  1. 有关如何使用此脚本的信息项目嵌入在另一个项目中(虽然我强烈建议不要这样做,但是 - 如果你将项目嵌入到彼此内部,从Xcode 3.x到Xcode 4.6,Apple在Xcode中会有一些显示阻塞错误.x)

  1. Info on how to use this script with a project-embedded-in-another-project (although I highly recommend NOT doing that, ever - Apple has a couple of show-stopper bugs in Xcode if you embed projects inside each other, from Xcode 3.x through to Xcode 4.6.x)

Bonus脚本让你自动包含Bundles(即包括来自你库的PNG文件,PLIST文件等) - 见下文(滚动到底部)

Bonus script to let you auto-include Bundles (i.e. include PNG files, PLIST files etc from your library!) - see below (scroll to bottom)

现在支持iPhone5(使用Apple的解决方案来处理lipo中的错误)。注意:安装说明已更改(我可以通过以后更改脚本来简化此操作,但现在不想冒风险)

now supports iPhone5 (using Apple's workaround to the bugs in lipo). NOTE: the install instructions have changed (I can probably simplify this by changing the script in future, but don't want to risk it now)

copy headerssection现在尊重公共标题位置的构建设置(由Frederik Wallner提供)

"copy headers" section now respects the build setting for the location of the public headers (courtesy of Frederik Wallner)

添加了SYMROOT的显式设置(可能需要OBJROOT)设置呢?),感谢Doug Dickinson

Added explicit setting of SYMROOT (maybe need OBJROOT to be set too?), thanks to Doug Dickinson






SCRIPT(这个是您必须复制/粘贴的内容)


SCRIPT (this is what you have to copy/paste)

有关使用/安装说明,请参阅下文

For usage / install instructions, see below

##########################################
#
# c.f. https://stackoverflow.com/questions/3520977/build-fat-static-library-device-simulator-using-xcode-and-sdk-4
#
# Version 2.82
#
# Latest Change:
# - MORE tweaks to get the iOS 10+ and 9- working
# - Support iOS 10+
# - Corrected typo for iOS 1-10+ (thanks @stuikomma)
# 
# Purpose:
#   Automatically create a Universal static library for iPhone + iPad + iPhone Simulator from within XCode
#
# Author: Adam Martin - http://twitter.com/redglassesapps
# Based on: original script from Eonil (main changes: Eonil's script WILL NOT WORK in Xcode GUI - it WILL CRASH YOUR COMPUTER)
#

set -e
set -o pipefail

#################[ Tests: helps workaround any future bugs in Xcode ]########
#
DEBUG_THIS_SCRIPT="false"

if [ $DEBUG_THIS_SCRIPT = "true" ]
then
echo "########### TESTS #############"
echo "Use the following variables when debugging this script; note that they may change on recursions"
echo "BUILD_DIR = $BUILD_DIR"
echo "BUILD_ROOT = $BUILD_ROOT"
echo "CONFIGURATION_BUILD_DIR = $CONFIGURATION_BUILD_DIR"
echo "BUILT_PRODUCTS_DIR = $BUILT_PRODUCTS_DIR"
echo "CONFIGURATION_TEMP_DIR = $CONFIGURATION_TEMP_DIR"
echo "TARGET_BUILD_DIR = $TARGET_BUILD_DIR"
fi

#####################[ part 1 ]##################
# First, work out the BASESDK version number (NB: Apple ought to report this, but they hide it)
#    (incidental: searching for substrings in sh is a nightmare! Sob)

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '\d\{1,2\}\.\d\{1,2\}$')

# Next, work out if we're in SIM or DEVICE

if [ ${PLATFORM_NAME} = "iphonesimulator" ]
then
OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}
else
OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}
fi

echo "XCode has selected SDK: ${PLATFORM_NAME} with version: ${SDK_VERSION} (although back-targetting: ${IPHONEOS_DEPLOYMENT_TARGET})"
echo "...therefore, OTHER_SDK_TO_BUILD = ${OTHER_SDK_TO_BUILD}"
#
#####################[ end of part 1 ]##################

#####################[ part 2 ]##################
#
# IF this is the original invocation, invoke WHATEVER other builds are required
#
# Xcode is already building ONE target...
#
# ...but this is a LIBRARY, so Apple is wrong to set it to build just one.
# ...we need to build ALL targets
# ...we MUST NOT re-build the target that is ALREADY being built: Xcode WILL CRASH YOUR COMPUTER if you try this (infinite recursion!)
#
#
# So: build ONLY the missing platforms/configurations.

if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: I am NOT the root invocation, so I'm NOT going to recurse"
else
# CRITICAL:
# Prevent infinite recursion (Xcode sucks)
export ALREADYINVOKED="true"

echo "RECURSION: I am the root ... recursing all missing build targets NOW..."
echo "RECURSION: ...about to invoke: xcodebuild -configuration \"${CONFIGURATION}\" -project \"${PROJECT_NAME}.xcodeproj\" -target \"${TARGET_NAME}\" -sdk \"${OTHER_SDK_TO_BUILD}\" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO" BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" SYMROOT=\"${SYMROOT}\"

xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"

ACTION="build"

#Merge all platform binaries as a fat binary for each configurations.

# Calculate where the (multiple) built files are coming from:
CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos
CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator

echo "Taking device build from: ${CURRENTCONFIG_DEVICE_DIR}"
echo "Taking simulator build from: ${CURRENTCONFIG_SIMULATOR_DIR}"

CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
echo "...I will output a universal build to: ${CREATING_UNIVERSAL_DIR}"

# ... remove the products of previous runs of this script
#      NB: this directory is ONLY created by this script - it should be safe to delete!

rm -rf "${CREATING_UNIVERSAL_DIR}"
mkdir "${CREATING_UNIVERSAL_DIR}"

#
echo "lipo: for current configuration (${CONFIGURATION}) creating output file: ${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}"
xcrun -sdk iphoneos lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"

#########
#
# Added: StackOverflow suggestion to also copy "include" files
#    (untested, but should work OK)
#
echo "Fetching headers from ${PUBLIC_HEADERS_FOLDER_PATH}"
echo "  (if you embed your library project in another project, you will need to add"
echo "   a "User Search Headers" build setting of: (NB INCLUDE THE DOUBLE QUOTES BELOW!)"
echo '        "$(TARGET_BUILD_DIR)/usr/local/include/"'
if [ -d "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}" ]
then
mkdir -p "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
# * needs to be outside the double quotes?
cp -r "${CURRENTCONFIG_DEVICE_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"* "${CREATING_UNIVERSAL_DIR}${PUBLIC_HEADERS_FOLDER_PATH}"
fi
fi






安装说明


INSTALL INSTRUCTIONS


  1. 创建静态库项目

  2. 选择目标

  3. 在构建设置选项卡中,将仅构建活动架构设置为否 (对于所有项目)

  4. 在Build Phases选项卡中,选择Add ... New Build Phase ... New Run Script Build Phase

  5. 将脚本(上方)复制/粘贴到方框中

  1. Create a static lib project
  2. Select the Target
  3. In "Build Settings" tab, set "Build Active Architecture Only" to "NO" (for all items)
  4. In "Build Phases" tab, select "Add ... New Build Phase ... New Run Script Build Phase"
  5. Copy/paste the script (above) into the box

...奖金可选用法:

...BONUS OPTIONAL usage:


  1. 可选:如果您的库中有标题,请将它们添加到复制标题阶段

  2. 可选:...并将它们从项目部分拖放到公共部分

  3. 可选:......并且它们将自动成为每次构建应用程序时,都会导出到debug-universal目录的子目录中(它们将在usr / local / include中)

  4. 可选:注意:如果您尝试将项目拖放到另一个Xcode项目中,这会暴露出Xcode 4中的错误,如果在拖放项目中有公共标题,则无法创建.IPA文件。解决方法:不要'嵌入xcode项目(Apple代码中有太多错误!)

  1. OPTIONAL: if you have headers in your library, add them to the "Copy Headers" phase
  2. OPTIONAL: ...and drag/drop them from the "Project" section to the "Public" section
  3. OPTIONAL: ...and they will AUTOMATICALLY be exported every time you build the app, into a sub-directory of the "debug-universal" directory (they will be in usr/local/include)
  4. OPTIONAL: NOTE: if you also try to drag/drop your project into another Xcode project, this exposes a bug in Xcode 4, where it cannot create an .IPA file if you have Public Headers in your drag/dropped project. The workaround: dont' embed xcode projects (too many bugs in Apple's code!)

如果找不到输出文件,这是一个解决方法:

If you can't find the output file, here's a workaround:


  1. 将以下代码添加到脚本的最后(由Frederik Wallner提供):打开$ {CREATING_UNIVERSAL_DIR}

  1. Add the following code to the very end of the script (courtesy of Frederik Wallner): open "${CREATING_UNIVERSAL_DIR}"

Apple删除200行后的所有输出。选择你的目标,并在运行脚本阶段,你必须解开:在构建日志中显示环境变量

Apple deletes all output after 200 lines. Select your Target, and in the Run Script Phase, you MUST untick: "Show environment variables in build log"

如果你正在使用自定义的构建输出XCode4的目录,然后XCode将所有意外文件放在错误的位置。

if you're using a custom "build output" directory for XCode4, then XCode puts all your "unexpected" files in the wrong place.


  1. 构建项目

  2. 点击Xcode4左上角右侧的最后一个图标。

  3. 选择顶部项目(这是您的最新版本.Apple应该在主窗口中自动选择它,但他们没有想到这一点。

  4. ,滚动到底部。最后一行应该是:lipo:用于当前配置(Debug)创建输出文件:/Users/blah/Library/Developer/Xcode/DerivedData/AppName-ashwnbutvodmoleijzlncudsekyf/Build/Products/Debug-universal/libTargetName.a

  1. Build the project
  2. Click on the last icon on the right, in the top left area of Xcode4.
  3. Select the top item (this is your "most recent build". Apple should auto-select it, but they didn't think of that)
  4. in the main window, scroll to bottom. The very last line should read: lipo: for current configuration (Debug) creating output file: /Users/blah/Library/Developer/Xcode/DerivedData/AppName-ashwnbutvodmoleijzlncudsekyf/Build/Products/Debug-universal/libTargetName.a

...这是您的Universal Build的位置。

...that is the location of your Universal Build.






如何在项目中包含非源代码文件(PNG,PLIST,XML等)


How to include "non sourcecode" files in your project (PNG, PLIST, XML, etc)


  1. 执行以上所有操作,检查是否有效

  2. 创建一个新的运行脚本阶段,该阶段在第一个之后出现(复制/粘贴下面的代码)

  3. 在Xcode中创建一个类型为bundle的新Target

  4. 在MAIN PROJECT中,在Build Phases中,将新包添加为它取决于的东西(顶部,点击加号按钮,滚动到底部,在你的产品中找到.bundle文件)

  5. 在你的新捆绑目标中,在构建中阶段,添加复制捆绑资源部分,并将所有PNG文件拖放到i中t

  1. Do everything above, check it works
  2. Create a new Run Script phase that comes AFTER THE FIRST ONE (copy/paste the code below)
  3. Create a new Target in Xcode, of type "bundle"
  4. In your MAIN PROJECT, in "Build Phases", add the new bundle as something it "depends on" (top section, hit the plus button, scroll to bottom, find the ".bundle" file in your Products)
  5. In your NEW BUNDLE TARGET, in "Build Phases", add a "Copy Bundle Resources" section, and drag/drop all the PNG files etc into it

将构建的软件包自动复制到与FAT静态库相同的文件夹中的脚本:

Script to auto-copy the built bundle(s) into same folder as your FAT static library:

echo "RunScript2:"
echo "Autocopying any bundles into the 'universal' output folder created by RunScript1"
CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal
cp -r "${BUILT_PRODUCTS_DIR}/"*.bundle "${CREATING_UNIVERSAL_DIR}"

这篇关于使用Xcode和SDK 4+构建胖静态库(设备+模拟器)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆