编译用于iOS项目的外部C ++库 [英] Compiling external C++ library for use with iOS project

查看:1578
本文介绍了编译用于iOS项目的外部C ++库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是全新使用C ++库,所以感谢这可能是一个具体的我的情况(让我知道,我可以提供更多的细节)。



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


忽略文件
/ iOS / TestProj / libpresage.a,文件是
,用于归档,而不是被链接的架构(i386):



/ Users / Developer / TestProj / libpresage.a


基于这个问题,我试着将Build Active Architecture Only改成NO,错误。这使我怀疑我编译的库的不正确的架构。



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


输入文件libpresage.a不是一个胖文件非fat文件:libpresage.a



是架构:x86_64


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



1)尝试

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

编译时出错,得到:

  ld:没有为-lcrt1.3.1.o找到库
clang:error:linker命令失败,退出代码1(使用-v查看调用)

2)尝试

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

编译错误,我得到:


ld:warning:ld:warning:忽略文件
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libSystem.dylib,
在文件$ b中缺少必需的架构arm64 $ b /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 slices)



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


有没有明显的缺失?





感谢回复,所以我设法将库作为自定义构建目标的Xcode,指向'make'命令MakeFile。



我的步骤:




  • 添加依赖项我的目标C iOS应用程序定位到自定义生成目标。

  • 引用库并创建一个Objective C ++包装器。

  • 这似乎很好,直到我需要调用外部C ++库,然后我在编译时遇到错误:




架构的未定义符号armv7:
Presage :: Presage(PresageCallback *),引用自:
- PresageBridge.o中的[PresageBridge init] b $ bPresage ::〜Presage(),引用自:
- PresageBridge.o中的[PresageBridge init]
ld:未找到用于体系结构的符号armv7
clang:错误:链接器命令失败,退出代码1(使用-v查看调用)





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

      #importPresageBridge.h
    #includepresage.h

    @implementation PresageBridge

    - (instancetype)init
    {
    if(self = [super init])
    {

    Presage hello(& callback);
    }

    return self;
    }


  • 根据上面的代码, m缺少标题,有趣的是,我也试图在外部库中创建其他类的实例,他们似乎是工作,这表明Xcode不能链接presage.h正确的某些原因。



解决方案

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



你想要的一般化方法是:



- 找出正确的配置参数, 。通常,你只需要专注于获得一个手臂和i386工作。其余的很容易,你有这样做。在某些情况下,您实际上需要修改配置文件以添加主机或进行其他调整。



- 您可以构建所有切片,您要运行lipo构建一个胖二进制。



最好的办法是创建一个构建脚本,这将为你做所有的工作。这样,更容易重做。更重要的是,你可以重用这个脚本或者改变它来构建其他外部库。



有很多方法可以构建脚本。这里是一个。我碰巧有这种类型的脚本的几个变体。这个脚本用于构建cURL。它或多或少地工作与非常少的模式(即改变卷曲到预设)。注意我没有在Xcode中测试它(即链接它和运行它)。我确实发现,我不得不禁用sqlite,否则它建立不正确的工具项。如果你需要它,你可以想出这个部分。



有很多方法可以使它更加光滑。例如,使用数组来存储所有体系结构。



脚本的关键点是:



- 获取最新的SDK
- 建立每个切片
-运行lipo



请注意,它应该可以开箱即用,但是,YMMV。准备好在必要时调试它。例如,我没有确认主机类型,但一般这是我一直使用的。你想把它放在presage的目录下(在configure的同一个目录下)。完成后,所有架构都在输出目录中。通用库位于预置目录中。



还要记住,您有责任正确链接通用库,并正确定义头文件搜索路径。 / p>

 #!/ 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 / Developers / SDKs`
arr =()
for sdk $ sdks
do
arr [$ {#arr [@]}] = $ sdk
done

#最后一个项目将是当前的SDK,因为它是alpha ordered
count = $ {#arr [@]}
if [$ count -gt 0];那么
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]];然后
hostarget =i386
elif [[$ hosttarget ==arm64]];然后
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 /输出/ arm64 / lib / libpresage.a $ pwd / output / x86_64 / lib / libpresage.a $ pwd / output / i386 / lib / libpresage.a -output libpresage.a
/ pre>

I'm completely new to using C++ libraries, so appreciate this might be a bit specific for my case (let me know and I can provide more details).

I have an external C++ library that I'm trying to use with an iOS project. The library follows a configure, make, make build pattern to output a .a library file. When I try and add this library file to Xcode, I get the following error:

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

Based on this question, I've tried turning Build Active Architecture Only to NO, and I get the same error. This makes me suspect that I've compiled the library for the incorrect architecture.

Running lipo -info on the .a file gives:

input file libpresage.a is not a fat file Non-fat file: libpresage.a

is architecture: x86_64

Given that this isn't armv7s, armv7, or arm64, I try and compile the C++ library again with the following parameters:

1) Try

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

Error in compiling, I get:

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

2) Try

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

Error in compiling, I get:

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)

Is there something obvious that I'm missing?

EDIT:

Thanks for the replies, so I've managed to get the library into Xcode as a custom build target, pointing the 'make' command to the libraries MakeFile. This build fine.

My steps from here:

  • Add a dependency from my Objective C iOS app target to the custom build target.
  • Reference the library and make an Objective C++ wrapper.
  • This seems fine until I need to call the external C++ library, then I get the error when compiling:

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)

  • My objective C++ wrapper (linking the external C++ library header presage.h):

    #import "PresageBridge.h"
    #include "presage.h"
    
    @implementation PresageBridge
    
    - (instancetype)init
    {
        if(self = [super init])
        {
    
           Presage hello(&callback);
        }
    
        return self;
    }
    

  • Based on the code above it doesn't seem like I'm missing the header, and what's interesting is that I've also tried creating an instance of other classes in the external library and they seem to be working, which suggests that Xcode can't link presage.h properly for some reason.

解决方案

So I've used many a 3rd party C++ library in my iOS projects. There are different strategies people use for this. As some have already cited, you can include the code within the project directly, build the static lib with Xcode, or build it command line. In the case of cross platform C++ libs which use the GNU configure and build system, I prefer command line. You only need to build it once and you only have to revisit it if you need to update the version or add a new architecture slice.

The generalized approach you want is:

-Figure out the right configure arguments to use to build each slice. Typically, you only need to focus on getting one of the arm as well as i386 working. The rest are easy one you have this done. In some cases, you actually need to modify the configure file to add the host or make some other adjustments.

-Once you can build all slices, you want to run lipo to build a fat binary.

The best way then to deal with this is create a build script which will do all the work for you. This way, it's easier to redo. More importantly, you can reuse the script or permute it to build other external libs.

There are many ways you can build the script. Here is one. I happen to have several variations of this type of script. This script was used to build cURL. It more or less worked for presage with very little mod (ie. change curl to presage). Note I didn't test it in Xcode (ie. linking it and running it). I did find that I had to disable sqlite, else it built tool items which don't build right. If you need it, you can figure that part out.

There are many ways you could make it more slick. For example using an array to store all the architectures. This is just brute force.

The key points of the script are:

-Getting the latest SDK -Building each slice -Then running lipo

Note that it should work out of the box, however, YMMV. Be prepared to have to debug it if necessary. For example, I haven't confirmed the host type, but generally that is what I've always used. You want to put this at the directory for presage (same directory where configure). When it is done, all architectures are in the output directory. The universal lib is in the presage directory.

Also remember it is your responsibility to properly link in the universal lib as well as have the header files search path defined properly.

#!/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

这篇关于编译用于iOS项目的外部C ++库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