es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

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?

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Para construir libbar que contenga libfoo sin doble compilación, puede modificar los archivos foo/CMakeLists.txt y CMakeLists.txt de la siguiente manera:

    En foo/CMakeLists.txt, cambie add_library(foo) a add_library(foo STATIC foo.cpp) para especificar que foo es una biblioteca estática.

    cmake_minimum_required(VERSION 3.14)
    project(foo)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    add_library(foo STATIC foo.cpp)
    

    En CMakeLists.txt, agregue la palabra clave INTERFACE al comando target_link_libraries, lo que asegurará que libfoo.a aparezca en la interfaz de enlace de bar, pero no se vinculará al objetivo bar en sí. Luego, use target_link_libraries para vincular el objetivo bar con foo.

    cmake_minimum_required(VERSION 3.14)
    
    set(CMAKE_CXX_STANDARD 11)
    set(CMAKE_CXX_STANDARD_REQUIRED ON)
    
    project(bar)
    
    add_subdirectory(foo)
    
    add_library(bar STATIC bar.cpp)
    
    target_link_libraries(bar INTERFACE foo)
    

    Con estos cambios, cuando ejecute cmake --build . en el directorio build, foo.cpp no se compilará dos veces y libbar.a contendrá tanto bar.cpp.o como foo.cpp.o.

    Scanning dependencies of target foo
    [ 20%] Building CXX object foo/CMakeFiles/foo.dir/foo.cpp.o
    [ 40%] Linking CXX static library libfoo.a
    [ 40%] Built target foo
    Scanning dependencies of target bar
    [ 60%] Building CXX object CMakeFiles/bar.dir/bar.cpp.o
    [ 80%] Building CXX object CMakeFiles/bar.dir/foo.cpp.o
    [100%] Linking CXX static library libbar.a
    [100%] Built target bar
    $ ar t libbar.a 
    bar.cpp.o
    foo.cpp.o
    

Comments are closed.