Compiling external C++ library for use with iOS project
我对使用C++库是全新的,所以欣赏这一点可能对我的情况有点具体(让我知道,我可以提供更多的细节)。
我有一个外部C++库,我想用IOS项目来使用它。库遵循配置、生成、生成生成模式以输出.a库文件。当我尝试将此库文件添加到Xcode时,我得到以下错误:
ignoring file
/Users/Developer/iOS/TestProj/libpresage.a, file was
built for archive which is not the architecture being linked (i386):/Users/Developer/iOS/TestProj/libpresage.a
基于这个问题,我尝试将build active architecture改为no,得到了相同的错误。这使我怀疑我为错误的体系结构编译了库。
在.a文件上运行lipo-info可以提供:
input file libpresage.a is not a fat file Non-fat file: libpresage.a
is architecture: x86_64
由于这不是ARMV7S、ARMV7或ARM64,所以我尝试用以下参数重新编译C++库:
1)尝试
1 2 3 | ./configure CC="gcc -arch armv7s" \ CXX="g++ -arch armv7s" \ CPP="gcc -E" CXXCPP="g++ -E" |
编译时出错,我得到:
1 2 | ld: library not found for -lcrt1.3.1.o clang: error: linker command failed with exit code 1 (use -v to see invocation) |
2)尝试
1 2 3 | ./configure CC="gcc -arch arm64" \ CXX="g++ -arch arm64" \ CPP="gcc -E" CXXCPP="g++ -E" |
编译时出错,我得到:
ld: warning: ld: warning: ignoring file
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib,
missing required architecture arm64 in file
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib
(2 slices)ignoring file
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib,
missing required architecture arm64 in file
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib
(2 slices)ld: dynamic main executables must link with libSystem.dylib for
architecture arm64 clang: error: linker command failed with exit code
1 (use -v to see invocation)
有什么明显的东西我不见了吗?
编辑:
感谢您的回复,所以我已经设法将库作为自定义构建目标导入Xcode,并将"make"命令指向库makefile。这个建筑很好。
我的步骤:
- 从我的目标C iOS应用程序目标添加到自定义生成目标的依赖项。
- 引用库并制作一个目标C++封装器。
- 这似乎很好,直到我需要调用外部C++库,然后编译时会出错:
Undefined symbols for architecture armv7:
"Presage::Presage(PresageCallback*)", referenced from:
-[PresageBridge init] in PresageBridge.o
"Presage::~Presage()", referenced from:
-[PresageBridge init] in PresageBridge.o
ld: symbol(s) not found for architecture armv7
clang: error: linker command failed with exit code 1 (use -v to see invocation)
我的目标C++封装器(链接外部C++库头预置。h):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#import"PresageBridge.h"
#include"presage.h"
@implementation PresageBridge
- (instancetype)init
{
if(self = [super init])
{
Presage hello(&callback);
}
return self;
}基于上面的代码,我似乎没有丢失头,有趣的是我还尝试在外部库中创建了其他类的实例,它们似乎在工作,这表明Xcode不能正确地链接presage.h,因为某种原因。
所以我在iOS项目中使用了很多第三方C++库。人们对此有不同的策略。正如一些人已经提到的,您可以直接在项目中包含代码,用xcode构建静态lib,或者构建它的命令行。在使用GNU配置和构建系统的跨平台C++ LIBS的情况下,我更喜欢命令行。您只需要构建一次,如果需要更新版本或添加一个新的体系结构切片,您只需要重新访问它。
您需要的通用方法是:
找出用于构建每个切片的正确配置参数。通常,您只需要专注于获得一个手臂以及i386工作。剩下的很简单,你已经做到了。在某些情况下,您实际上需要修改配置文件以添加主机或进行其他调整。
一旦你可以建立所有切片,你想运行lipo建立一个脂肪二元体。
最好的方法是创建一个构建脚本,它将为您完成所有工作。这样,就更容易重做。更重要的是,您可以重用该脚本或将其置换为构建其他外部libs。
有许多方法可以构建脚本。这里有一个。我碰巧有几种不同类型的脚本。这个脚本是用来构建curl的。它或多或少地适用于预赛与很少的mod(即改变卷曲为预赛)。注意,我没有在Xcode中测试它(即链接它并运行它)。我发现我必须禁用sqlite,否则它会生成不正确的工具项。如果你需要的话,你可以找出那部分。
有很多方法可以让它更光滑。例如,使用数组存储所有体系结构。这只是蛮力。
脚本的关键点是:
但是,请注意,它应该是开箱即用的,YMMV。如有必要,请做好调试准备。例如,我还没有确认主机类型,但通常这是我一直使用的类型。您希望将它放在用于预分页的目录中(与配置的目录相同)。完成后,所有架构都在输出目录中。通用库在预装配目录中。
还请记住,在通用库中正确链接以及正确定义头文件搜索路径是您的责任。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | #!/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_(这些体系结构之间的区别比较复杂,但现在假设i386表示桌面32位,而x86_表示桌面64位)。
- ARM架构是针对iPhone的,而不是针对您的MacOS(这就是为什么它在MacOSX文件夹中找不到具有ARM架构的库的原因)!
解决这些问题有多种方法。
对于第一个,我建议将静态库包含到工作区中,并将其作为依赖项添加到构建目标中。为此,您需要了解Xcode构建。
我猜你真的想做一个电话应用程序,所以对于第三个选项,你需要配置你的G++构建,以便在链接ARM目标(照顾iphoneos.platform)时从xcode查看iphoneskd。
制造一个手臂只能在iPhone上工作。如果您希望它在模拟器上工作,您需要将静态库链接到iphoneSimulator.platform内的库。
如果您希望静态库同时适用于iPhone和iPhone模拟器,则需要创建一个胖库(基本上是一个包含两个平台符号的库)。
如果你缺少这些平台,你可以从xcode下载它们(但我相信它们确实存在)。
正如您所看到的,一路上事情会变得越来越复杂,所以我强烈建议使用Xcode编译静态库(它仍然可以用g++you实现)。
我相信您将有助于研究以下概念:
- ARM,x86,x86_
- 静态库
- 静态连杆机构
- fat lib(通用库)
- 具有多个项目的Xcode工作区
希望这有帮助:)。
以下是Xcode9在iOS设备(iPhoneX)中的作用:1)使用以下设置的标志编译dylib:a)"安装目录":@可执行路径/框架b)"运行路径搜索路径":@可执行路径/框架见下图:xcode 9中的dylib设置
2)在使用/链接dylib的xcode项目中:a)"运行路径搜索路径":@可执行路径/框架b)在"构建阶段->嵌入库"中,确保选择"目标"作为"可执行文件",子路径作为"框架",选中"代码登录副本":设置链接iOS应用程序
此方法经过测试,并与Xcode9.2和iPhoneX一起使用。
戴维
移动本编写的脚本很棒,除了最后一行将库文件名硬编码到脚本中。下面是对最后一个lipo命令的替换,并动态地使用lipo合并编译后创建的每个库文件。
更改手机本的线路:
1 | $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 |
到:
1 2 3 4 5 6 7 8 9 10 | 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 |
注意:我不想用新的代码功能编辑Mobile Ben的答案,并将其添加为注释丢失格式。
将架构设置回默认值,然后尝试以下操作。1。在构建阶段->使用库链接二进制文件,将libz.dylib和libxml2.dylib库添加到项目中。2。在buildsettings->search path中,始终将search user path设置为yes,并在framework search path下添加框架的正确路径。使用终端获取框架的正确路径。三。尝试将你的"编译器源"设置为C++或使用命中和试用,并检查所有选项。编译源也在buildsettings下。使用cmd+f搜索它。
尝试这些方法,让我知道,同时告诉我您在项目中尝试使用的框架或SDK。
C++在iOS上工作,你可以把它添加到你的项目中。或者,如果您真的想拥有动态库,您可以使用Xcode编译它并指定目标体系结构。