2016-07-08 5 views
7

私はSwift Frameworkをコンパイルし、サードパーティの開発者に配布しています。プロジェクトにいくつかのCコードを追加したいのですが、私がそれを動作させる唯一の方法は、Cヘッダーをフレームワークのヘッダーにインポートし、Cヘッダーをパブリックに設定することです。これは、私たちが望むものではない第三者の開発者にCコードのすべてを公開します。 https://spin.atomicobject.com/2015/02/23/c-libraries-swift/CコードをSwift Frameworkにコンパイルする方法

しかし、この方法の注意点は、あなたがこの技術を用いて構築する任意のフレームワークの消費者はまた、持ってしようとしていることに注意してください」である:私はこれを行う方法については、オンラインで見つけることができます

すべてがこの方法のバリエーションでありますSwiftの検索パスにモジュールを追加することができます。これを試してみましたが、サードパーティの開発者がエラーを受け取りました。Missing required module 'CGeodesic'これは、Cヘッダーを指すように定義したモジュールです。

コードを非公開にして、サードパーティの開発者にビルド設定を変更してもらうために、Cコードをフレームワークにコンパイルするだけではどうでしょう?プロジェクトでこれらのサブモジュールをセットアップする必要はありませんが、一日の終わりには、単一のフレームワークバイナリに直接コンパイルして、ダイナミックリンクや検索パスなどを必要としません。

編集


プロジェクトは、Cコードサイドバイサイドスイフトコードです。

  • 測地/
    • Geodesic.h
    • Geodesic.c
    • Geodesic.swift

:私はこのようになります私のプロジェクトでサブディレクトリを持っていますスウィフトファイルは、Cコードをラップしてよりクリーンなものにする。私はそのディレクトリにmodule.modulemapファイルも持っていましたが、私が以前に言ったように動作しませんでした。私はスウィフトコードでCコードを横に並べることを好みますが、この問題を解決するためにCコードを提供したいと思います。

+0

現在の設定は何ですか? SwiftコードとCコードを並べて表示しますか? – zneak

+0

https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html。これは役に立ちますか? CコードはObjective-Cであり、CとSwiftが混在したフレームワークを書くことができるように見え、ユーザーには単一の言語で書かれたように見えます。私はまだこれを試していない。 – OmniProg

+0

@OmniProgだから、現在行っていることです。その方法の問題は、必然的にすべてのヘッダーを公開することであり、これは避けようとしていることです。 – user1084447

答えて

14

あなたの問題を言い換えると、基本的にSwiftでCコードをラップし、カプセル化されたCコードに直接アクセスしないようにしたいとします。これは、SwiftとObjective-Cの両方からのアクセスを防ぐことを意味します。

これは可能ですが、ビルドプロセスといくつかの後処理を調整する必要があります。フレームワーク

Cとスウィフト相互運用あなたはスウィフトでラップしたい任意のCコードは、アンブレラヘッダを介して、またはモジュールのマップを使用してどちらかのコンパイル時に、公開する必要があります。ここでの重要な部分:コンパイル時。フレームワークには完全性チェックがありません。つまり、後処理を適用することができます(例えば、lipoという太ったバイナリーフレームワークを作成するなど)。それが私たちがここで必要とするものです。アンブレラヘッダにすべてのCヘッダの依存関係を置くこと

代わりにビルドを準備

あなたもmodule.modulemapファイルにそれらを置くことができます。それには1つの利点があります:Headers Build Phaseでヘッダーを非公開にすることができます。したがって

、プロジェクト内module.modulemapファイルを作成し、例えば、Packagingセクション(xcconfigファイルでMODULEMAP_FILE)でModule Map Fileビルド設定で、それへのパスを設定し、$(SRCROOT)/MyFramework/module.modulemap。これまでのところは良い

# module.modulemap 

framework module MyFramework { 

    umbrella header "MyFramework.h" 

    export * 
    module * {export *} 

    # All C Files you want to wrap in your Swift code 

    header "A.h" 
    header "B.h" 
} 

あなたmodule.modulemapファイルには、次の内容を持っている必要があります。これで、コードを作成し、SwiftとObjective-Cの両方からアクセスできるようになりました。唯一の問題:SwiftとObjective-CでCヘッダファイルにアクセスできます。あなたは、最終的なフレームワークバンドルを見ている場合

を後処理

は、すべてのあなたのプライベートヘッダファイルがMyFramework.framework/PrivateHeadersフォルダにコピーされていることがわかります。つまり、Objective-Cでは#import <MyFramework/A.h>でアクセスできます。

Swiftでは、MyFramework.framework/Modules/module.modulemapにコピーされたmodule.modulemapファイルにヘッダーファイルを格納するので、Cコードにアクセスできます。

幸いなことに、私たちは後処理のビットとのそれら二つの問題を取り除くことができます。

  1. フレームワークバンドルからPrivateHeadersフォルダーを削除します。
  2. 個別のmodulemapを作成し、すべてheader "XYZ.h"文を削除します(例:public.modulemap)。
  3. Run Scriptビルドフェーズに

をそのすべてを入れてここで公共modulemapです:

# public.modulemap 

framework module MyFramework { 

    umbrella header "MyFramework.h" 

    export * 
    module * {export *} 

    # No more C Headers here 
} 

そして、あなたはあなたのフレームワークのビルドフェーズの最後に追加する必要があり、実行スクリプト:

# Delete PrivateHeaders folder 
rm -rf ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/PrivateHeaders 

# Remove module.modulemap file 
rm ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

# Copy public.modulemap file and rename it to module.modulemap 
cp ${SRCROOT}/test/public.modulemap ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

# Append the Swift module so you can access you Swift code in Objective-C via @import MyFramework.Swift 
echo "module ${PRODUCT_NAME}.Swift { header \"${PRODUCT_NAME}-Swift.h\" }" >> ${TARGET_BUILD_DIR}/${PRODUCT_NAME}${WRAPPER_SUFFIX}/Modules/module.modulemap 

希望に役立ちます!

+0

完璧に動作します!ありがとうございました! – user1084447

+3

これは複雑な問題に対する優れた答えです。ありがとうございます。 –

+0

この回答はもちろん信じられないほどです、@ JensMeder、ありがとう。1つのこと - おそらく、あなたは*簡単なケースの短い補遺を追加することができます。これは答えを明らかにするかもしれない。私はこれが多くの人に役に立つと思う。 (これに関する古い記事はすべてwwwと一緒に消えてしまった!:)) – Fattie

1

解決策はありますが、お勧めできません。 .Swiftファイル内には、Cヘッダーを使用する代わりにuse @_silgen_nameを使用できます。

関連する問題