iOSおよびOSX用のSharkを構築する

画像

はい、そのような見出しはあまり意味がありませんので、「カットに行くかどうか」とまだ考えている人のためにいくつかの説明をします。



Shark-機械学習(機械学習)のC ++ライブラリのセット、つまり線形および非線形最適化、ニューラルネットワーク、教師あり、なしの学習、進化的アルゴリズムなど。 より詳細な説明は、プロジェクトのウェブサイトで見つけることができます。



次の質問への回答に興味がある場合





それからあなたは猫の下にいます。





なんで?



「iOSにとって便利で便利なライブラリを増やすために」と簡単に答えることができましたが、別の理由がありました。 iOS向けのボードゲームの開発中に、機械学習を使用して、対戦相手の人工知能(AI)を開発したかったのです。



計画は単純で、最初に数万のゲームを通じてニューラルネットワークを駆動してAIをトレーニングし、Mac OSで強力なハードウェアで実行してから、トレーニングされたネットワークを利用してiPhone / iPadのアプリケーションで使用します。 brew install shark



を使用してSharkバージョン2.3.4をポピーにインストールできる場合のみ、計画の最初の部分は比較的簡単に実装できました。



ここで、記事がライブラリ2.3.4のバージョンに関するものであることに注意してください。 プロジェクト自体はすでに2.3.4から大きく外れており、現在ベータバージョン3.0が利用可能です 。 新しいバージョンのコードは大幅に再設計され、サードパーティライブラリとしてboostを使用しているため 、特にiOSのコンテキストでは、これはまったく異なる話です。




計画の2番目の部分に戻りましょう。 トレーニング後、私はまだニューラルネットワーク係数のファイルを手にしています。 このファイルの形式はどこにも記述されていません(または検索が不十分です)ので、読み取りと使用の最も安価な方法は同じSharkを使用することです。つまり、ライブラリをiOSに移植する必要があります。



どうやって?



簡単な答えは、ソースを取得してコンパイルすることです。詳細な答えは、Habréの記事です。



明確なビジネス、Habrで書く前に、私は最初にライブラリを組み立て、 GitHubのリポジトリの形でこのすべてを設計しました。 そのため、わかりやすくするために、ビルドスクリプトのコードを使用して投稿にシーズニングを行います。



プロセス全体を次のステップに分けることができます





はい、つまり、iOSデバイスおよびシミュレーター(およびOSXの個別)の開発用に「太い」(「太い」または「太い」)静的ライブラリーを収集するだけでなく、すべてをフレームワークとして整理し、 CocoaPodsからアクセスできるようにします。



それでは、一歩一歩始めましょう。



ソースコードをダウンロードする


ここではすべてが簡単です。あまり詳細に説明することはありませんので、噛みすぎたり、アーカイブをダウンロードして解凍したりしないようにします。

ダウンロードして解凍する
 VERSION=2.3.4 SHARK_ZIP=shark-$VERSION.zip # --- download() { if [ ! -s $SHARK_ZIP ]; then echo Downloading shark source code $SHARK_ZIP... curl -L --progress-bar -o $SHARK_ZIP "http://sourceforge.net/projects/shark-project/files/Shark%20Core/Shark%20${VERSION}/shark-${VERSION}.zip/download" else echo Source code $SHARK_ZIP already downloaded... fi doneSection } SRC_DIR=src # --- unpackSource() { echo Unpacking $SHARK_ZIP to $SRC_DIR... [ -d $SRC_DIR ] || unzip -q $SHARK_ZIP -d $SRC_DIR [ -d $SRC_DIR ] && echo " ...unpacked as $SRC_DIR" doneSection }
      
      









ソースコードにパッチを当てる


当初、コードはgcc 4.2を使用して開発されましたが、clangバージョン5.0を使用してコンパイルしようとしています。 gcc 4.2のリリース以来、コンパイラとC ++標準は大きく進歩したため、clangが一部のコードを好まないことは驚くことではありません。 修正する以外に何も残っていない、すなわち パッチ、問題のあるコード。



デフォルトのコンストラクター


初めて、コンパイラはReClaM/EarlyStopping.cpp



78行目でつまずきReClaM/EarlyStopping.cpp





 EarlyStopping::EarlyStopping(unsigned sl = 5)
      
      





