web-dev-qa-db-ja.com

iOSプロジェクトで使用するための外部C ++ライブラリのコンパイル

私はC++ライブラリの使用にまったく慣れていないので、これは私のケースに少し固有である可能性があることを認識してください(お知らせください。詳細を提供できます)。

IOSプロジェクトで使用しようとしている外部C++ライブラリがあります。ライブラリは、.aライブラリファイルを出力するために、構成、作成、作成のビルドパターンに従います。このライブラリファイルをXcodeに追加しようとすると、次のエラーが発生します。

ファイル/Users/Developer/iOS/TestProj/libpresage.aを無視して、ファイルはアーカイブ用にビルドされましたが、リンクされているアーキテクチャではありません(i386):

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

この質問 に基づいて、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 slices)無視するファイル/Applications/Xcode.app/Contents/ Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/usr/lib/libstdc ++。dylib、ファイル/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developerに必要なアーキテクチャーarm64がない/SDKs/MacOSX10.10.sdk/usr/lib/libstdc++.dylib(2スライス)

ld:動的メイン実行可能ファイルは、アーキテクチャーarm64のlibSystem.dylibとリンクする必要がありますclang:エラー:リンカーコマンドが終了コード1で失敗しました(-vを使用して呼び出しを確認してください)

私が行方不明であることは明らかですか?

編集:

返信ありがとうございます。ライブラリをカスタムビルドターゲットとしてXcodeに入れて、 'make'コマンドがライブラリMakeFileを指すようにしました。これはうまくいきます。

ここからの私のステップ:

  • Objective C iOSアプリターゲットからカスタムビルドターゲットに依存関係を追加します。
  • ライブラリを参照し、Objective C++ラッパーを作成します。
  • これは、外部C++ライブラリを呼び出す必要があるまでは問題ありません。コンパイルするとエラーが発生します。

アーキテクチャarmv7の未定義のシンボル:「Presage :: Presage(PresageCallback *)」、次から参照:PresageBridge.oの-[PresageBridge init]、「Presage ::〜Presage()」、PresageBridgeの-[PresageBridge init]から参照o 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を適切にリンクしないでください。

19
HHHH

そのため、iOSプロジェクトでサードパーティのC++ライブラリを多数使用しました。これには人々が使用するさまざまな戦略があります。すでに引用したように、プロジェクト内にコードを直接含めたり、Xcodeで静的libをビルドしたり、コマンドラインをビルドしたりできます。 GNU=システムを構成して構築するクロスプラットフォームC++ライブラリの場合は、コマンドラインを使用します。一度構築するだけで、更新する必要がある場合にのみ、再確認する必要があります。バージョンまたは新しいアーキテクチャスライスを追加します。

あなたが望む一般的なアプローチは:

  • 各スライスの構築に使用する正しい構成引数を見つけます。通常、腕の1つとi386の動作に集中する必要があります。残りは簡単にできます。場合によっては、実際に構成ファイルを変更してホストを追加するか、その他の調整を行う必要があります。

  • すべてのスライスを構築できたら、lipoを実行してファットバイナリを構築します。

これに対処する最善の方法は、すべての作業を行うビルドスクリプトを作成することです。これにより、やり直しが簡単になります。さらに重要なのは、スクリプトを再利用するか、スクリプトを並べ替えて、他の外部ライブラリを構築できることです。

スクリプトを作成する方法はたくさんあります。こちらです。この種類のスクリプトには、いくつかのバリエーションがあります。このスクリプトは、cURLの構築に使用されました。それは多かれ少なかれmodがほとんどないpresageで機能しました(つまり、curlをpresageに変更します)。 Xcodeでテストしていないことに注意してください(つまり、リンクして実行しています)。私はsqliteを無効にする必要があることに気づきました。それ以外の場合は、正しくビルドされないツールアイテムをビルドしました。必要な場合は、その部分を理解できます。

あなたがそれをより滑らかにすることができる多くの方法があります。たとえば、すべてのアーキテクチャを格納するために配列を使用します。これは総当たりです。

スクリプトの要点は次のとおりです。

  1. 最新のSDKを入手する
  2. 各スライスを構築する
  3. その後、lipoを実行します

