동일한 소스는 정적 및 공유 버전을 모두 원합니다. 쉬운가요?
답변
예, 적당히 쉽습니다. 두 개의 “add_library”명령을 사용하십시오.
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
소스 파일이 많은 경우에도 소스 목록을 cmake 변수에 배치하면 여전히 쉽습니다.
Windows에서는 공유 및 정적 파일에 “.lib”파일이 있으므로 각 라이브러리에 다른 이름을 지정해야합니다. 그러나 Linux 및 Mac에서는 두 라이브러리에 동일한 이름 (예 : libMyLib.a
및 libMyLib.so
) 을 지정할 수도 있습니다 .
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
그러나 정적 및 동적 버전의 라이브러리에 동일한 이름을 지정하지 않는 것이 좋습니다. 라이브러리에 링크하는 도구에 대해 컴파일 라인에서 정적 링크와 동적 링크를 더 쉽게 선택할 수 있기 때문에 다른 이름을 사용하는 것을 선호합니다. 일반적으로 libMyLib.so
(공유) 및 libMyLib_static.a
(정적) 과 같은 이름을 선택합니다 . (이것은 리눅스에서 이름이 될 것입니다.)
답변
CMake 버전 2.8.8부터 “개체 라이브러리” 를 사용 하여 개체 파일의 중복 컴파일을 피할 수 있습니다 . 두 개의 소스 파일이있는 Christopher Bruns의 라이브러리 예제 사용 :
# list of source files
set(libsrc source1.c source2.c)
# this is the "object library" target: compiles the sources only once
add_library(objlib OBJECT ${libsrc})
# shared libraries need PIC
set_property(TARGET objlib PROPERTY POSITION_INDEPENDENT_CODE 1)
# shared and static libraries built from the same object files
add_library(MyLib_shared SHARED $<TARGET_OBJECTS:objlib>)
add_library(MyLib_static STATIC $<TARGET_OBJECTS:objlib>)
로부터 CMake 워드 프로세서 :
오브젝트 라이브러리는 소스 파일을 컴파일하지만 오브젝트 파일을 라이브러리에 아카이브하거나 링크하지 않습니다. 대신 다른 대상
은 양식의 표현식을 소스로 사용하여 오브젝트를 참조add_library()
하거나add_executable()
참조 할 수 있습니다$<TARGET_OBJECTS:objlib>
. 여기서 objlib는 오브젝트 라이브러리 이름입니다.
간단히 add_library(objlib OBJECT ${libsrc})
말해이 명령은 CMake에게 소스 파일을 *.o
객체 파일 로 컴파일하도록 지시 합니다. *.o
그런 다음 이 파일 콜렉션을 동일한 오브젝트 파일 세트 에서 공유 및 정적 라이브러리를 빌드하는 적절한 라이브러리 작성 명령을 호출 $<TARGET_OBJECT:objlib>
하는 두 add_library(...)
명령 에서 참조됩니다 . 소스 파일이 많으면 파일을 컴파일하는 데 시간이 오래 걸릴 수 있습니다. 객체 라이브러리를 사용하면 한 번만 컴파일 할 수 있습니다.*.o
당신이 지불하는 가격은 공유 라이브러리가 이것을 필요로하기 때문에 객체 파일이 위치 독립적 코드로 작성되어야한다는 것입니다 (정적 라이브러리는 신경 쓰지 않습니다). 위치 독립적 인 코드는 효율성이 떨어질 수 있으므로 성능을 극대화하려면 정적 라이브러리를 사용하십시오. 또한 정적으로 링크 된 실행 파일을 배포하는 것이 더 쉽습니다.
답변
일반적으로 ADD_LIBRARY
목적을 위해 통화 를 복제 할 필요는 없습니다 . 그냥 활용하십시오
$> man cmake | grep -A6 '^ *BUILD_SHARED_LIBS$'
BUILD_SHARED_LIBS
Global flag to cause add_library to create shared libraries if on.
If present and true, this will cause all libraries to be built shared unless the library was
explicitly added as a static library. This variable is often added to projects as an OPTION
so that each user of a project can decide if they want to build the project using shared or
static libraries.
와 (한 아웃의 소스 디렉토리에) 먼저 구축하는 동안 -DBUILD_SHARED_LIBS:BOOL=ON
, 그리고 함께 OFF
다른있다.
답변
이전 답변에서 제안한 것과 동일한 컴파일 호흡으로 eveything을 포장하는 것이 가능하지만 결국 간단한 프로젝트에서만 작동하는 해킹이기 때문에 조언하지 않을 것입니다. 예를 들어, 어느 시점에서 라이브러리의 다른 버전에 대해 다른 플래그가 필요할 수 있습니다 (플래그가 일반적으로 심볼 내보내기간에 전환하는 데 사용되는 Windows의 경우). 또는 위에서 언급 한 것처럼 .lib
파일이 정적 또는 공유 라이브러리에 해당하는지에 따라 파일을 다른 디렉토리에 넣을 수 있습니다. 이러한 각 장애물에는 새로운 핵이 필요합니다.
명백 할 수도 있지만 이전에 언급되지 않은 한 가지 대안은 라이브러리 유형을 매개 변수로 만드는 것입니다.
set( ${PROJECT_NAME}_LIBTYPE CACHE STRING "library type" )
set_property( CACHE ${PROJECT_NAME}_LIBTYPE PROPERTY STRINGS "SHARED;STATIC" )
add_library( ${PROJECT_NAME} ${PROJECT_NAME}_LIBTYPE ${SOURCE_FILES} )
두 개의 다른 이진 트리에 라이브러리의 공유 및 정적 버전이 있으면 다른 컴파일 옵션을보다 쉽게 처리 할 수 있습니다. 특히 컴파일이 자동화 된 경우 컴파일 트리를 고유하게 유지하는 데 심각한 결점이 없습니다.
중간 OBJECT
라이브러리를 사용하여 컴파일을 상호 작용하려는 경우에도 (위에 언급 된 경고를 사용하여 강력한 이유가 필요함) 여전히 엔드 라이브러리를 두 개의 다른 프로젝트에 넣을 수 있습니다.
답변
실제로 가능합니다. @Christopher Bruns가 그의 답변에서 말했듯이 라이브러리의 두 가지 버전을 추가해야합니다.
set(libsrc source1.c source2.c source3.c)
add_library(mylib-static STATIC ${libsrc})
add_library(mylib-shared SHARED ${libsrc})
그런 다음 여기 에 설명 된대로 두 대상 모두 동일한 출력 이름을 사용하고 서로의 파일을 덮어 쓰지 않도록 지정해야합니다.
SET_TARGET_PROPERTIES(mylib-static PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(mylib-shared PROPERTIES OUTPUT_NAME mylib CLEAN_DIRECT_OUTPUT 1)
이 방법으로 libmylib.a 및 libmylib.so (Linux) 또는 mylib.lib 및 mylib.dll (Windows)을 모두 얻을 수 있습니다.