EarlyStopping



コンストラクターには単一の引数( unsigned sl



)があり、この引数にはデフォルト値( 5



)が指定されています。 したがって、このコンストラクターはデフォルトのコンストラクターになります。「まあ、それを聞かせて」-gcc 4.2は言いますが、clangはこれについて完全に異なる意見を持っています。 StackOverflow このエラーの説明を見つけることができます。



「額」を修正します。つまり、 デフォルト値を削除するだけです。

 EarlyStopping::EarlyStopping(unsigned sl)
      
      





ちょっと待って! -あなたが言う-このコンストラクタが引数なしでライブラリコードのどこかで使用されている場合はどうなりますか?

絶対に公正な質問。 幸いなことに、このコンストラクターはコードの他のどこでも(明示的または暗黙的に)呼び出されません。つまり、このような変更による害はありませんが、コードで呼び出すときは注意してsl



値を渡す必要があります



finiteはiOSでは使用できません


次のエラーは、デバイスとシミュレーターの両方で、iOSでfinite(x)



関数が使用できない(含まれない)ことです。 この問題への参照は、たとえばこちらの Webで見つけることができます。



解決策は、 isfinite(x)



関数を使用することです。 プリプロセッサマクロを使用して、 finite(x)



isfinite(x)



finite(x)



として再定義しますこれを行うには、 SharkDefs.h



次のコードを追加します

SharkDefs.h
 #if defined(__APPLE__) && defined(__MACH__) /* Apple OSX and iOS (Darwin). */ #include <TargetConditionals.h> #if TARGET_IPHONE_SIMULATOR == 1 /* iOS in Xcode simulator */ #define finite(x) isfinite(x) #elif TARGET_OS_IPHONE == 1 /* iOS on iPhone, iPad, etc. */ #define finite(x) isfinite(x) // #define drem(x, y) remainder(x, y) #elif TARGET_OS_MAC == 1 /* OSX */ #endif #endif
      
      









ここでのロジックは、Apple OSの1つ、つまり __APPLE__



および__MACH__



場合、 TargetConditionals.h



ヘッダーファイルを含めてから、 TARGET_IPHONE_SIMULATOR



TARGET_OS_IPHONE



およびTARGET_OS_MAC



値を確認し、iOSデバイスおよびシミュレーターのfinite(x)



を再定義します。



drem(x, y)



関数とまったく同じ問題で、 drem(x, y)



に置き換える必要があります。 ただし、Shark drem(x, y)



は使用しないため、これは単なる情報のメモです。



FileUtilの修正


次のエラーは、 FileUtil



モジュール、つまりFileUtil.h



ファイルに関連しています。



最初は、clangはiotype



SetDefault



ScanFrom



およびPrintTo



を見つけることができません。 名前空間(名前空間)を使用して、コンパイラにヒントを与えましょう。 必要に応じて簡単な交換を行います

 iotype -> FileUtil::iotype SetDefault -> FileUtil::SetDefault ScanFrom -> FileUtil::ScanFrom PrintTo -> FileUtil::PrintTo
      
      







このファイルの最後の問題はio_strict



関数です。この関数は、 io_strict



宣言されるscanFrom_strict



およびprintTo_strict



関数を呼び出します。

解決策? io_strict



をファイルの最後に移動するだけで問題ありません。



double erf(double) throw() ;


Mixture/MixtureOfGaussians.cpp



コンパイルMixture/MixtureOfGaussians.cpp



、次のコードMixture/MixtureOfGaussians.cpp



としてマークされます。

 extern "C" double erf(double) throw();
      
      







extern "C"



宣言は元のプロトタイプと一致しません。

この場合、問題はthrow()



削除することで解決されます。

 extern "C" double erf(double);
      
      







一部の修正については、 throw()



を削除するなど、詳細な説明を提供していないことを認識しています。 コメント欄にコメントをいただければうれしいです。




RandomVector this-> p


次の行は、 Mixture/RandomVector.h



72行Mixture/RandomVector.h



。コンパイラーは、 p



どのようにMixture/RandomVector.h



