CMake를 사용하여 여러 정적 라이브러리를 하나로 결합
cmake 메일링 리스트에 기재되어 있는 것과 같은 문제가 있습니다.프로젝트는 다수의 스태틱라이브러리에 의존합니다(모두 개별 서브모듈의 소스로부터 구축되어 각각 독자적인 CMake Lists).각 라이브러리의 빌드 프로세스를 설명하는 txt)를 사용하여 하나의 정적 라이브러리로 결합하여 소비자에게 공개하고 싶습니다.제 라이브러리의 의존성은 변경될 수 있으며, 이러한 변화로 인해 개발자들에게 부담을 주고 싶지 않습니다.가장 좋은 해결책은 모든 libs를 하나의 lib에 묶는 것입니다.
재미있게도target_link_libraries
타깃 설정 시 명령어가 모든 통계 정보를 결합하지 않습니다.mylib
이렇게 쓰니까...
target_link_libraries(mylib a b c d)
하지만, 이상하게도, 만약 내가 이 모든 것들을mylib
실행 가능한 프로젝트의 하위 모듈을 투영하고 링크만 합니다.mylib
최상위 실행 파일인 CMAkeLists에서 확인할 수 있습니다.txt, 라이브러리가 결합된 것 같습니다.즉, mylib는 27MB로 타깃을 빌드만 설정했을 때 3MB가 아닌mylib
.
libs를 오브젝트 파일로 압축 해제하고 재결합(여기, 여기)하는 솔루션이 있습니다만, 위의 예에서 설명한 바와 같이 CMake가 libs를 자동으로 Marge할 수 있을 것 같으면 이는 매우 서투른 것으로 보입니다.내가 놓치고 있는 마법 명령어나 릴리스 라이브러리를 만들 때 추천할 만한 우아한 방법이 있나요?
내가 생각할 수 있는 가장 간단한 작업 예를 들어, 2개의 클래스,a
그리고.b
,어디에a
에 의존하다b
. .
a.h.
#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;
}
이들을 별도의 static lib로 컴파일한 후 커스텀타깃을 사용하여 static lib를 결합할 수 있습니다.
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)
또, 애플을 사용하면, 정상적으로 동작합니다.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
)
더 깔끔한 방법이 있어야 할 것처럼 여전히 솔기가 있다.
이것이 질문에 직접 답하는 것은 아니지만, 도움이 된다는 것을 알았습니다.
https://cristianadam.eu/20190501/bundling-together-static-libraries-with-cmake/
기본적으로 타깃에 필요한 모든 스태틱lib를 수집하여 하나의 스태틱lib로 결합하는 CMake 함수를 정의합니다.
add_library(awesome_lib STATIC ...);
bundle_static_library(awesome_lib awesome_lib_bundled)
다음은 실제 기능의 복사 및 붙여넣기입니다.
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()
이 기능을 사용하여 원하는 수의 라이브러리에 가입할 수 있습니다.
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를 사용할 수 있는 장점이 있습니다.이렇게 하면 라이브러리(및 의존관계)는 필요할 때만 구축되며 매번 구축되는 것은 아닙니다.단점은 더미 파일 생성 인쇄입니다.
https://cmake.org/pipermail/cmake/2018-September/068263.html
CMake는 그것을 지원하지 않는 것 같습니다.
Marge하려는 라이브러리가 서드파티제인 경우 (learnvst 예에 따라) 이 코드는 .o 파일의 치환을 처리합니다(예를 들어 liba와 libb 둘 다 파일명이 zz.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 라이브러리를 사용해야 합니다.이 라이브러리는 이들 라이브러리의 Marge에 매우 적합한 메커니즘입니다.
이를 위해서는 스태틱라이브러리를 조합하는 조작이 아니라 모든 것을 링크하는 데 필요한 비트가 포함된 CMake Config 파일을 사용자에게 제공하는 것이 좋습니다.CMake를 사용하여 이러한 파일을 생성하거나 pkg-config 파일을 생성할 수 있습니다.또, 「이러한 라이브러리와 링크 하는 방법을 가르쳐 주세요」툴의 다른 형식도 사용할 수 있습니다.
링크처의 라이브러리에 관심이 있는 유저도 있을 가능성이 있습니다.또, 링크처에서는, 같은 라이브러리의 카피나 버전을 사용하고 있는 경우도 있습니다.바로 이 경우 솔루션이 엉망으로 되어 사용자가 여러 코드를 통합할 수 없게 됩니다.그 이유는 의존관계(정적 라이브러리의 의존관계를 하나의 정적 라이브러리에 결합할 때 수행하는 작업)의 복사본을 반드시 사용해야 한다고 판단했기 때문입니다.
언급URL : https://stackoverflow.com/questions/37924383/combining-several-static-libraries-into-one-using-cmake
'programing' 카테고리의 다른 글
구조에서는 하나의 어레이 필드를 사용하여 다른 어레이 필드에 액세스하는 것이 합법입니까? (0) | 2022.08.11 |
---|---|
vuex: 비동기 함수에서 기본값 설정 (0) | 2022.08.11 |
모달 Bootstrap-vue를 사용하여 백그라운드에서 이벤트 클릭 가져오기 (0) | 2022.08.10 |
정의되지 않은 속성 'length'를 읽을 수 없습니다." (0) | 2022.08.10 |
switch 문에서 instance of operator를 사용할 수 있습니까? (0) | 2022.08.10 |