lea*_*vst 25 c c++ cmake static-libraries
我有一个非常类似于cmake邮件列表中描述的问题,我们有一个依赖于许多静态库的项目(所有静态库都是从各个子模块中的源代码构建的,每个子模块都有自己的CMakeLists.txt描述每个库的构建过程)我想组合成一个静态库,以便向消费者发布.我的库的依赖性可能会发生变化,我不想让开发人员在这些变化的后面进一步负担.简洁的解决方案是将所有lib捆绑到一个单独的lib中.
有趣的是,target_link_libraries在设置目标mylib和使用它时,该命令不会结合所有静态..
target_link_libraries(mylib a b c d)
Run Code Online (Sandbox Code Playgroud)
但是,奇怪的是,如果我将mylib项目作为可执行项目的子模块,并且只mylib在顶级可执行文件CMAkeLists.txt中链接,那么该库似乎确实是组合在一起的.即,当我将目标设置为仅构建时,mylib为27 MB,而不是3 MB mylib.
有一些解决方案描述了将lib解压缩到目标文件并重新组合(这里和这里),但是当CMake看起来完全能够自动合并lib时,这似乎非常笨拙,如上例所述.它有一个我失踪的神奇命令,或推荐的优雅方式制作发布库?
lea*_*vst 10
鉴于最简单的工作示例,我可以想到:2个类,a以及b在哪里a取决于b..
#ifndef A_H
#define A_H
class aclass
{
public:
int method(int x, int y);
};
#endif
Run Code Online (Sandbox Code Playgroud)
#include "a.h"
#include "b.h"
int aclass::method(int x, int y) {
bclass b;
return x * b.method(x,y);
}
Run Code Online (Sandbox Code Playgroud)
#ifndef B_H
#define B_H
class bclass
{
public:
int method(int x, int y);
};
#endif
Run Code Online (Sandbox Code Playgroud)
#include "b.h"
int bclass::method(int x, int y) {
return x+y;
}
Run Code Online (Sandbox Code Playgroud)
#include "a.h"
#include <iostream>
int main()
{
aclass a;
std::cout << a.method(3,4) << std::endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
可以将它们编译为单独的静态库,然后使用自定义目标组合静态库.
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)
Run Code Online (Sandbox Code Playgroud)
使用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
)
Run Code Online (Sandbox Code Playgroud)
仍然接缝似乎应该有一个更简洁的方式..
小智 6
您可以使用此功能来加入任意数量的库。
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)
Run Code Online (Sandbox Code Playgroud)
它具有使用add_custom_command而不是add_custom_target的好处。这样,库(及其依赖项)仅在需要时才构建,而不是每次都构建。缺点是伪文件生成的打印。
这并没有直接回答问题,但我发现它很有用:
https://cristianadam.eu/20190501/bundling-together-static-libraries-with-cmake/
基本,定义一个 CMake 函数,它将收集目标所需的所有静态库并将它们组合成一个静态库:
add_library(awesome_lib STATIC ...);
bundle_static_library(awesome_lib awesome_lib_bundled)
Run Code Online (Sandbox Code Playgroud)
这是实际功能的复制和粘贴:
function(bundle_static_library tgt_name bundled_tgt_name)
list(APPEND static_libs ${tgt_name})
function(_recursively_collect_dependencies input_target)
set(_input_link_libraries LINK_LIBRARIES)
get_target_property(_input_type ${input_target} TYPE)
if (${_input_type} STREQUAL "INTERFACE_LIBRARY")
set(_input_link_libraries INTERFACE_LINK_LIBRARIES)
endif()
get_target_property(public_dependencies ${input_target} ${_input_link_libraries})
foreach(dependency IN LISTS public_dependencies)
if(TARGET ${dependency})
get_target_property(alias ${dependency} ALIASED_TARGET)
if (TARGET ${alias})
set(dependency ${alias})
endif()
get_target_property(_type ${dependency} TYPE)
if (${_type} STREQUAL "STATIC_LIBRARY")
list(APPEND static_libs ${dependency})
endif()
get_property(library_already_added
GLOBAL PROPERTY _${tgt_name}_static_bundle_${dependency})
if (NOT library_already_added)
set_property(GLOBAL PROPERTY _${tgt_name}_static_bundle_${dependency} ON)
_recursively_collect_dependencies(${dependency})
endif()
endif()
endforeach()
set(static_libs ${static_libs} PARENT_SCOPE)
endfunction()
_recursively_collect_dependencies(${tgt_name})
list(REMOVE_DUPLICATES static_libs)
set(bundled_tgt_full_name
${CMAKE_BINARY_DIR}/${CMAKE_STATIC_LIBRARY_PREFIX}${bundled_tgt_name}${CMAKE_STATIC_LIBRARY_SUFFIX})
if (CMAKE_CXX_COMPILER_ID MATCHES "^(Clang|GNU)$")
file(WRITE ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in
"CREATE ${bundled_tgt_full_name}\n" )
foreach(tgt IN LISTS static_libs)
file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in
"ADDLIB $<TARGET_FILE:${tgt}>\n")
endforeach()
file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in "SAVE\n")
file(APPEND ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in "END\n")
file(GENERATE
OUTPUT ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar
INPUT ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar.in)
set(ar_tool ${CMAKE_AR})
if (CMAKE_INTERPROCEDURAL_OPTIMIZATION)
set(ar_tool ${CMAKE_CXX_COMPILER_AR})
endif()
add_custom_command(
COMMAND ${ar_tool} -M < ${CMAKE_BINARY_DIR}/${bundled_tgt_name}.ar
OUTPUT ${bundled_tgt_full_name}
COMMENT "Bundling ${bundled_tgt_name}"
VERBATIM)
elseif(MSVC)
find_program(lib_tool lib)
foreach(tgt IN LISTS static_libs)
list(APPEND static_libs_full_names $<TARGET_FILE:${tgt}>)
endforeach()
add_custom_command(
COMMAND ${lib_tool} /NOLOGO /OUT:${bundled_tgt_full_name} ${static_libs_full_names}
OUTPUT ${bundled_tgt_full_name}
COMMENT "Bundling ${bundled_tgt_name}"
VERBATIM)
else()
message(FATAL_ERROR "Unknown bundle scenario!")
endif()
add_custom_target(bundling_target ALL DEPENDS ${bundled_tgt_full_name})
add_dependencies(bundling_target ${tgt_name})
add_library(${bundled_tgt_name} STATIC IMPORTED)
set_target_properties(${bundled_tgt_name}
PROPERTIES
IMPORTED_LOCATION ${bundled_tgt_full_name}
INTERFACE_INCLUDE_DIRECTORIES $<TARGET_PROPERTY:${tgt_name},INTERFACE_INCLUDE_DIRECTORIES>)
add_dependencies(${bundled_tgt_name} bundling_target)
endfunction()
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
10808 次 |
| 最近记录: |