我对使用C ++库完全陌生,所以请注意这可能对我的情况有点具体(让我知道,我可以提供更多细节)。
我有一个外部C ++库,我试图在iOS项目中使用它。该库遵循configure,make,make构建模式以输出.a库文件。当我尝试将此库文件添加到Xcode时,我收到以下错误:
忽略文件 /Users/Developer/iOS/TestProj/libpresage.a,文件是 为存档而构建,而不是被链接的架构(i386):
/Users/Developer/iOS/TestProj/libpresage.a
基于this question,我尝试将Build Active Architecture Only转为NO,我得到了同样的错误。这让我怀疑我为不正确的架构编译了库。
在.a文件上运行lipo -info给出:
输入文件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:警告:ld:警告:忽略文件 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib, 缺少文件中所需的架构arm64 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib (2片)忽略文件 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib, 缺少文件中所需的架构arm64 /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib (2片)
ld:动态主要可执行文件必须与libSystem.dylib链接 架构arm64 clang:错误:链接器命令失败,退出代码 1(使用-v查看调用)
我有什么明显的遗失吗?
修改
感谢您的回复,因此我设法将图书馆作为自定义构建目标放入Xcode,并指出了“#' make'命令库MakeFile。这个构建很好。
我的步骤:
架构armv7的未定义符号: " Presage :: Presage(PresageCallback *)",引自: - PresageBridge.o中的[PresageBridge init] " Presage :: ~Presage()",引自: - PresageBridge.o中的[PresageBridge init] ld:找不到架构armv7的符号 clang:错误:链接器命令失败,退出代码为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;
}
根据上面的代码,我似乎没有错过标题,有趣的是我还尝试创建其他类的实例在外部库中它们似乎正在工作,这表明Xcode可以出于某种原因正确链接presage.h。
答案 0 :(得分:30)
所以我在iOS项目中使用了很多第三方C ++库。人们使用不同的策略。正如一些人已经提到的,您可以直接在项目中包含代码,使用Xcode构建静态库,或者构建命令行。对于使用GNU配置和构建系统的跨平台C ++库,我更喜欢命令行。您只需要构建一次,如果需要更新版本或添加新的体系结构切片,则只需重新访问它。
您想要的通用方法是:
找出用于构建每个切片的正确配置参数。通常情况下,您只需要专注于让其中一个手臂以及i386正常工作。其余的很容易就可以完成。在某些情况下,您实际上需要修改配置文件以添加主机或进行其他一些调整。
一旦你可以构建所有切片,你想运行lipo来构建一个胖二进制文件。
然后处理此问题的最佳方法是创建一个构建脚本,它将为您完成所有工作。这样,重做更容易。更重要的是,您可以重用脚本或置换脚本来构建其他外部库。
您可以通过多种方式构建脚本。这是一个。我碰巧有这种类型的脚本的几种变体。该脚本用于构建cURL。它或多或少地用于预设,具有非常少的mod(即改变卷曲到预期)。注意我没有在Xcode中测试它(即链接它并运行它)。我确实发现我必须禁用sqlite,否则它会构建不正确构建的工具项。如果你需要它,你可以找出那部分。
有很多方法可以让它更光滑。例如,使用数组来存储所有体系结构。这只是蛮力。
脚本的关键点是:
请注意,它应该开箱即用,但YMMV。如有必要,请准备好进行调试。例如,我还没有确认主机类型,但通常这是我一直使用的。你想把它放在预告的目录(配置相同的目录)。完成后,所有体系结构都在输出目录中。通用lib位于presage目录中。
另外请记住,您有责任正确链接通用库,并正确定义头文件搜索路径。
#!/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
答案 1 :(得分:6)
考虑到你是C ++库的新手,我想你需要做更多的研究。
但是,我将尝试概述您需要考虑的一些步骤:
有多种方法可以解决这些问题。
对于第一个我建议将静态库包含到您的工作区中,并将其作为依赖项添加到您的构建目标。为此,您需要了解XCode构建。
我猜你实际上是在尝试创建一个手机应用程序,所以对于第三个选项,你需要配置你的g ++构建,以便在链接arm目标(看看iPhoneOS.platform)时从XCode查看iPhoneSDK
进行手臂构建仅适用于iPhone。如果您希望它在模拟器上运行,则需要将静态库链接到iPhoneSimulator.platform中的库。
如果你想让你的静态库适用于iPhone和iPhone模拟器,你需要制作一个胖lib(基本上是一个包含两个平台符号的库)
如果您缺少这些平台,可以从XCode下载它们(但我相信它们在那里)
正如您所看到的,在此过程中事情将变得越来越复杂,所以我强烈建议使用XCode来编译静态库(它仍然可以用g ++进行编译)。
我相信您可以使用以下概念进行研究:
希望这会有所帮助:)。
答案 2 :(得分:2)
以下是Xcode 9 for iOS设备(iPhone X)的用途:
1)使用以下设置的标志编译dylib:
a)"安装目录":
@ executable_path /框架
b)"运行路径搜索路径":
@ executable_path /框架
见下图:
dylib settings in Xcode 9
2)在使用/链接dylib的Xcode项目中:
a)" Runpath搜索路径":
@ executable_path /框架
b)在"构建阶段 - >嵌入库"确保选择"目的地" as"可执行文件"和子路径为"框架","代码签名复制"检查:
Setting the the linking iOS app
此方法已经过测试,可与Xcode 9.2和iPhone X一起使用。
大卫
答案 3 :(得分:0)
C ++适用于iOS,您只需将其添加到项目中即可。或者,如果您真的想拥有动态库,可以使用Xcode编译它并指定目标体系结构。
答案 4 :(得分:0)
将您的架构恢复为默认值,然后尝试以下操作。 1.在Build Phases-> Link Binary With Libraries中将libz.dylib和libxml2.dylib库添加到您的项目中。 2.在BuildSettings-> Search Paths中将Always Search User Paths设置为Yes,并在Framework Search Paths下添加框架的正确路径。使用终端获取框架的正确路径。 3.尝试将"编译器源设置为"到C ++或使用点击和试用,并检查所有选项。 Complier Source As也在BuildSettings下。使用cmd + f进行搜索。
尝试这些并让我知道,也告诉我您正在尝试在项目中使用的框架或sdk。
答案 5 :(得分:0)
Mobile Ben的脚本很棒,除了最后一行硬编码脚本中的库文件名。以下是最后一个lipo命令的替换,并动态使用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
为:
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的答案,并将其添加为评论丢失格式。