代码之家  ›  专栏  ›  技术社区  ›  Community wiki

如何建立重症监护室,以便我可以在iPhone应用程序中使用它?

  •  14
  • Community wiki  · 技术社区  · 2 年前

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

    我正在维护一个使用SQLite数据库的iPhone应用程序。现在我必须在启用ICU支持的情况下进行编译( SQLITE_ENABLE_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文件是为什么体系结构构建的
    • libsqlite3cerod.a是为i386构建的

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

    已编辑以添加

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

    我尝试了@serigio的解决方案,结果成功了。但我仍然会遇到同样的错误,首先是:

    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 。这是正确的流程吗?

    注:

    @塞吉奥在推荐 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_ATOMICS 从…起 1 0 (英寸 platform.h )唉,没什么区别。我也意识到最后一行的错误( not found for architecture arm6 )并不意味着它会起作用 arm7 ,这只是一个提示,这是一个交叉编译。当我指定 扶手7 生成时,它以相同的消息失败。唉。

    编辑#4

    成功

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

    我没有试着在模拟器中重复这一点,但这超出了我的问题范围。

    特别感谢史蒂文·R·卢米斯的投入,感谢塞尔吉奥·莫拉的推动。

    5 回复  |  直到 13 年前
        1
  •  5
  •   Community CDub    8 年前

    编辑:

    我可以确认,如果你这样做,正如史蒂文·R·卢米斯建议的那样:

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

    2. 使distclean

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

    这个问题应该得到解决。事实上,如果不这样做,所构建的库将包含冒犯性的未定义符号:

    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进行交叉编译。

    步骤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来说应该是可以的。

    最后,你应该考虑到,苹果(一半)拒绝了至少一个与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:警告:。。。文件是为不受支持的文件格式生成的,该格式不是所链接的体系结构(i386)

    在我看来,你是在对抗模拟器。。。为此,您将需要“普通”macos x libs。。。

        2
  •  2
  •   Brent    8 年前

    我使用的是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_CXFLAGS和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"
    
        3
  •  2
  •   dbquarrel    4 年前

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

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

    下载这个makefile,它将获得ICU,并为(macOS,macCatalyst,iOS,iOS模拟器)构建一个适用于(M1/ARM/x86)的ICU.xcframework。

    一次注射,所有头痛都消失了。

    过了很长时间才回答这个问题,但很可能这么早以前就不可能这样做了。

        4
  •  1
  •   Sergio Moura    13 年前

    如果你有来源,你真的需要链接库吗?只需将源代码添加到您的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,您需要更改编译器二进制文件的名称,因为它们已经更改。

        5
  •  1
  •   Steven R. Loomis    13 年前

    re:sync-synchronize:可能有人在原子论上撒谎,或者需要一些gcc库。尝试 #define U_HAVE_GCC_ATOMICS 0 在icu/source/common/ucode/uconfig.h的顶部 (注意:ARM的内存模型似乎较弱,因此此更改将导致比其他情况下需要更多的锁定/解锁,但仍然安全。)