2012-07-11 6 views
38

私は、次のようなレイアウトを持っている:CMake:どのようにサブプロジェクトのすべての静的ライブラリから単一の共有ライブラリを作成しますか?

top_project 
    + subproject1 
    + subproject2 

subproject1subproject2のそれぞれは、静的ライブラリを作成します。これらの静的ライブラリを、top_projectレベルの単一の共有ライブラリにリンクしたいと思います。

私がこれまでに収集した情報は次のとおりです。

  • いずれの単一の共有ライブラリに静的ライブラリをリンクしたりできるようになります位置に依存しないコードを作成するために、(Windowsの以外のすべての必要な)-fPicを使用してコンパイル解凍すべての静的ライブラリ(例えばarを使用)、
  • すべてのソースファイルがadd_libraryコマンドに明示的に指定する必要があります(私は洗練&非ポータブルソリューションだと思います)、共有ライブラリにそれらを再リンク:何らかの理由でその私は理解することができない、単に書くことadd_library(${PROJECT_NAME} SHARED subproject1 subproject2)が期待どおりに動作しません(本質的に空のライブラリを作成します)
  • CMakeにOBJECTライブラリ機能がありますが、実際に私が望むことは目的ではないと思います。

+0

私はcmake 3.4。+を使用しています。共有ライブラリに静的ライブラリを追加するだけです。これらは1つのファイルにコンパイルされています:)私はこれをアンドロイドでテストしました:) –

+0

誰かがMSVCの下でこれを行う方法についてヒントを持っていますか?私はqmakeを使用していますが、cmakeではありませんが、私がそれらを理解することができれば、私はステップを自分で処理することができます... –

答えて

27

わかりました。これはわかりました。これははるかに痛いものです。非常に最近まで、Kitwareの人々は誰がなぜ静的ライブラリからDLLを作成したいのか理解できませんでした。彼らの主張は、実質的にそれ自身のプロジェクトであるので、メインファイル(例えば、私の場合はtop_project)ディレクトリにソースファイルが常にあるはずであるということです。私は物事が異なって見える&私はtop_projectを独立して存在してはならない小さなサブプロジェクトに分割する必要があります。つまり、&のために本格的なプロジェクトを作成する際には、ExternalProject_Addを使用して追加する必要はありません。また、共有ライブラリを(Java Native Interfaceなどで)使用する場合、プロジェクトの内部レイアウトが公開されるため、数十の共有ライブラリを出荷する必要はありません。とにかく、静的ライブラリから共有ライブラリを作成した場合、技術的な詳細に進むつもりです。 subproject1subproject2のCMakeLists.txtで

、あなたは(CMakeの2.8.8で導入された)オブジェクトライブラリ機能を使用して、ターゲットを作成する必要があります。

SRCは、ソースファイルのリスト(注を指定
add_library(${PROJECT_NAME} OBJECT ${SRC}) 

makeがCMakeLists.txtの変更が検出されたときにmakeがCMakeを再起動できるように、CMakeLists.txtファイルに明示的に設定する必要があります。追加または削除するファイル)を

top_project

を使用して、サブプロジェクトを追加する場合:

add_subdirectory(subproject1) 
add_subdirectory(subproject2) 

を、静的ライブラリから使用するシンボルを参照するために:

set(CMAKE_SHARED_LINKER_FLAGS "-Wl,--export-all-symbols") 

あなたがすることができ、その後

add_library(${PROJECT_NAME} SHARED $<TARGET_OBJECTS:subproject1> 
            $<TARGET_OBJECTS:subproject2>) 

私は、 "正常な"ライブラリーすなわち、オブジェクトではない)を別のadd_libraryコマンドで追加する必要があります。それ以外の場合は単に無視されます。実行可能ファイルの

、あなたが使用することができます。

add_executable(name_of_executable $<TARGET_OBJECTS:subproject1> 
        $<TARGET_OBJECTS:subproject2>) 
