回答:
はい、簡単です。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.a
とlibMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
ただし、ライブラリの静的バージョンと動的バージョンの両方に同じ名前を付けることはお勧めしません。ライブラリにリンクするツールのコンパイル行で静的リンケージと動的リンケージを簡単に選択できるようにするため、私は異なる名前を使用することを好みます。通常、libMyLib.so
(共有)やlibMyLib_static.a
(静的)などの名前を選択します。(これらはLinuxでの名前になります。)
-fPIC
)として構築する必要があるため、これらの静的ライブラリを使用すると、実行時のオーバーヘッドが少し増えます。したがって、最大のパフォーマンスを得るには、この答えが依然として最善です。
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
あなたが支払う代償は、共有ライブラリがこれを必要とするため(静的ライブラリは気にしない)、オブジェクトファイルは位置独立コードとして構築されなければならないということです。位置に依存しないコードは効率が悪い場合があることに注意してください。最大のパフォーマンスを目指す場合は、静的ライブラリを使用します。さらに、静的にリンクされた実行可能ファイルを配布する方が簡単です。
target_link_libraries()
、ライブラリに依存する後続の 呼び出しが「オブジェクトライブラリ」を使用してリンクできないことでした。これらは、新しい共有ライブラリまたは静的ライブラリをターゲットにする必要があります(重複する可能性があります)。しかし、最初のコメント投稿者の経験とは異なり、これは非常に便利で、重複したターゲットをすべて削除して、すべてのCMakeLists.txt
ファイルを半分近くにカットすることができました。
set_property
を使用objlib
したときのみ機能し、を使用したときは機能しませんでした${objlib}
。それで、おそらくこの答えは修正できますか?
通常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
し、もう一方を使用します。
以前の回答で示唆されているように、すべてを同じコンパイルのブレスにパックすることは可能ですが、最終的には単純なプロジェクトでのみ機能するハックであるため、私はそれをお勧めしません。たとえば、ライブラリのバージョンが異なると、ある時点で異なるフラグが必要になる場合があります(特に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つの異なるプロジェクトに配置することができます。
それは確かに可能です。@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の場合)の両方を取得できます。