如何构建ICU以便我可以在iPhone应用程序中使用它?

时间:2011-11-14 18:24:41

标签: iphone ios sqlite icu

如何配置和构建ICU,以便将其链接到我的iPhone应用程序?

我正在维护一个使用SQLite数据库的iPhone应用程序。现在我必须在启用ICU支持的情况下进行编译(SQLITE_ENABLE_ICU)。我有最新的ICU来源。

我正在使用的configure标志:

./configure --target=arm-apple-darwin --enable-static --disable-shared

之后,运行gnumake运行没有错误。

然后我将库添加到我的Xcode项目中。但是当我建立时,我得到50行:

Undefined symbols:
  "_uregex_close_48", referenced from:
      _icuRegexpDelete in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_ubrk_current_48", referenced from:
      _icuNext in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_ucol_strcoll_48", referenced from:
      _icuCollationColl in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_u_isspace_48", referenced from:
      _icuRegexpFunc in libsqlite3-cerod.a(sqlite3_cerod.o)
  "_utf8_countTrailBytes_48", referenced from:
      _utf8_countTrailBytes_48$non_lazy_ptr in libsqlite3-cerod.a(sqlite3_cerod.o)
     (maybe you meant: _utf8_countTrailBytes_48$non_lazy_ptr)
  "_ubrk_next_48", referenced from:
      _icuNext in libsqlite3-cerod.a(sqlite3_cerod.o)

知道我做错了吗?

已编辑添加:

当我将库添加到项目中时(右键单击项目名称,然后添加现有...),我得到了这个:

ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicudata.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicui18n.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicuio.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicule.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libiculx.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicutu.a, file was built for unsupported file format which is not the architecture being linked (i386)
ld: warning: in /Users/eric.grunin/dev/iOS/icu/source/lib/libicuuc.a, file was built for unsupported file format which is not the architecture being linked (i386)

这就是为什么我认为我正在错误地构建库。就好像在说:

  • 它无法分辨为.a文件构建的架构
  • libsqlite3-cerod.a是为i386构建的

我不明白这两种可能性,但我是iPhone开发的新手。

已编辑添加

我尝试了@Sergio Moura的解决方案,并得到了我的评论中提到的错误。

我尝试了@ sergio的解决方案。但我仍然得到相同的错误,从:

开始
ld: warning: in /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicudata.a, file was built for unsupported file format which is not the architecture being linked (i386)

我可能告诉Xcode错误的东西吗?我右键单击项目名称,然后选择“添加 - >现有文件”,并从.a中选择六个或七个/icu/iosbuild/lib文件。这是正确的过程吗?

注意:

@sergio推荐configure --host=arm-apple-darwin,@ Sergio Moura正在使用configure --target=arm-apple-darwin。唉,两者都没有区别。

编辑#2

定位设备(而不是模拟器)解决了除链接错误之外的所有错误!这是剩下的:

Undefined symbols for architecture armv6:
  "___sync_synchronize", referenced from:
      _ucol_initUCA_48 in libicui18n.a(ucol_res.ao)
      udata_getHashTable()      in libicuuc.a(udata.ao)
      _umtx_init_48 in libicuuc.a(umutex.ao)
      _initCache in libicuuc.a(uresbund.ao)
      icu_48::hasService()       in libicui18n.a(coll.ao)
      _ucol_initInverseUCA_48 in libicui18n.a(ucol_bld.ao)
      icu_48::locale_set_default_internal(char const*)in libicuuc.a(locid.ao)
      ...
ld: symbol(s) not found for architecture armv6

之前是这些警告的级联:

ld: warning: CPU_SUBTYPE_ARM_ALL subtype is deprecated: /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicuuc.a(resbund.ao)
ld: warning: CPU_SUBTYPE_ARM_ALL subtype is deprecated: /Users/eric.grunin/dev/iOS/icu/iosbuild/lib/libicuuc.a(ustrfmt.ao)

编辑#3

@Stephen R. Loomis建议我将#define U_HAVE_GCC_ATOMICS1更改为0(在platform.h中)没有任何区别,唉。我也意识到错误的最后一行(not found for architecture arm6)并不意味着它适用于arm7,这只是一个fyi,这是一个交叉编译。当我指定arm7版本时,它失败并显示相同的消息。唉。

编辑#4

成功!

总结:@ sergio的构建标志基本上是正确的。我在-os build的CFLAGS中添加了-DU_HAVE_GCC_ATOMICS = 0。我做错的一件事是没有意识到我需要交叉编译库来创建一个设备构建。

我没有尝试过为模拟器重复此操作,但这不在我的问题范围内。

特别感谢Steven R. Loomis投球,并感谢Sergio Moura让事情顺利进行。

5 个答案:

答案 0 :(得分:5)

编辑:

