使用 CMake 将多个静态库合二为一

2021-12-26 00:00:00 c cmake c++ static-libraries

我有一个与 cmake 上的 描述 非常相似的问题邮件列表,我们有一个依赖于许多静态库的项目(全部从单个子模块中的源代码构建,每个子模块都有自己的 CMakeLists.txt 描述每个库的构建过程),我想将它们组合成一个静态库以供发布给消费者.我的库的依赖项可能会发生变化,我不希望这些变化给链下游的开发人员带来负担.简洁的解决方案是将所有库捆绑到一个库中.

I have a very similar problem to one described on the cmake mailing list where we have a project dependent on many static libraries (all built from source in individual submodules, each with their own CMakeLists.txt describing the build process for each library) that I'd like to combine into a single static library for release to the consumers. The dependencies of my library are subject to change, and I do not want to burden developers further down the chain with those changes. The neat solution would be to bundle all of the libs into one single lib.

有趣的是,在将目标设置为 mylib 并像这样使用它时,target_link_libraries 命令并没有结合所有的静态..

Interestingly, the target_link_libraries command does not combine all of the statics when setting the target to mylib and using it like so . .

target_link_libraries(mylib a b c d)

然而,奇怪的是,如果我使 mylib 项目成为可执行项目的子模块,并且只链接到顶级可执行文件 CMAkeLists.txt 中的 mylib,库似乎是结合在一起的.IE.mylib 是 27 MB,而不是我将目标设置为仅构建 mylib 时的 3MB.

However, bizarrely, if I make the mylib project a submodule of an executable project, and only link against mylib in the top level executable CMAkeLists.txt, the library does seem to be combined. I.e. mylib is 27 MB, instead of the 3MB when I set the target to only build mylib.

有一些解决方案描述了将库解包为目标文件并重新组合(此处 和 此处),但这似乎非常当 CMake 看起来完全有能力自动合并库时,就像上面的例子中描述的那样笨拙.是否有我遗漏的魔法命令,或者推荐的制作发布库的优雅方式?

There are solutions describing unpacking of the libs into object files and recombining (here, and here), but this seems remarkably clumsy when CMake seems perfectly capable of automatically merging the libs as described in the above example. It there a magic command I'm missing, or a recommended elegant way of making a release library?

推荐答案

给出我能想到的最简单的工作示例:2 个类,ab,其中a 依赖于 b ..

Given the most simple working example I can think of: 2 classes, a and b, where a depends on b . .

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

可以将它们编译成单独的静态库,然后使用自定义目标组合静态库.

It is possible to compile these into separate static libs, and then combine the static libs using a custom target.

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 版本的自定义目标也可以正常工作...

It also works just fine using Apple's libtool version of the custom target . . .

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

仍然接缝,好像应该有一个更整洁的方法..

Still seams as though there should be a neater way . .

相关文章