CMakeに同じライブラリの静的バージョンと共有バージョンの両方をビルドさせることは可能ですか?


141

同じソース、それだけでも、静的バージョンと共有バージョンの両方が必要です。簡単ですか?

回答:


123

はい、簡単です。2つの「add_library」コマンドを使用するだけです。

add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)

多くのソースファイルがある場合でも、ソースのリストをcmake変数に配置するので、簡単に実行できます。

Windowsでは、共有と静的の両方に「.lib」ファイルがあるため、おそらく各ライブラリに異なる名前を付ける必要があります。しかし、LinuxとMacでは、両方のライブラリに同じ名前を付けることもできます(例:libMyLib.alibMyLib.so):

set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)

ただし、ライブラリの静的バージョンと動的バージョンの両方に同じ名前を付けることはお勧めしません。ライブラリにリンクするツールのコンパイル行で静的リンケージと動的リンケージを簡単に選択できるようにするため、私は異なる名前を使用することを好みます。通常、libMyLib.so(共有)やlibMyLib_static.a(静的)などの名前を選択します。(これらはLinuxでの名前になります。)


彼らが同じ名前を持つことを望んでいたが、まあ。別の質問:可能な場合、静的ライブラリを共有ライブラリにリンクするようにCMakeに指示できますか?
2010年

「同じ名前」の詳細:Windowsを使用していて、両方のライブラリに同じ名前が必要で、共有.libファイルが必要ない場合は、静的.libと共有.dllを作成できます。ただし、通常のコンパイル時リンクにライブラリを使用している場合は、その共有.libファイルが必要です。
クリストファーブランズ2010年

1
静的ライブラリを共有ライブラリにリンクすることについてのあなたの質問を理解したかわかりません。
Christopher Bruns

5
これはもう推奨される方法ではないことに注意しください。重要なサイズのプロジェクト(コンパイルに数秒ではなく数分かかるプロジェクト)の場合、コンパイル時間を2倍にしないのは不思議です。:オブジェクトライブラリの使用状況やドキュメントについては、以下のuser465139の答えを参照してくださいcmake.org/cmake/help/v3.8/command/...
KymikoLoco

3
@KymikoLoco:オブジェクトライブラリアプローチは実際にコンパイル時間を半分に短縮しますが、静的ライブラリを位置独立コード(つまり-fPIC)として構築する必要があるため、これらの静的ライブラリを使用すると、実行時のオーバーヘッドが少し増えます。したがって、最大のパフォーマンスを得るには、この答えが依然として最善です。
John Zwinck 2017

95

CMakeバージョン2.8.8以降、「オブジェクトライブラリ」使用して、オブジェクトファイルのコンパイルの重複を回避できます。2つのソースファイルを持つライブラリのクリストファーブランズの例を使用します。

# list of source files
set(libsrc source1.c source2.c)

# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})

# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)

# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)

CMakeのドキュメントから:

オブジェクトライブラリはソースファイルをコンパイルしますが、オブジェクトファイルをライブラリにアーカイブまたはリンクしません。代わりに、フォームの式をソースとして使用してオブジェクトを作成するadd_library()add_executable()参照する可能性のある他のターゲット( $<TARGET_OBJECTS:objlib>objlibはオブジェクトライブラリ名)。

簡単に言うと、add_library(objlib OBJECT ${libsrc})コマンドはソースファイルを*.oオブジェクトファイルにコンパイルするようにCMakeに指示します。この*.oファイルのコレクションは、同じオブジェクトファイルのセットから共有ライブラリと静的ライブラリを構築する適切なライブラリ作成コマンドを呼び出す$<TARGET_OBJECT:objlib>2つのadd_library(...)コマンドで参照されます。ソースファイルが多数ある場合、ファイルのコンパイルにはかなり時間がかかることがあります。オブジェクトライブラリを使用すると、一度だけコンパイルできます。*.o

あなたが支払う代償は、共有ライブラリがこれを必要とするため(静的ライブラリは気にしない)、オブジェクトファイルは位置独立コードとして構築されなければならないということです。位置に依存しないコードは効率が悪い場合があることに注意してください。最大のパフォーマンスを目指す場合は、静的ライブラリを使用します。さらに、静的にリンクされた実行可能ファイルを配布する方が簡単です。


3
これは私にとって魅力のように機能しました。唯一の注意点はtarget_link_libraries()、ライブラリに依存する後続の 呼び出しが「オブジェクトライブラリ」を使用してリンクできないことでした。これらは、新しい共有ライブラリまたは静的ライブラリをターゲットにする必要があります(重複する可能性があります)。しかし、最初のコメント投稿者の経験とは異なり、これは非常に便利で、重複したターゲットをすべて削除して、すべてのCMakeLists.txtファイルを半分近くにカットすることができました。
fish2000 2016年

