web-dev-qa-db-ja.com

CMakeを使用して複数の静的ライブラリを1つに結合する

私は多くの静的ライブラリに依存するプロジェクトを持っているcmakeメーリングリストにある described に非常に似た問題があります(すべて個別のサブモジュールのソースから構築されます) 、各ライブラリのビルドプロセスを説明する独自のCMakeLists.txtを含む)を、コンシューマにリリースするために単一の静的ライブラリに結合したいと思います。私のライブラリの依存関係は変更される可能性があり、開発者がこれらの変更でチェーンのさらに下に負担をかけたくありません。適切なソリューションは、すべてのライブラリを1つのライブラリにバンドルすることです。

興味深いことに、target_link_librariesコマンドは、ターゲットをmylibに設定し、そのように使用する場合、すべての静的を結合しません。 。

target_link_libraries(mylib a b c d)

しかし、奇妙なことに、mylibプロジェクトを実行可能プロジェクトのサブモジュールにし、最上位の実行可能CMAkeLists.txtのmylibに対してのみリンクすると、ライブラリは結合されているように見えます。つまりターゲットをmylibのみをビルドするように設定した場合、mylibは3 MBではなく27 MBです。

オブジェクトファイルへのライブラリの展開と( here 、および here )、しかし、CMakeが上記の例で説明されているようにlibを自動的にマージできると完全に思われる場合、これは著しく不器用に見えます。それは私が見逃している魔法のコマンド、またはリリースライブラリを作成するための推奨されるエレガントな方法ですか?

22
learnvst

私が考えることができる最も単純な作業例を考えると、2つのクラス、ab、ここでabに依存します。 。

ああ

#ifndef A_H
#define A_H

class aclass
{
public:
    int method(int x, int y);
};

#endif

a.cpp

#include "a.h"
#include "b.h"

int aclass::method(int x, int y) {
    bclass b;
    return x * b.method(x,y);
}

b.h

#ifndef B_H
#define B_H

class bclass
{
public:
    int method(int x, int y);
};

#endif

b.cpp

#include "b.h"

int bclass::method(int x, int y) {
    return x+y;
}

main.cpp

#include "a.h"
#include <iostream>

int main()
{
    aclass a;
    std::cout << a.method(3,4) << std::endl;

    return 0;
}

これらを個別の静的ライブラリにコンパイルし、カスタムターゲットを使用して静的ライブラリを結合することができます。

cmake_minimum_required(VERSION 2.8.7)

add_library(b b.cpp b.h)
add_library(a a.cpp a.h)
add_executable(main main.cpp)

set(C_LIB ${CMAKE_BINARY_DIR}/libcombi.a)

add_custom_target(combined
        COMMAND ar -x $<TARGET_FILE:a>
        COMMAND ar -x $<TARGET_FILE:b>
        COMMAND ar -qcs ${C_LIB} *.o
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS a b
        )

add_library(c STATIC IMPORTED GLOBAL)
add_dependencies(c combined)

set_target_properties(c
        PROPERTIES
        IMPORTED_LOCATION ${C_LIB}
        )

target_link_libraries(main c)

Appleのlibtoolバージョンのカスタムターゲットを使用しても正常に機能します。 。 。

add_custom_target(combined
        COMMAND libtool -static -o ${C_LIB} $<TARGET_FILE:a> $<TARGET_FILE:b>
        WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
        DEPENDS a b
        )

きちんとした方法があるべきであるかのようにまだ継ぎ目。 。

10
learnvst

マージしようとしているライブラリがサードパーティのものである場合(learnvstの例に続いて)、このコードは可能な.oファイルの置き換えを処理します(たとえば、libaとlibbの両方のファイル名がzzz.oの場合)

## Create static library (by joining the new objects and the dependencies)
ADD_LIBRARY("${PROJECT_NAME}-static" STATIC ${SOURCES})
add_custom_command(OUTPUT lib${PROJECT_NAME}.a
                   COMMAND rm ARGS -f *.o
                   COMMAND ar ARGS -x ${CMAKE_BINARY_DIR}/lib${PROJECT_NAME}-static.a
                   COMMAND rename ARGS 's/^/lib${PROJECT_NAME}-static./g' *.o
                   COMMAND rename ARGS 's/\\.o/.otmp/g' *.o
                   COMMAND ar ARGS -x ${CMAKE_SOURCE_DIR}/lib/a/liba.a
                   COMMAND rename ARGS 's/^/liba./g' *.o
                   COMMAND rename ARGS 's/\\.o/.otmp/g' *.o
                   COMMAND ar ARGS -x ${CMAKE_SOURCE_DIR}/lib/b/libb.a
                   COMMAND rename ARGS 's/^/libb./g' *.o
                   COMMAND rename ARGS 's/\\.o/.otmp/g' *.o
                   COMMAND rename ARGS 's/\\.otmp/.o/g' *.otmp
                   COMMAND ar ARGS -r lib${PROJECT_NAME}.a *.o
                   COMMAND rm ARGS -f *.o
                   DEPENDS "${PROJECT_NAME}-static")

add_custom_target(${PROJECT_NAME} ALL DEPENDS lib${PROJECT_NAME}.a)

それ以外の場合、ライブラリが自分のものであれば、CMake OBJECTライブラリを使用する必要があります。CMakeOBJECTライブラリは、それらをマージするための非常に優れたメカニズムです。

4
debuti

この関数を使用して、任意の数のライブラリを結合できます。

function(combine_archives output_archive list_of_input_archives)
    set(mri_file ${TEMP_DIR}/${output_archive}.mri)
    set(FULL_OUTPUT_PATH ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/lib${output_archive}.a)
    file(WRITE ${mri_file} "create ${FULL_OUTPUT_PATH}\n")
    FOREACH(in_archive ${list_of_input_archives})
        file(APPEND ${mri_file} "addlib ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}/lib${in_archive}.a\n")
    ENDFOREACH()
    file(APPEND ${mri_file} "save\n")
    file(APPEND ${mri_file} "end\n")

    set(output_archive_dummy_file ${TEMP_DIR}/${output_archive}.dummy.cpp)
    add_custom_command(OUTPUT ${output_archive_dummy_file}
                       COMMAND touch ${output_archive_dummy_file}
                       DEPENDS ${list_of_input_archives})

    add_library(${output_archive} STATIC ${output_archive_dummy_file})
    add_custom_command(TARGET ${output_archive}
                       POST_BUILD
                       COMMAND ar -M < ${mri_file})
endfunction(combine_archives)

Add_custom_targetではなくadd_custom_commandを使用する利点があります。このように、ライブラリ(および依存関係)は、毎回ではなく、必要なときにのみ構築されます。欠点は、ダミーファイルの生成の印刷です。

3
zbut