set(LINK_FLAGS ${LINK_FLAGS} "-Wl,-whole-archive") 
target_link_libraries(name_of_executable ${PROJECT_NAME} 

私はこれが唯一にCMakeのバージョン2.8.8のように動作することを繰り返します。同様に、CMakeは依存関係を非常によく管理しています。&はクロスプラットフォームです。これは普通の古いMakefiles &よりもはるかに柔軟ではありません。

+0

annoyingly Ubuntu 12.04はCMake 2.8.7でスタックされています。ライブラリを定義するときにすべてのソースファイルを参照するだけですか? – Ibrahim

+2

静的ライブラリを-fPICでコンパイルして問題を解決しましたが、共有ライブラリは正しくリンクされていましたが、まだ使用していないので実際には動作しません。 – Ibrahim

1

それを行うための別の方法は、ソースファイルとすべてのあなたのヘッダファイルのパスを提供することですプロジェクトを作成し、一緒にビルドして.soを生成します。静的ライブラリを作成する代わりに、通常はこれをお勧めします。

基本的に次の操作を行う必要があります。

FILE(GLOB subproject1_sources 
    <sub_project1_lib_sources_dir>/file1.c 
    <sub_project1_lib_sources_dir>/file2.c //... etc 
) 

FILE(GLOB subproject2_sources 
    <sub_project2_lib_sources_dir>/file1.c 
    <sub_project2_lib_sources_dir>/file2.c //... etc 
) 

FILE(GLOB topProject_sources 
    <top_project_lib_sources_dir>/file1.c 
    <top_project_lib_sources_dir>/file2.c //... etc 
) 

include_directories("<sub_project1_lib_sources_dir>") 
include_directories("<sub_project2_lib_sources_dir>") 
include_directories("<top_project_lib_sources_dir>") //should be "." if you're building from here 

add_library(topProject SHARED ${topProject_sources} ${subproject1_sources} ${subproject2_sources}) 
+0

これは非常に有用ではありません。問題は、しばしば変更したくない内部の魔法によって.oファイルを生成する古いビルドシステムが混在していることです。あなたはめったに生産システムのソースのリストを追加することはできません。 –

4

私のソリューションは、サブライブラリのすべてがある、あなたのメインのライブラリがリンクされているときように、リンカフラグに/WHOLEARCHIVE-all_load、または--whole-archiveを追加するだけです。すべてのシンボル(本体のみライブラリで使用されているサブライブラリのシンボルを含めるようにデフォルトの動作があるなど、含またとえば、次のように

ソースファイル

$ echo "void Func1() { }" > source1.cpp 
$ echo "void Func2() { }" > source2.cpp 
$ echo "void Func3() { }" > source3.cpp 
$ echo "void Func4() { }" > source4.cpp 

ナイーブCMakeLists.txt

cmake_minimum_required(VERSION 3.7) 

# The 'sub' libraries, e.g. from an `add_subdirectory()` call. 
add_library(sublib_a STATIC source1.cpp source2.cpp) 
add_library(sublib_b STATIC source3.cpp source4.cpp) 

# The main library that contains all of the sub libraries. 
add_library(mainlib SHARED) 

target_link_libraries(mainlib sublib_a sublib_b) 

(OSX上で)それを実行:

$ make VERBOSE=1 
... 
[100%] Linking CXX shared library libmainlib.dylib 
/usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1 
/Library/Developer/CommandLineTools/usr/bin/c++ -dynamiclib -Wl,-headerpad_max_install_names -o libmainlib.dylib -install_name @rpath/libmainlib.dylib libsublib_a.a libsublib_b.a 
[100%] Built target mainlib 

$ nm libmainlib.dylib | grep Func 
$ 

正しいCMakeLists.txt

追加この:

# By default, symbols provided by the sublibs that are not used by mainlib (which is all of them in this case) 
# are not used. This changes that. 
if (WIN32) 
    set_target_properties(mainlib PROPERTIES 
     LINK_FLAGS "/WHOLEARCHIVE" 
    ) 
elseif (APPLE) 
    set_target_properties(mainlib PROPERTIES 
     LINK_FLAGS "-Wl,-all_load" 
    ) 
else() 
    set_target_properties(mainlib PROPERTIES 
     LINK_FLAGS "-Wl,--whole-archive" 
    ) 
endif() 

それを実行しています(余分なものに注意してください-all_load):私は実際にこれまで-all_loadをテストしてみた、と/WHOLEARCHIVEはMSVC 2015オプションです

$ make VERBOSE=1 
[100%] Linking CXX shared library libmainlib.dylib 
/usr/local/Cellar/cmake/3.7.1/bin/cmake -E cmake_link_script CMakeFiles/mainlib.dir/link.txt --verbose=1 
/Library/Developer/CommandLineTools/usr/bin/c++ -dynamiclib -Wl,-headerpad_max_install_names -Wl,-all_load -o libmainlib.dylib -install_name @rpath/libmainlib.dylib libsublib_a.a libsublib_b.a 
[100%] Built target mainlib 

$ nm libmainlib.dylib | grep Func 
0000000000001da0 T __Z5Func1v 
0000000000001db0 T __Z5Func2v 
0000000000001dc0 T __Z5Func3v 
0000000000001dd0 T __Z5Func4v 

注意。

+0

私はLinux上で '-Wl、 - whole-archive'を追加すると、' libgcc.a'に関連する多数の "多重定義"エラーが発生しました – nodakai

+0

'/ WHOLEARCHIVE'オプションはうまくいきませんまあ、私はちょうどオブジェクトライブラリのアプローチに行きました。 – Timmmm

関連する問題