编译用于iOS项目的外部C ++库

我对使用C ++库是完全陌生的,所以感谢这可能是我的情况有点特定(让我知道,我可以提供更多的细节)。

我有一个外部的C ++库,我试图用一个iOS项目。 该库遵循一个configuration,使make构build模式输出.a库文件。 当我尝试将这个库文件添加到Xcode,我得到以下错误:

忽略文件/Users/Developer/iOS/TestProj/libpresage.a,文件是为存档build立的,而不是被链接的体系结构(i386):

/Users/Developer/iOS/TestProj/libpresage.a

基于这个问题 ,我已经尝试将Build Active Architecture Only设置为NO,并且我得到了同样的错误。 这使我怀疑我已经编译了不正确的架构的库。

在.a文件上运行lipo -info将给出:

input文件libpresage.a不是胖文件非胖文件:libpresage.a

是架构:x86_64

鉴于这不是armv7s,armv7或arm64,我尝试使用以下参数再次编译C ++库:

1)尝试

./configure CC="gcc -arch armv7s" \ CXX="g++ -arch armv7s" \ CPP="gcc -E" CXXCPP="g++ -E" 

编译错误,我得到:

 ld: library not found for -lcrt1.3.1.o clang: error: linker command failed with exit code 1 (use -v to see invocation) 

2)尝试

 ./configure CC="gcc -arch arm64" \ CXX="g++ -arch arm64" \ CPP="gcc -E" CXXCPP="g++ -E" 

编译错误,我得到:

ld:warning:ld:warning:忽略文件/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib,缺less必需的体系结构arm64文件/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib(2个片段)忽略文件/Applications/Xcode.app/Contents/ /applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer中缺less必需的体系结构arm64 /SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib(2个切片)

ld:dynamic主要可执行文件必须与libSystem.dylib链接以用于架构arm64 clang:error:linker命令失败,退出代码1(使用-v查看调用)

有什么明显的,我失踪?

编辑:

谢谢你的回复,所以我设法把库作为一个自定义的构build目标,把'make'命令指向库MakeFile。 这build立好。

我从这里开始的步骤:

  • 从我的Objective C iOS应用程序目标添加一个依赖项到自定义的构build目标。
  • 引用库并制作一个Objective C ++包装器。
  • 这似乎很好,直到我需要调用外部C ++库,然后编译时出现错误:

架构armv7的未定义符号:PresageBridge.o中的PresageBridge init参考PresageBridge中PresageBridge init的Presage :: Presage()引用:“Presage :: PresageCallback *”。 o ld:找不到符号(s)架构armv7 clang:错误:linker命令失败,退出代码1(使用-v查看调用)

  • 我的目标C ++包装(链接外部C ++库的头文件presage.h):

     #import "PresageBridge.h" #include "presage.h" @implementation PresageBridge - (instancetype)init { if(self = [super init]) { Presage hello(&callback); } return self; } 
  • 基于上面的代码,它似乎不像我错过了标题,有趣的是,我也尝试创build外部库中的其他类的实例,他们似乎工作,这表明Xcode可以出于某种原因,请妥善连接presage.h。

所以我在我的iOS项目中使用了许多第三方C ++库。 人们使用不同的策略。 正如一些人已经提到的,你可以直接在项目中包含代码,使用Xcode构build静态库,或者构build命令行。 在使用GNUconfiguration和构build系统的跨平台C ++库的情况下,我更喜欢命令行。 您只需构build一次,如果需要更新版本或添加新的体系结构片,则只需重新访问它。

你想要的广义的方法是:

  • 找出用于构build每个片的正确configuration参数。 通常情况下,你只需要把重点放在臂之一和i386工作。 其余的很容易你做到这一点。 在某些情况下,您实际上需要修改configuration文件以添加主机或进行其他调整。

  • 一旦你可以build立所有切片,你想运行lipo来build立一个胖二进制。

处理这个问题的最好方法是创build一个构build脚本,它将为您完成所有的工作。 这样,重做就容易了。 更重要的是,您可以重新使用该脚本或将其置换来构build其他外部库。

有很多方法可以构build脚本。 这是一个。 我碰巧有这种types的脚本的几个变种。 这个脚本被用来构buildcURL。 它或多或less地用于很lessmod的预示(即,改变curl来预示)。 注意我没有在Xcode中testing它(即链接并运行它)。 我发现我不得不禁用SQLite,否则它build立了不正确的工具项目。 如果你需要的话,你可以把那部分弄清楚。

有很多方法可以使它更光滑。 例如使用一个数组来存储所有的体系结构。 这只是蛮力。

脚本的要点是:

  1. 获取最新的SDK
  2. build立每个切片
  3. 然后运行lipo

请注意,它应该开箱即用,但是,YMMV。 准备必要时进行debugging。 例如,我还没有确认主机types,但通常这是我一直使用的。 你想把它放在presage的目录下(同一个目录的configuration)。 完成后,所有体系结构都在输出目录中。 通用库位于预处理目录中。