かわかりません。 また、この行のコードコメント( // !!!



)も警告されます。

 for (unsigned k = x.dim(0); k--;) { l += log(Shark::max(p(x[ k ]), 1e-100)); // !!! }
      
      





コードを分析した結果、これは非常にp



でした。 RandomVector



は、「失われた」メソッドp



を宣言したRandomVar



継承します。

pを探しています
 // RandomVar.h template < class T > class RandomVar { public: // *** virtual double p(const T&) const = 0; // *** } // RandomVector.h template < class T > class RandomVector : public RandomVar< Array< T > > { public: // *** }
      
      









this->p



の構築はthis->p



ます。

 for (unsigned k = x.dim(0); k--;) { l += log(Shark::max(this->p(x[ k ]), 1e-100)); // !!! }
      
      







CMakeLists.txt


最新のパッチは、コンパイルエラーとは関係ありません。

iOS用のライブラリを取得するため、このライブラリは静的である必要がありますが、プロジェクトはデフォルトで動的ライブラリを構築します。 目的の結果を得るには、 CMakeLists.txt



ファイルの1行を置き換えます。

 ADD_LIBRARY( shark SHARED ${SRCS} ) #   ADD_LIBRARY( shark STATIC ${SRCS} )
      
      





原則として、この行を「SHARED」で置き換えることはできませんが、単に「STATIC」で別の行を追加すると、動的ライブラリと静的ライブラリの両方がコンパイルされます。



パッチを適用する


もちろん、このプロセスを繰り返すことにした場合、コードを手動で選択することは意味がありません。 時間と神経を節約するために、既製のパッチがあります。

興味のある方は、このパッチはdiff



ユーティリティを使用して入手した

 diff -crB shark_orig shark_patched > shark.patch
      
      





このパッチを適用するには、ユーティリティ、アテンション、 patch



を使用する必要があります

 SRC_DIR=src # --- patchSource() { echo Patching source code... patch -d $SRC_DIR/Shark -p1 --forward -r - -i ../../shark.patch doneSection }
      
      







構成および構築


最後に、パッチは終了しました。アセンブリに直接進むことができます。

make



を使用してプロジェクトをビルドします。プラットフォームごとにすべてを正しく構成するためにのみ残りますcmake



(configure make)ユーティリティは、 Makefile



およびmake



必要な他のファイルを作成するのに役立ちます。 次のプラットフォームとアーキテクチャのために、ライブラリを3回構成および構築する必要があります。





はい、重要な点は、Xcode 5を使用することですarmv6



アーキテクチャのサポートはXcode 5から公式に削除されたため、まったく考慮しません。




iOSデバイスとシミュレーターのライブラリを1つの「厚い」ライブラリーにマージします。これらのライブラリーは、不要なジェスチャーなしでデバイスとシミュレーターの開発に同時に使用できます。



Cmakeの基本


だからcmake



。 プラットフォームごとに、次の設定を使用して環境を適切に構成する必要があります





Xcode Toolkit


ツールチェーンという用語の最も成功した翻訳ではないかもしれませんが、「ツールチェーン」よりも確かに優れています。 Xcodeには、必要なすべてのツール(コンパイラ、iPhone OS SDKおよびiPhone Simulator SDKのライブラリなど)が含まれています。もちろん、Xcodeをインストールする必要があります。同じツール(Xcodeコマンドラインツール)もインストールする必要があります。 Xcode設定またはxcode-select --install



を使用しxcode-select --install







次に、 xcode-select



を使用して、必要なすべてのツールとディレクトリを見つけます。

Xcodeツール
 #     XCODE_ROOT=$(xcode-select -print-path) #   iPhone OS SDK XCODE_ARM_ROOT=$XCODE_ROOT/Platforms/iPhoneOS.platform/Developer #   iPhone Simulator SDK XCODE_SIM_ROOT=$XCODE_ROOT/Platforms/iPhoneSimulator.platform/Developer #    ,  ... XCODE_TOOLCHAIN_BIN=$XCODE_ROOT/Toolchains/XcodeDefault.xctoolchain/usr/bin # C++  CXX_COMPILER=${XCODE_TOOLCHAIN_BIN}/clang++ # C  C_COMPILER=${XCODE_TOOLCHAIN_BIN}/clang
      
      









Mac OS X SDKの場合、 cmake



はそれ以上の指示なしにルートシステムディレクトリを見つけるのに十分なほどスマートです。



プラットフォームごとに順番に次に。



iOSデバイス(iPhone OS SDK)

build/ios



別のフォルダーに収集します。



コンパイラはすでに見つかりましたが、C ++コンパイラのフラグを定義します。 armv7



armv7s



、およびarm64



アーキテクチャ用にビルドするため、 clang++



は特別な-arch



フラグを使用しclang++







ARMアーキテクチャに必要なすべてのシステムライブラリは、 SDKs/iPhoneOS7.0.sdk



サブディレクトリXCODE_ARM_ROOT





 CXX_FLAGS="-arch armv7 -arch armv7s -arch arm64" SYSTEM_ROOT=${XCODE_ARM_ROOT}/SDKs/iPhoneOS7.0.sdk
      
      







cmake



呼び出しは次のようになります

 mkdir -p build/ios cd build/ios cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_OSX_SYSROOT="$SYSTEM_ROOT" \ -DCMAKE_C_COMPILER=$C_COMPILER \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -G "Unix Makefiles" \ ../../src/Shark
      
      







ところで、 cmake



は私たちのために多くの特別な仕事をします。 CおよびC ++コンパイラのみを指定するだけで十分ですcmake



は、同じツールキットから他のすべてのユーティリティ、たとえばranlib



lipo



ld



などを検索します。




iOSシミュレーター(iPhone Simulator SDK)

同じコンパイラ。



今回必要なアーキテクチャはi386



x86_64



です。後者は、たとえば「iPhone Retina(4インチ64ビット)」など、64ビットアーキテクチャのデバイスのシミュレータでテストするために必要です。



必要なライブラリは${XCODE_SIM_ROOT}/SDKs/iPhoneSimulator7.0.sdk



ます。



また、コードが同じアーキテクチャのOS Xではなくシミュレータ専用に構築されたというもう1つの非常に重要な点は、コンパイラーが-mios-simulator-version-min=7.0



フラグを使用して追加のヒントを与える必要があることです



 mkdir -p build/sim cd build/sim CXX_FLAGS="-arch i386 -arch x86_64 -mios-simulator-version-min=7.0" SYSTEM_ROOT=${XCODE_SIM_ROOT}/SDKs/iPhoneSimulator7.0.sdk cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_OSX_SYSROOT="$SYSTEM_ROOT" \ -DCMAKE_C_COMPILER=$C_COMPILER \ -DCMAKE_CXX_FLAGS="$CXX_FLAGS" \ -G "Unix Makefiles" \ ../../src/Shark
      
      







Mac OS X

そして最後に、Mac OSX。

今回は、CおよびC ++コンパイラーのみを指定するだけで十分であり、 cmake



は残りを見つけます。

 mkdir -p build/osx cd build/osx cmake \ -DCMAKE_CXX_COMPILER=$CXX_COMPILER \ -DCMAKE_C_COMPILER=$C_COMPILER \ -G "Unix Makefiles" \ ../../src/Shark
      
      







Cmakeのトリック


さあ、 make



ましょmake





cmake



は、考慮すべきcmake



がいくつかあります。



コンパイラーテスト

まず、最初の起動時に、 cmake



はCおよびC ++コンパイラーのテストを実行します。 奇妙なことに、clangとclang ++はiOSプラットフォームでこのテストに失敗しました。 このテストを回避する方法については、インターネット上でいくつかの推奨事項があります。たとえば、 CMakeLists.txt



ファイルでプロジェクトの説明にNONE



を追加しますが、これは役に立ちませんでした。

 PROJECT( shark NONE )
      
      







私のために働いた方法は、clangとclang ++コンパイラと他のオプションを指定せずに最初にcmake



を開始することです。 cmake



CMakeCache.txt



ファイルとCMakeFiles



ディレクトリcmake



生成します。 さまざまな設定でcmake



を起動すると、今回はコンパイラテストが実行されません。



構成変更

合計で、 cmake



を少なくとも2回開始する必要があります-もう一度考えます。

そして再び、いいえ。



CやC ++コンパイラなどの重要なパラメータが次の起動時に変更された場合、変更はすぐには有効になりません。 cmake



は警告を発し、再度実行するようアドバイスします。 実際、 cmake



はこのようなことを言っていませんが、 ccmake



ユーティリティccmake



より多くの情報ccmake



提供します。 ccmake



cmake



コンソールGUIです。



一般的に





作る


はい、大事なmake



実行できます。 処理を高速化するために、 -j



フラグを使用してアセンブリを並列化できます。

 make -j16
      
      





このプロセスには時間がかかりません。その結果、 libshark.a



静的ライブラリをlibshark.a



ます。 file



ユーティリティを使用するすべての消防士について、結果のライブラリが必要なすべてのアーキテクチャをサポートしていることを確認します。

脂肪チェック
 $ file build/ios/libshark.a build/ios/libshark.a: Mach-O universal binary with 3 architectures build/ios/libshark.a (for architecture armv7): current ar archive random library build/ios/libshark.a (for architecture armv7s): current ar archive random library build/ios/libshark.a (for architecture cputype (16777228) cpusubtype (0)): current ar archive random library $ file build/sim/libshark.a build/sim/libshark.a: Mach-O universal binary with 2 architectures build/sim/libshark.a (for architecture i386): current ar archive random library build/sim/libshark.a (for architecture x86_64): current ar archive random library $ file build/osx/libshark.a build/osx/libshark.a: current ar archive random library
      
      









「厚い」ライブラリを作成する


iOSデバイス用のライブラリとシミュレータは、1つの「厚い」ライブラリに結合する必要があります。



ここではすべてが非常に簡単ですlipo



ユーティリティはこのタスクに対処しますlipo





 mkdir -p lib/ios $XCODE_TOOLCHAIN_BIN/lipo -create build/ios/libshark.a build/sim/libshark.a -o lib/ios/libshark.a
      
      





念のため、結果のライブラリ( file lib/ios/libshark.a



)をチェックして、5つのアーキテクチャがすべてfile lib/ios/libshark.a



れていることを確認してください。



フレームワークにパックする


ライブラリをフレームワークの形で注意深くパックするときが来ました。 フレームワークディレクトリは、多くの場合バンドルと呼ばれます。



バンドルを作成する


この段階で、 mkdir



ln



を使用して、必要なすべてのシンボリックリンクを使用して、 Shark.framework



ディレクトリと必要なフォルダー構造を内部に作成します。

 Shark.framework/ ├── Documentation -> Versions/Current/Documentation ├── Headers -> Versions/Current/Headers ├── Resources -> Versions/Current/Resources └── Versions ├── A │ ├── Documentation │ ├── Headers │ └── Resources └── Current -> A
      
      







ライブラリをコピー


静的ライブラリをバンドル内にコピーし、その名前をShark



変更します。

 cp build/ios/libshark.a Shark.framework/Versions/A/Shark
      
      







ヘッダーファイルをコピーする


次に、すべての.h



ファイルをsrc/Shark/include



からバンドル内のHeaders



フォルダーにコピーします。 次に、不要なstatistics.h



削除しstatistics.h



CMakeLists.txt



ファイルに対応するINSTALL



コマンドがないためだけに、このファイルは必要ありません。

 cp -r src/Shark/include/* Shark.framework/Headers/ rm Shark.framework/Headers/statistics.h
      
      







パッチヘッダーファイル

ヘッダーがすべてをコピーしたように見えますが、やはりすべてがそれほど明白ではありません。 今フレームワークを使用しようとすると、ヘッダーファイルへのパスに関連するいくつかの不明瞭なエラーがポップアップします。 OS Xの動的ライブラリの場合、ヘッダー検索パスを使用して問題を回避できたとしたら、フレームワークの場合、すべてがそれほど単純ではありません。



Shark開発者は#include



ディレクティブの正しいパスを処理しなかったため、それらの作業を行う必要があります。



適切なアプローチを探して、よく整理されたライブラリの例、すなわちブーストに注意を向けました。 たとえば、 boost/



からboost/



で始まるコンポーネントの#include



ディレクティブのすべてのパス
 #include "boost/config.hpp" #include <boost/type_traits/remove_reference.hpp>
      
      







すべての#include



ディレクティブに対して次のルールを使用して、 sed



エディターとパッチファイルを使用します





ここでのコンポーネントとは、 Headers



フォルダーのサブディレクトリ、つまり Array, Rng, LinAlg, FileUtil, EALib, MOO-EALib, ReClaM, Mixture, TimeSeries, Fuzzy







パッチ.hファイル
 #     "invalid character sequence" export LC_TYPE=C export LANG=C #     #include  #    SharkDefs.h #      #  -E     ,       "gnu vs non-gnu sed" components="Array|Rng|LinAlg|FileUtil|EALib|MOO-EALib|ReClaM|Mixture|TimeSeries|Fuzzy" find Shark.framework/Headers -type f -exec \ sed -E -i '' \ -e "s,#include([<\"]),#include \1,g" \ -e "s,#include([ \t])([<\"])(SharkDefs.h),#include\1\2Shark/\3,g" \ -e "s,#include([ \t])([<\"])(${components}/),#include\1\2Shark/\3,g" \ {} +
      
      









Info.plistを作成する


フレームワークを作成する最後の手順は、対応するInfo.plistを作成することです。 重要なプロパティは、フレームワークの名前とバージョンです。

Info.plistを作成する
 FRAMEWORK_NAME=Shark FRAMEWORK_CURRENT_VERSION=2.3.4 cat > Shark.framework/Resources/Info.plist <<EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>dk.diku.image</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> EOF
      
      









iOS 7、つまりarm64



アーキテクチャを備えたデバイスのリリース前は、シミュレータを含むiOSとOSXの両方のユニバーサル静的ライブラリ、したがってフレームワークを作成できました。 armv6, armv7, armv7s, i386



、およびx86_64



を1つの太字ライブラリにパックすることを妨げるものは何もありませんでした。 64ビットアーキテクチャのデバイスは、すべてのカードを混乱させました。 「厚い」ライブラリでは、同じアーキテクチャの2つのレイヤーは存在できません。つまり、64ビットデバイスのiOSシミュレーターの場合はx86_64



、OS Xの場合はx86_64



x86_64



できません。




CocoaPodsへの投稿


すぐに、既製のフレームワークを使用してプロジェクトに自由に追加できますが、この段階も自動化する必要があります。 これがまさにCocoaPodsの目的です。 何らかの理由で電車の後ろにいて、CocoaPodsをまだ使用していない場合は、このプロジェクトに注意を払うときです。



囲炉裏の仕様を作成することもまた別の話です。 ここまで、実際にすべての小さなものをペイントしたという事実にもかかわらず、ここでは完成した結果を参照します。

Shark-SDK.podspec
 Pod::Spec.new do |s| s.name = 'Shark-SDK' s.version = '2.3.4' s.license = { :type => 'GPLv2', :text => 'See https://sourceforge.net/directory/license:gpl/' } s.summary = 'iOS & OS X framework for Shark: C++ Machine Learning Library' s.description = <<-DESC SHARK provides libraries for the design of adaptive systems, including methods for linear and nonlinear optimization (eg, evolutionary and gradient-based algorithms), kernel-based algorithms and neural networks, and other machine learning techniques. DESC s.homepage = 'https://sourceforge.net/projects/shark-project/' s.author = { 'shark-admin' => 'https://sourceforge.net/u/shark-admin/profile/' } s.source = { :http => 'https://github.com/mgrebenets/shark2-iosx/releases/download/v2.3.4/Shark-SDK.tgz', :type => :tgz } s.ios.vendored_frameworks = "Shark-iOS-SDK/Shark.framework" s.osx.vendored_frameworks = "Shark-OSX-SDK/Shark.framework" s.ios.deployment_target = '6.0' s.osx.deployment_target = '10.7' end
      
      









そして使用例。

ポッドファイル
 # Podfile platform :ios, :deployment_target => '6.0' pod 'Shark-SDK' target :'shark2-osx-demo', :exclusive => true do platform :osx, :deployment_target => '10.7' pod 'Shark-SDK' end
      
      









まとめ



そのため、突然自分の問題を思いついた場合、その結果は、控えめに言っても保証されませんが、それでも何かを試してください。その結果、どのような新しいスキルが活用できるのか決してわかりません。



All Articles