it-swarm.com.de

Mehrere statische Bibliotheken mit CMake zu einer zusammenfassen

Ich habe ein sehr ähnliches Problem wie ein beschrieben auf der cmake-Mailingliste, bei dem wir ein Projekt haben, das von vielen statischen Bibliotheken abhängig ist (alle in einzelnen Submodulen aus dem Quellcode erstellt), wobei jede ihre eigene CMakeLists.txt enthält, die den Build-Prozess für jede beschreibt Bibliothek), die ich zu einer einzigen statischen Bibliothek zusammenfassen möchte, um sie den Verbrauchern zur Verfügung zu stellen. Die Abhängigkeiten meiner Bibliothek können sich ändern, und ich möchte die Entwickler nicht weiter mit diesen Änderungen belasten. Die beste Lösung wäre, alle Bibliotheken in einer einzigen Bibliothek zu bündeln.

Interessanterweise kombiniert der Befehl target_link_libraries nicht alle Statiken, wenn das Ziel auf mylib festgelegt und auf diese Weise verwendet wird. . 

target_link_libraries(mylib a b c d)

Seltsamerweise, wenn ich das mylib-Projekt zu einem Untermodul eines ausführbaren Projekts mache und nur gegen mylib in der ausführbaren Datei CMAkeLists.txt der obersten Ebene verlinke, scheint die Bibliothek kombiniert zu sein. Das heißt Mylib ist 27 MB, anstatt der 3 MB, wenn ich das Ziel so eingestellt habe, dass nur mylib erstellt wird.

Es gibt Lösungen, die das Entpacken der Bibliotheken in Objektdateien beschreiben und rekombinieren ( hier und hier ). Dies scheint jedoch bemerkenswert ungeschickt zu sein, wenn CMake perfekt in der Lage ist, die Bibliotheken automatisch zu mischen, wie im obigen Beispiel beschrieben. Fehlt da ein magischer Befehl oder eine empfohlene elegante Art, eine Release-Bibliothek zu erstellen?

15
learnvst

In Anbetracht des einfachsten Arbeitsbeispiels kann ich mir vorstellen: 2 Klassen, a und b, wobei a von b abhängt. .

ah

#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;
}

Es ist möglich, diese in separate statische Bibliotheken zu kompilieren und dann die statischen Bibliotheken mit einem benutzerdefinierten Ziel zu kombinieren.

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)

Es funktioniert auch gut mit Apples libtool-Version des benutzerdefinierten Ziels. . .

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

Noch Nähte, als ob es einen sauberen Weg geben sollte. .

9
learnvst

Wenn die Bibliotheken, die Sie zusammenführen möchten, von Drittanbietern stammen, kümmert sich dieser Code (nach learnvst-Beispiel) um mögliche Ersetzung von .o-Dateien (wenn z. B. liba und libb einen Dateinamen zzz.o haben)

## 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)

Andernfalls sollten Sie, wenn die Bibliotheken Ihnen gehören, CMake OBJECT-Bibliotheken verwenden. Dies ist ein ziemlich guter Mechanismus, um sie zusammenzuführen.

3
debuti

Mit dieser Funktion können Sie beliebig viele Bibliotheken zusammenfügen.

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)

Es hat die Vorteile von add_custom_command und nicht von add_custom_target. Auf diese Weise werden die Bibliothek (und ihre Abhängigkeiten) nur dann erstellt, wenn sie benötigt wird, und nicht jedes Mal ..__ Der Nachteil ist der Ausdruck der Generierung der Dummy-Datei.

0
zbut