另外请记住,您有责任在通用库中正确链接,并正确定义头文件searchpath。

 #!/bin/bash PLATFORMPATH="/Applications/Xcode.app/Contents/Developer/Platforms" TOOLSPATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin" export IPHONEOS_DEPLOYMENT_TARGET="8.0" pwd=`pwd` findLatestSDKVersion() { sdks=`ls $PLATFORMPATH/$1.platform/Developer/SDKs` arr=() for sdk in $sdks do arr[${#arr[@]}]=$sdk done # Last item will be the current SDK, since it is alpha ordered count=${#arr[@]} if [ $count -gt 0 ]; then sdk=${arr[$count-1]:${#1}} num=`expr ${#sdk}-4` SDKVERSION=${sdk:0:$num} else SDKVERSION="8.0" fi } buildit() { target=$1 hosttarget=$1 platform=$2 if [[ $hosttarget == "x86_64" ]]; then hostarget="i386" elif [[ $hosttarget == "arm64" ]]; then hosttarget="arm" fi export CC="$(xcrun -sdk iphoneos -find clang)" export CPP="$CC -E" export CFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION" export AR=$(xcrun -sdk iphoneos -find ar) export RANLIB=$(xcrun -sdk iphoneos -find ranlib) export CPPFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION" export LDFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk" mkdir -p $pwd/output/$target ./configure --prefix="$pwd/output/$target" --disable-shared --disable-sqlite --host=$hosttarget-apple-darwin make clean make make install } findLatestSDKVersion iPhoneOS buildit armv7 iPhoneOS buildit armv7s iPhoneOS buildit arm64 iPhoneOS buildit i386 iPhoneSimulator buildit x86_64 iPhoneSimulator LIPO=$(xcrun -sdk iphoneos -find lipo) $LIPO -create $pwd/output/armv7/lib/libpresage.a $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a 

考虑到你是新的C ++库,我想你将需要做更多的研究。

不过,我会尝试概述一些您需要考虑的步骤:

  • 您需要确保您为静态库(.a)和项目的相同体系结构进行编译
  • 从你的错误,你需要编译你的静态库为i386或更改您的项目为x86_64(这些架构之间的差异更复杂,但现在让我们说,i386意味着桌面32位,而x86_64意味着桌面64位)
  • arm架构是为iPhone,而不是为您的MacOS(这就是为什么它无法findMacOSX文件夹内的ARM架构库)!

有多种方法可以解决这些问题。

对于第一个我build议包括到您的工作区的静态库,并作为依赖项添加到您的构build目标。 为此,您需要了解XCode构build。

我猜你实际上正在尝试创build一个手机应用程序,所以对于第三个选项,你需要configuration你的g ++构build,以便在连接arm目标(照顾iPhoneOS.platform)时从XCode查看iPhone SDK。

制作arm只能在iPhone上使用。 如果你想在模拟器上工作,你需要将你的静态库链接到iPhoneSimulator.platform中的库。

如果你想让你的静态库同时适用于iPhone和iPhone模拟器,你将需要做一个胖的库(基本上是一个包含两个平台的符号的库)

如果您错过了这些平台,您可以从XCode下载它们(但我相信它们在那里)

正如你所看到的,一路上的事情会变得越来越复杂,所以我强烈build议使用XCode来编译静态库(它仍然适用于g ++)。

我相信以下这些概念对于研究有用:

  • arm,x86,x86_64
  • 静态库
  • 静态链接
  • 胖lib(通用库)
  • 包含多个项目的XCode工作区

希望这可以帮助 :)。

C ++在iOS上运行,您可以将其添加到您的项目中。 或者如果你真的想拥有你的dynamic库,你可以用Xcode进行编译,并指定你的目标架构。

将您的体系结构重置为默认值,然后尝试以下操作 1.在Build Phases-> Link Binary With Libraries中,将libz.dylib和libxml2.dylib库添加到您的项目中。 2.在BuildSettings->searchpath设置始终search用户path为是,并在框架searchpath下添加您的框架的正确path。 使用terminal来获得你的框架的正确path。 3.尝试将“Compiler Source As”设置为C ++,或者使用命中和试用并检查所有选项。 编译器源代码也在BuildSettings下。 使用cmd + f来search它。

试试这些,让我知道,也告诉我你正在尝试在你的项目中使用的框架或SDK。

Mobile Ben的脚本非常棒,除了最后一行代码将一个库文件名硬编码到脚本之外。 以下是对最后一个lipo命令的replace,并dynamic使用lipo合并编译后创build的每个库文件。

改变移动本的线:

 $LIPO -create $pwd/output/armv7/lib/libpresage.a $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a 

至:

 for t in `ls $pwd/output/armv7/lib/*.a` ; do export LIB=`basename $t` export ARCHSTRING="" for a in `ls $pwd/output` do export ARCSTRING="$ARCSTRING $pwd/output/$a/lib/$LIB " done $LIPO -create $ARCSTRING -output $LIB done 

注意:我不想用新的代码function编辑Mobile Ben的答案,并将其添加为注释丢失的格式。