Cómo evitar que CMake compile fuentes duplicados al empaquetar bibliotecas estáticas de C++.
Estoy intentando construir una biblioteca estática libbar con CMake. Libbar debe contener libfoo, es decir, todos los archivos objeto del subdirectorio target libfoo también deberían aparecer en libbar. El árbol de directorios más simple es el siguiente:
bar
├── bar.cpp
├── CMakeLists.txt
└── foo
├── CMakeLists.txt
└── foo.cpp
Aquí está foo /CMakeLists.txt
:
cmake_minimum_required(VERSION 3.14)
project(foo)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_library(foo)
target_sources(foo PUBLIC foo.cpp)
Y aquí está el archivo CMakeLists.txt
superior:
cmake_minimum_required(VERSION 3.14)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
project(bar)
add_library(bar)
add_subdirectory(foo)
target_sources(bar PUBLIC bar.cpp)
target_link_libraries(bar PRIVATE foo)
En bar/ hago lo siguiente:
cmake . -Bbuild
cd build
cmake --build .
Y obtengo:
Escaneando dependencias de la meta foo
[20%] Construyendo objeto CMakeFiles/foo.dir/foo.cpp.o
[40%] Enlazando biblioteca estática CXX libfoo.a
[40%] Construyendo la meta foo
Escaneando dependencias de la meta bar
[60%] Construyendo objeto CMakeFiles/bar.dir/bar.cpp.o
[80%] Construyendo objeto CMakeFiles/bar.dir/foo/foo.cpp.o
[100%] Enlazando biblioteca estática CXX libbar.a
[100%] Construyendo la meta bar
Como se puede ver, el archivo foo.cpp fue compilado dos veces y estoy tratando de deshacerme de este comportamiento. Por cierto, este método me da un resultado correcto:
$ ar t libbar.a
bar.cpp.o
foo.cpp.o
Si cambio PUBLIC a PRIVATE en foo /CMakeLists.txt
, el registro de compilación es el siguiente:
Escaneando dependencias de la meta foo
[25%] Construyendo objeto CMakeFiles/foo.dir/foo.cpp.o
[50%] Enlazando biblioteca estática CXX libfoo.a
[50%] Construyendo la meta foo
Escaneando dependencias de la meta bar
[75%] Construyendo objeto CMakeFiles/bar.dir/bar.cpp.o
[100%] Enlazando biblioteca estática CXX libbar.a
[100%] Construyendo la meta bar
Pero foo.cpp.o
no entra en libbar:
$ ar t libbar.a
bar.cpp.o
¿Cuál es la forma correcta de construir libbar que contiene libfoo sin compilar dos veces?
davy.ai
Para construir libbar que contenga libfoo sin doble compilación, puede modificar los archivos
foo/CMakeLists.txt
yCMakeLists.txt
de la siguiente manera:En
foo/CMakeLists.txt
, cambieadd_library(foo)
aadd_library(foo STATIC foo.cpp)
para especificar quefoo
es una biblioteca estática.En
CMakeLists.txt
, agregue la palabra claveINTERFACE
al comandotarget_link_libraries
, lo que asegurará quelibfoo.a
aparezca en la interfaz de enlace debar
, pero no se vinculará al objetivobar
en sí. Luego, usetarget_link_libraries
para vincular el objetivobar
confoo
.Con estos cambios, cuando ejecute
cmake --build .
en el directoriobuild
,foo.cpp
no se compilará dos veces ylibbar.a
contendrá tantobar.cpp.o
comofoo.cpp.o
.