1
ターゲットプロパティを設定するときにobblibを「エスケープ」する必要がありますか?つまり、set_property(TARGET $ {objlib} PROPERTY ...)対set_property(TARGET objlib PROPERTY ...)
gnac

1
誰がこれに反対票を投じたのか...その人は彼/彼女が間違っていると考えたものについての説明を提供できますか?これはOPが望むことを行う推奨される方法であるため、なおさらです。CMakeのドキュメントを参照してください。
Laryx Decidua 2017

1
@ user465139おそらく、静的ターゲットと共有ターゲットの両方でオブジェクトファイルを再利用する理由が説明できるはずです。特に、SOの一般的な知識はまだ非常に混乱しています。古いアーカイブはそれを明確にするのに役立ちません。cmake.org/pipermail/cmake/2008-March/020315.html 現状についてのしっかりした説明が必要です。ps反対票を投じたのは私ではありませんでした
mloskot

2
@gnac確認できません。私の場合、set_propertyを使用objlibしたときのみ機能し、を使用したときは機能しませんでした${objlib}。それで、おそらくこの答えは修正できますか?
josch

22

通常ADD_LIBRARY、目的に合わせて通話を複製する必要はありません。ちょうど利用する

$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$' 
   BUILD_SHARED_LIBS
          Global flag to cause add_library to create shared libraries if on.

          If present and true, this will cause all libraries to be built shared unless the library was
          explicitly added as a static library.  This variable is often added to projects as an OPTION
          so  that each user of a project can decide if they want to build the project using shared or
          static libraries.

ビルド中は、最初に(1つのソース外のディレクトリで)を-DBUILD_SHARED_LIBS:BOOL=ON使用OFFし、もう一方を使用します。


43
これは静的バージョンと共有バージョンの両方を構築していないようですが、これがこの質問で達成されていることだと思います。
Nick Desaulniers、2015

0

以前の回答で示唆されているように、すべてを同じコンパイルのブレスにパックすることは可能ですが、最終的には単純なプロジェクトでのみ機能するハックであるため、私はそれをお勧めしません。たとえば、ライブラリのバージョンが異なると、ある時点で異なるフラグが必要になる場合があります(特にWindowsの場合、フラグは通常、シンボルのエクスポートの切り替えに使用されます)。または、上記のように、.libファイルが静的ライブラリまたは共有ライブラリに対応しているかどうかに応じて、ファイルを異なるディレクトリするます。それらのハードルのそれぞれは、新しいハックが必要になります。

明白かもしれませんが、以前に言及されていない1つの代替策は、ライブラリーのタイプをパラメーターにすることです:

set( ${PROJECT_NAME}_LIBTYPE CACHE STRING "library type" )
set_property( CACHE ${PROJECT_NAME}_LIBTYPE PROPERTY STRINGS "SHARED;STATIC" )
add_library( ${PROJECT_NAME} ${PROJECT_NAME}_LIBTYPE ${SOURCE_FILES} )

2つの異なるバイナリツリーでライブラリの共有バージョンと静的バージョンを使用すると、さまざまなコンパイルオプションの処理が容易になります。特にコンパイルが自動化されている場合は、コンパイルツリーを明確にしておくことに重大な欠点はないと思います。

中間OBJECTライブラリを使用してコンパイルを相互化するつもりである場合でも(上記の注意事項があるため、そうするための説得力のある理由が必要です)、エンドライブラリを2つの異なるプロジェクトに配置することができます。


-2

それは確かに可能です。@Christopher Brunsが彼の回答で述べたように、ライブラリの2つのバージョンを追加する必要があります。

set(libsrc source1.c source2.c source3.c)
add_library(mylib-static STATIC ${libsrc})
add_library(mylib-shared SHARED ${libsrc})

次に、ここで説明するように、両方のターゲットが同じ出力名を使用し、互いのファイルを上書きしないように指定する必要があります。

SET_TARGET_PROPERTIES(mylib-static PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(mylib-shared PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)

この方法で、libmylib.aとlibmylib.so(Linuxの場合)またはmylib.libとmylib.dll(Windowsの場合)の両方を取得できます。


10
プロパティは2009年に削除されたため、2.8。[0?]以上のCMakeバージョンを使用する場合、これは不要であり、プロパティが提供する動作がデフォルトになりました。これは2.8未満のユーザーには役立つかもしれませんが、CMake <2.7をまだ使用している場合は、アップグレードするようにお願いします。github.com/Kitware/CMake/commit/...
KymikoLoco
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.