CMake: la forma correcta de lidiar con bibliotecas estáticas y compartidas

2 minutos de lectura

Consideremos la distribución Debian o Ubuntu donde uno puede instalar algún paquete de biblioteca, digamos libfoobary un correspondiente libfoobar-dev. El primero contiene un objeto de biblioteca compartida. El último generalmente contiene encabezados, variante de biblioteca estática y objetivos exportados cmake (por ejemplo, FoobarTargets.cmake) que permiten cosas de CMake como find_package para trabajar sin problemas. para hacerlo FoobarTargets.cmake tiene que contener ambos objetivos: para la variante estática y para la compartida.

Por otro lado, he leído muchos artículos que afirman que yo (como autor de libfoobar) debería abstenerme de declarar add_library(foobar SHARED ....) y add_library(foobar_static STATIC ...) en CMakeLists.txt a favor de construir e instalar una biblioteca utilizando BUILD_SHARED_LIBS=ON y BUILD_SHARED_LIBS=OFF. Pero este enfoque exportará solo una variante de la biblioteca a FoobarTargets.cmake porque la compilación posterior sobrescribirá la primera.

Entonces, la pregunta es: ¿cómo hacerlo de la manera correcta? Para que el mantenedor del paquete no necesite parchear la biblioteca CMakeLists.txt para exportar correctamente ambas variantes desde un lado. ¿Y para adherirse al sentido de CMake de una manera verdadera, eliminando objetivos duplicados que difieren solo por estático/compartido del otro lado?

Avatar de usuario de Alex Reinking
Alex Reinking

escribí una publicación de blog completa sobre esto. Un ejemplo de trabajo es disponible en GitHub.

La idea básica es que necesitas escribir tu FoobarConfig.cmake archivo de tal manera que cargue uno de FoobarSharedTargets.cmake o FoobarStaticTargets.cmake de una manera controlada por el usuario basada en principios, que también es tolerante con la presencia de uno u otro. Abogo por la siguiente estrategia:

  1. Si el find_package listas de llamadas exactamente uno de static o shared entre los componentes requeridos, luego cargue el conjunto correspondiente de objetivos.
  2. Si la variable Foobar_SHARED_LIBS está definido, luego cargue el conjunto correspondiente de objetivos.
  3. De lo contrario, respete el ajuste de BUILD_SHARED_LIBS para mantener la coherencia con los usuarios de FetchContent.

En todos los casos, sus usuarios enlazarán a Foobar::Foobar.

En última instancia, no puede tener tanto el estático como el compartido importados en el mismo subdirectorio y al mismo tiempo proporcionar una interfaz consistente de árbol de compilación (FetchContent) y árbol de instalación (buscar paquete). Pero esto no es gran cosa ya que normalmente los consumidores solo quieren uno o el otro, y es totalmente ilegal vincular ambos a un solo objetivo.

  • Dios mío, hace solo una hora que escribí la pregunta y la has encontrado con una respuesta tan completa. Empecé a leer tu publicación y siento de antemano que has hecho un gran trabajo. Voy y leo su artículo hasta el final y le escribiré una vez que complete la lectura. Muchas gracias de antemano.

    – Max Dmitrichenko

    12 de febrero a las 16:39

  • Vale, he leído tu publicación. 10/10!

    – Max Dmitrichenko

    13 de febrero a las 9:55

¿Ha sido útil esta solución?