如果你这样做,我可以证实,正如Steven R. Loomis建议的那样:

  1. 在icu / source / common / unicode / platform.h中将U_HAVE_GCC_ATOMICS设置为0

  2. make distclean

  3. sh cross_configure.sh(使用我的脚本,即如果你正在使用它)

  4. 问题应该解决。实际上,如果不这样做,构建的库包含违规的未定义符号:

    sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
         U ___sync_synchronize
         U ___sync_val_compare_and_swap_4
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
    

    遵循上述建议后,这是同一命令的结果:

    sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
    nm: no name list
    nm: no name list
    

    所以,当然,二进制文件中不存在有问题的符号。

    结束编辑。

    针对iOS的交叉编译libicu需要两个单独的步骤:

    1. 在构建目录中为主机(MacOS)编译libicu;

    2. 通过指定交叉编译目录来交叉编译iOS的libicu。

    3. 第1步是必要的原因是libicu会自行引导一下,即它会编译一些中间工具,然后在构建过程的其余部分使用它们;这些工具需要在主机平台上运行,因此它们可用。

      嗯,总而言之,您可以按照步骤(1.为主机编译):

      $ cd $icu
      $ mkdir hostbuild
      $ cd hostbuild
      $ ../icu/source/configure <configure settings you need>
      $ gnumake
      

      一旦完成,就可以进行交叉编译(2.为iOS编译):

      $ cd $icu  (or cd ../ from the previous directory)
      $ mkdir iosbuild
      $ cd iosbuild
      $ sh ../cross_configure_icu.sh
      $ gnumake
      

      其中cross_configure_icu.sh是一个类似于以上Sergio Moura提议的shell脚本,但是为libicu定制并使用更高级的llvm编译器:

      DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
      SDKROOT=$DEVROOT/SDKs/iPhoneOS4.3.sdk
      SYSROOT=$SDKROOT
      
      ICU_PATH=<ABSOLUTE_PATH_TO_YOUR_ICU_DIR>
      ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_MYSRC/source/tools/tzcode/ "
      
      export CXXPP=
      export CXXPPFLAGS=
      export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/llvm-gcc-4.2/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/include/ -I$SDKROOT/usr/include/c++/4.2.1/armv7-apple-darwin10/ -I./include/ -miphoneos-version-min=2.2 $ICU_FLAGS"
      
      export CFLAGS="$CPPFLAGS -pipe -no-cpp-precomp -isysroot $SDKROOT"
      export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
      export CXXFLAGS="$CFLAGS" 
      export CC="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-gcc-4.2"
      export CXX="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-g++-4.2"
      export LDFLAGS="-L$SDKROOT/usr/lib/ -isysroot $SDKROOT -Wl,-dead_strip -miphoneos-version-min=2.0"
      
      sh $ICU_PATH/source/configure --host=arm-apple-darwin --enable-static --disable-shared -with-cross-build=$ICU_PATH/hostbuild
      

      在上面的脚本(source)中,ICU_PATH是绝对路径,因为libicu配置需要with-cross-build选项。再次,检查SDK和编译器的值,但这应该适用于4.3。

      最后,您应该考虑到Apple已经(一半)拒绝了至少一个与libicu链接的应用程序,因为它使用了保留的API。看看这个S.O. topic

      编辑:

      很高兴听到你可以编译!

      现在,关于链接问题。

      首先,请检查libicu库的格式是否正确:

      sergio@sfogliatella$ lipo -info ./lib/libicuuc.a 
      

      输出应该是(对于任何一个库):

      input file ./lib/libicuuc.a is not a fat file
      Non-fat file: ./lib/libicuuc.a is architecture: arm
      

      如果没问题,那么接下来的问题是:您是在为模拟器还是为设备构建?模拟器需要i386库,设备臂库...来自您显示的错误消息:

        

      ld:warning:...文件是为不支持的文件格式构建的,而不是所链接的体系结构(i386)

      在我看来,你正在建立对抗模拟器...因为你需要“普通”的macos x libs ...

答案 1 :(得分:2)

我使用iOS SDK版本6.1,使用clang并构建c ++ 11标准库。我发现设置环境变量(如CXXFLAGS)没有任何影响,并且尝试将它们传递给命令行上的“configure”似乎完全打破了它。我最终制作了一个clang,clang ++和ld脚本,允许我传入其他参数。例如,我的铿锵脚本:

#This script circumvents gnumake getting rid of our flags. Use the environment variable $MORE_CFLAGS
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang "$@" $MORE_CFLAGS

其他是相同的,但在适当的地方替换clang ++和ld,并分别使用MORE_CXXFLAGS和MORE_LDFLAGS。

最后,我创建了这个脚本,它执行主机构建,模拟器构建和iOS构建。请注意,模拟器构建包括调试信息,iOS版本是-O2优化的。然后它将libs(制作通用二进制文件)与它们一起复制,并将它们与include文件夹一起复制到由INSTALL_PATH指定的目标。第3-5行用于配置脚本。将所有这4个脚本放在同一个文件夹中,并从命令行执行最后一个:

