Можно ли заставить CMake создавать как статическую, так и общую версию одной и той же библиотеки?


тот же источник, все это, просто хочу статическую и общую версию обоих. Легко сделать?

4 108

4 ответа:

Да, это в меру легко. Просто используйте две "команды add_library":

add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)

даже если у вас много исходных файлов, вы разместите список источников в переменной cmake, так что это все еще легко сделать.

в Windows вы, вероятно, должны дать каждой библиотеке другое имя, так как есть ".lib " файл для общего и статического. Но на Linux и Mac вы даже можете дать обеим библиотекам одно и то же имя (например, libMyLib.а и libMyLib.so):

set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)

Но Я не рекомендуется давать статической и динамической версиям библиотеки одинаковое имя. Я предпочитаю использовать разные имена, потому что это упрощает выбор статической и динамической связи в строке компиляции для инструментов, которые ссылаются на библиотеку. Обычно я выбираю такие имена, как libMyLib.so (shared) и libMyLib_static.статика.) (Это были бы имена в linux.)

начиная с версии CMake 2.8.8, вы можете использовать "библиотеки объектов"чтобы избежать дублирования компиляции объектных файлов. Используя пример библиотеки Кристофера Брунса с двумя исходными файлами:

# 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 docs:

библиотека объектов компилирует исходные файлы, но не архивирует и не связывает их их объектные файлы в библиотеку. Вместо этого другие цели, созданные add_library() или add_executable() может ссылаться на объекты, используя выражение вида $ как источник, где objlib-это имя библиотеки объектов.

проще говоря,add_library(objlib OBJECT ${libsrc}) команда дает команду CMake скомпилировать исходные файлы в *.o объектные файлы. Эта коллекция *.o файлы называется $<TARGET_OBJECT:objlib> в два add_library(...) команды, вызывающие соответствующие команды создания библиотек, которые создают общие и статические библиотеки из тот же набор of объектный файл. Если у вас есть много исходных файлов, то компиляция *.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=ВКЛ и ВЫКЛ в другом

Это действительно возможно. Как сказал @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.а и libmylib.so (на Linux) или mylib.Либ и милиб.dll (на Windows).