Creé un proyecto con algunas dependencias de bibliotecas anidadas usando el tipo de biblioteca OBJECT . La motivación para esto es evitar problemas de orden de enlace con bibliotecas estáticas.
Tengo una estructura de directorio simple de la siguiente manera:
├── bar │ ├── bar.c │ └── bar.h ├── foo │ ├── foo.c │ └── foo.h ├── main.c └── CMakeLists.txt foo depende de bar , y main depende de foo . Por ejemplo,
bar.c
#include "bar.h" #include <stdio.h> void bar(void) { printf("woot woot\n"); }foo.c
#include "foo.h" #include "bar.h" void foo(void) { bar(); }C Principal
#include "foo.h" int main() { foo(); return 0; }El archivo CMakeLists.txt
cmake_minimum_required(VERSION 3.18) project(myproj) enable_language(C ASM) set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_EXTENSIONS OFF) # build bar add_library(bar OBJECT ${PROJECT_SOURCE_DIR}/bar/bar.c) target_include_directories(bar PUBLIC ${PROJECT_SOURCE_DIR}/bar) # build foo, depends on bar add_library(foo OBJECT ${PROJECT_SOURCE_DIR}/foo/foo.c) target_include_directories(foo PUBLIC ${PROJECT_SOURCE_DIR}/foo) target_link_libraries(foo PUBLIC bar) # build executable, depends on foo add_executable(myexe ${PROJECT_SOURCE_DIR}/main.c) target_link_libraries(myexe PUBLIC foo) Mi expectativa es que myexe herede la dependencia de la bar de foo cuando se vincula a ella. Sin embargo, este no es el caso que parece. Cuando se compila el código, main.o solo se vincula a foo.o y, por lo tanto, hay una referencia indefinida a bar . Sin embargo, si cambio los tipos de biblioteca de OBJECT a STATIC , todo funciona bien. ¿Por qué pasó esto?
Las bibliotecas de objetos no se pueden encadenar de esta manera. Debe vincular directamente (no transitivamente) a una biblioteca de objetos para adquirir sus archivos de objetos. Como dice en la documentación ,
Las bibliotecas de objetos pueden "vincularse" a otras bibliotecas de objetos para obtener los requisitos de uso, pero dado que no tienen un paso de enlace, no se hace nada con sus archivos de objetos. [...] En otras palabras, cuando las bibliotecas de objetos aparecen en la propiedad
INTERFACE_LINK_LIBRARIESde un objetivo, se tratarán como bibliotecas de interfaz, pero cuando aparecen en la propiedadLINK_LIBRARIESde un objetivo, sus archivos de objetos también se incluirán en el enlace.
Sin embargo, estoy de acuerdo en que desafía toda razón.
Sin embargo, puede propagar manualmente los archivos de objeto a través target_link_libraries(INTERFACE) y la expresión del generador $<TARGET_OBJECTS> de la versión 3.21 (hacerlo tenía errores en versiones anteriores, y las fuentes de destino de incluso hackers target_sources se pueden usar en versiones anteriores).
Tenga en cuenta que esto es un truco, ya que hay algunos casos que se romperán. En particular, si un destino de biblioteca se vincula a dicho destino públicamente, los archivos de objeto se propagarán nuevamente . Así que ten cuidado.
Aún así, aquí hay una versión corregida de su compilación de ejemplo:
cmake_minimum_required(VERSION 3.21) project(myproj LANGUAGES C ASM) set(CMAKE_C_STANDARD 11 CACHE STRING "The C standard to use") option(CMAKE_C_STANDARD_REQUIRED "Enforce strict C standard selection" ON) option(CMAKE_C_EXTENSIONS "Allow compiler-specific C extensions" OFF) # build bar add_library(bar OBJECT bar/bar.c) target_include_directories( bar PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/bar>" ) # build foo, depends on bar add_library(foo OBJECT foo/foo.c) target_include_directories( foo PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/foo>" ) target_link_libraries(foo PUBLIC bar "$<TARGET_OBJECTS:bar>") # build executable, depends on foo add_executable(myexe main.c) target_link_libraries(myexe PRIVATE foo)En la línea de comando:
$ cmake -G Ninja -S . -B build ... $ cmake --build build -- -nv [1/4] /usr/bin/cc -I/path/to/bar -std=c11 -MD -MT CMakeFiles/bar.dir/bar/bar.co -MF CMakeFiles/bar.dir/bar/bar.cod -o CMakeFiles/bar.dir/bar/bar.co -c /path/to/bar/bar.c [2/4] /usr/bin/cc -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/foo.dir/foo/foo.co -MF CMakeFiles/foo.dir/foo/foo.cod -o CMakeFiles/foo.dir/foo/foo.co -c /path/to/foo/foo.c [3/4] /usr/bin/cc -I/path/to/foo -I/path/to/bar -std=c11 -MD -MT CMakeFiles/myexe.dir/main.co -MF CMakeFiles/myexe.dir/main.cod -o CMakeFiles/myexe.dir/main.co -c /path/to/main.c [4/4] : && /usr/bin/cc CMakeFiles/foo.dir/foo/foo.co CMakeFiles/myexe.dir/main.co -o myexe CMakeFiles/bar.dir/./bar/bar.co && :