#unpack the ICU source and point $ICU_PATH at it

ICU_PATH="$HOME/Downloads/icu"
ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_PATH/source/tools/tzcode/ "
INSTALL_PATH="$HOME/Documents/git/gamelib/Graphics/Text/icu/51.1"
SDKROOT=`xcrun --sdk iphoneos --show-sdk-path`
SIMULATOR_SDKROOT=`xcrun --sdk iphonesimulator --show-sdk-path`


SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
SAVEPATH=$PATH

cd $ICU_PATH
mkdir host_build
cd host_build
../source/configure
gnumake

PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:$SAVEPATH
cd $ICU_PATH
mkdir iPhoneSimulator_build
cd iPhoneSimulator_build
#PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
#those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
export MORE_CFLAGS="-arch i386 -pipe -std=c99 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
export MORE_CXXFLAGS="-arch i386 -pipe -std=c++11 -stdlib=libc++ -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
export MORE_LDFLAGS="-arch i386 -isysroot $SIMULATOR_SDKROOT -miphoneos-version-min=5.0"
$ICU_PATH/source/configure --enable-debug --disable-release --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneSimulator_build/install" --enable-static=yes --enable-shared=no
gnumake clean
gnumake VERBOSE=1 install

PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$SAVEPATH
cd $ICU_PATH
mkdir iPhoneOS_build
cd iPhoneOS_build
#PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
#those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
export MORE_CFLAGS="-arch armv7 -pipe -std=c99 -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
export MORE_CXXFLAGS="-arch armv7 -pipe -std=c++11 -stdlib=libc++ -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
export MORE_LDFLAGS="-arch armv7 -isysroot $SDKROOT -miphoneos-version-min=5.0"
$ICU_PATH/source/configure --host=arm-apple-darwin --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneOS_build/install" --enable-static=yes --enable-shared=no
gnumake clean
gnumake VERBOSE=1 install

PATH=$SAVEPATH

mkdir "$INSTALL_PATH/lib"
for file in $ICU_PATH/iPhoneOS_build/install/lib/*.a; do
    BASENAME="${file##*/}"
    lipo "$ICU_PATH/iPhoneOS_build/install/lib/$BASENAME" "$ICU_PATH/iPhoneSimulator_build/install/lib/$BASENAME" -create -output "$INSTALL_PATH/lib/$BASENAME"
done

rm -r "$INSTALL_PATH/include"
cp -r "$ICU_PATH/iPhoneOS_build/install/include" "$INSTALL_PATH/include"

答案 2 :(得分:1)

如果您有源,是否真的需要链接库?只需将源添加到您的XCode项目中,您应该好好去...

如果您真的想要构建一个库,我建议您以iPhone为目标为该库创建一个XCode项目,并将该库链接到您的代码,因为您的库是为了在MacOS中运行而构建的电脑(根据您的错误日志)。

修改

要从命令行构建它并假设您没有使用iOS 5(因为您的XCode版本),我借用并调整了这组指令以正确设置标志以正确配置和构建二进制文件从here到您的平台:

export IOS_BASE_SDK=4.2
export IOS_DEPLOY_TGT=4.2
export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS$IOS_BASE_SDK.sdk
export CFLAGS="-arch armv7 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"

export CPP=$DEVROOT/usr/bin/cpp-4.2
export CXX=$DEVROOT/usr/bin/g++-4.2
export CXXCPP=$DEVROOT/usr/bin/cpp-4.2
export CC=$DEVROOT/usr/bin/gcc-4.2
export LD=$DEVROOT/usr/bin/ld
export AR=$DEVROOT/usr/bin/ar
export AS=$DEVROOT/usr/bin/as
export NM=$DEVROOT/usr/bin/nm
export RANLIB=$DEVROOT/usr/bin/ranlib
export LDFLAGS="-L$SDKROOT/usr/lib/"

export CPPFLAGS=$CFLAGS
export CXXFLAGS=$CFLAGS

./configure --target=arm-apple-darwin --enable-static --disable-shared

请将前两条指令的IOS版本正确设置为正确的环境值。

如果您要使用iOS 5 SDK,则需要更改编译器二进制文件的名称,因为它们已经更改。

答案 3 :(得分:1)

re:同步同步:有人可能在说原子或者需要一些gcc库。在icu / source / common / unicode / uconfig.h 的顶部尝试#define U_HAVE_GCC_ATOMICS 0(注意:ARM似乎有一个弱内存模型,所以这个更改将导致更多的锁定/解锁必要但仍然安全。)

答案 4 :(得分:1)

我现在有了解决所有这些丑陋问题的简单方法。

https://github.com/dbquarrel/icu4c-xcframework

下载这个makefile,会得到ICU,并为(M1/ARM/x86)构建ICU.xcframework for(macOS、macCatalyst、iOS、iOS模拟器)。

一枪,所有的头痛都消失了。

很久以后才回答这个问题,但很久以前可能不可能这样做。