そのまま使用できますが、YMMVです。必要に応じてデバッグする準備をしてください。たとえば、私はホストタイプを確認していませんが、通常はそれを常に使用しています。これをpresageのディレクトリ(configureと同じディレクトリ)に置きます。完了すると、すべてのアーキテクチャが出力ディレクトリに配置されます。ユニバーサルlibはpresageディレクトリにあります。

また、ユニバーサルlibに適切にリンクし、ヘッダーファイルの検索パスを適切に定義するのは、ユーザーの責任であることを忘れないでください。

#!/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
31
Mobile Ben

C++ライブラリの初心者であることを考えると、もう少し調査する必要があると思います。

ただし、考慮する必要があるいくつかの手順の概要を説明します。

  • 静的ライブラリ(.a)とプロジェクトの両方を同じアーキテクチャ用にコンパイルする必要があります。
  • エラーから、i386の静的ライブラリをコンパイルする必要がありますORプロジェクトをx86_64に変更します(これらのアーキテクチャの違いはもう少し複雑ですが、今のところi386はデスクトップ32を意味するとします。ビットx64_64はデスクトップ64ビットを意味します)
  • armアーキテクチャはiPhone用であり、MacOS用ではありません(そのため、MacOSXフォルダ内でarmアーキテクチャのライブラリを見つけることができません)!

これらの問題に取り組む方法はいくつかあります。

最初の1つとして、ワークスペースに静的ライブラリを含め、それを依存関係としてビルドターゲットに追加することをお勧めします。このためには、XCodeビルドを理解する必要があります。

私はあなたが実際に電話アプリケーションを作成しようとしていると思うので、3番目のオプションでは、このために腕のターゲットをリンクするとき(iPhoneOS.platformの後で)、X ++からiPhoneSDKを調べるようにg ++ビルドを構成する必要があります。

Armビルドを作成すると、iPhoneでのみ機能します。シミュレータで動作させる場合は、静的ライブラリをiPhoneSimulator.platform内のライブラリにリンクする必要があります。

静的ライブラリをiPhoneとiPhoneシミュレータの両方で機能させるには、ファットライブラリ(基本的には両方のプラットフォームのシンボルを含むライブラリ)を作成する必要があります。

これらのプラットフォームがない場合は、XCodeからダウンロードできます(ただし、そこにあると思います)

ご覧のとおり、状況は次第に複雑になります。静的ライブラリのコンパイルにはXCodeを使用することを強くお勧めします(g ++でも実行できます)。

私はあなたが調査するのに役立つ次の概念を信じています:

  • arm、x86、x86_64
  • 静的ライブラリ
  • 静的リンク
  • fat lib(ユニバーサルライブラリ)
  • 複数のプロジェクトを含むXCodeワークスペース

お役に立てれば :)。

6
MichaelCMS

Xcode 9 for iOSデバイス(iPhone X)で私のために働いたものは次のとおりです。
1)これらのフラグを次のように設定して、dylibをコンパイルします。
a)「インストールディレクトリ」:@ executable_path/Frameworks b)「実行パス検索パス」:@ executable_path/Frameworks
下の画像を参照してください:
Xcode 9のdylib設定

2)dylibが使用/リンクされているXcodeプロジェクト:
a)「ランパス検索パス」:
@ executable_path/Frameworks
b)[ビルドフェーズ->埋め込みライブラリ]で、[宛先]を[実行可能ファイル]として選択し、[サブパス]を[フレームワーク]として選択し、[コードサインオンコピー]をオンにします。
リンクしているiOSアプリの設定

このメソッドは、Xcode 9.2およびiPhone Xでテストおよび使用されています。

デビッド

2
us_david

アーキテクチャをデフォルトに戻し、以下を試してください。 1.ビルドフェーズ->バイナリとライブラリをリンクで、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についても教えてください。

0
Nauman

C++はiOSで動作します。プロジェクトに追加するだけです。または、動的ライブラリが本当に必要な場合は、Xcodeでコンパイルして、ターゲットアーキテクチャを指定できます。

0
debug

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の回答を新しいコード機能で編集したくありませんでした。これをコメントとして追加すると、書式が失われました。

0
A.Badger