La misma fuente, todo eso, solo quiere una versión estática y compartida. ¿Fácil de hacer?
Sí, es moderadamente fácil. Simplemente use dos comandos "add_library":
add_library(MyLib SHARED source1.c source2.c)
add_library(MyLibStatic STATIC source1.c source2.c)
Incluso si tiene muchos archivos fuente, colocaría la lista de fuentes en una variable cmake, por lo que aún es fácil de hacer.
En Windows, probablemente debería darle a cada biblioteca un nombre diferente, ya que hay un archivo ".lib" para compartir y estático. Pero en Linux y Mac, incluso puede dar a ambas bibliotecas el mismo nombre (por ejemplo, libMyLib.a
y libMyLib.so
):
set_target_properties(MyLibStatic PROPERTIES OUTPUT_NAME MyLib)
Pero no recomiendo dar el mismo nombre a las versiones estáticas y dinámicas de la biblioteca. Prefiero usar nombres diferentes porque eso hace que sea más fácil elegir el enlace estático frente al dinámico en la línea de compilación para las herramientas que enlazan con la biblioteca. Por lo general, elijo nombres como libMyLib.so
(compartido) y libMyLib_static.a
(estático). (Esos serían los nombres en Linux).
-fPIC
), que agrega una pequeña cantidad de tiempo de ejecución cuando se usan esas bibliotecas estáticas. Entonces, para obtener el máximo rendimiento, esta respuesta sigue siendo la mejor.Desde CMake versión 2.8.8, puede usar "bibliotecas de objetos" para evitar la compilación duplicada de los archivos de objetos . Usando el ejemplo de Christopher Bruns de una biblioteca con dos archivos fuente:
De los documentos de CMake :
En pocas palabras, el
add_library(objlib OBJECT ${libsrc})
comando indica a CMake que compile los archivos de origen en archivos de*.o
objetos. A*.o
continuación, se hace referencia a esta colección de archivos como$<TARGET_OBJECT:objlib>
en los dosadd_library(...)
comandos que invocan los comandos de creación de bibliotecas apropiados que crean las bibliotecas compartidas y estáticas a partir del mismo conjunto de archivos de objetos. Si tiene muchos archivos fuente, compilarlos*.o
puede llevar bastante tiempo; con bibliotecas de objetos las compilas solo una vez.El precio que paga es que los archivos de objeto deben construirse como código independiente de la posición porque las bibliotecas compartidas necesitan esto (a las bibliotecas estáticas no les importa). Tenga en cuenta que el código independiente de la posición puede ser menos eficiente, por lo que si busca un rendimiento máximo, optará por bibliotecas estáticas. Además, es más fácil distribuir ejecutables vinculados estáticamente.
fuente
target_link_libraries()
llamadas posteriores que dependen de su biblioteca no pueden usar la "biblioteca de objetos" para enlazar; deben dirigirse a las nuevas bibliotecas compartidas o estáticas (y pueden estar duplicadas). Pero, contrariamente a la experiencia de los primeros comentaristas, esto fue bastante útil y me permitió eliminar todos los objetivos duplicados y cortar todos misCMakeLists.txt
archivos a la mitad.set_property
solo funcionaba cuando lo usabaobjlib
y no cuando lo usaba${objlib}
. Entonces, ¿tal vez esta respuesta podría corregirse?Generalmente no hay necesidad de duplicar
ADD_LIBRARY
llamadas para su propósito. Solo haz uso demientras construye, primero (en un directorio fuera de la fuente) con
-DBUILD_SHARED_LIBS:BOOL=ON
, y conOFF
en el otro.fuente
Es posible empacar todo en el mismo aliento de compilación, como se sugirió en las respuestas anteriores, pero recomendaría no hacerlo, porque al final es un truco que funciona solo para proyectos simples. Por ejemplo, es posible que en algún momento necesite diferentes indicadores para diferentes versiones de la biblioteca (especialmente en Windows, donde los indicadores generalmente se usan para cambiar entre exportar símbolos o no). O como se mencionó anteriormente, es posible que desee colocar
.lib
archivos en diferentes directorios dependiendo de si corresponden a bibliotecas estáticas o compartidas. Cada uno de esos obstáculos requerirá un nuevo truco.Puede ser obvio, pero una alternativa que no se ha mencionado anteriormente es hacer que el tipo de biblioteca sea un parámetro:
Tener versiones compartidas y estáticas de la biblioteca en dos árboles binarios diferentes facilita el manejo de diferentes opciones de compilación. No veo ningún inconveniente serio en mantener distintos árboles de compilación, especialmente si sus compilaciones están automatizadas.
Tenga en cuenta que incluso si tiene la intención de mutualizar compilaciones utilizando una
OBJECT
biblioteca intermedia (con las advertencias mencionadas anteriormente, por lo que necesita una razón convincente para hacerlo), aún podría tener bibliotecas finales en dos proyectos diferentes.fuente
De hecho es posible. Como @Christopher Bruns dijo en su respuesta, debe agregar dos versiones de la biblioteca:
Luego, como se describe aquí , debe especificar que ambos objetivos deben usar el mismo nombre de salida y no sobrescribir los archivos del otro:
De esta manera, obtendrá libmylib.a y libmylib.so (en Linux) o mylib.lib y mylib.dll (en Windows).
fuente