programacion - Uso de la optimización de tiempo de enlace de GCC con bibliotecas enlazadas estáticas
diferencia entre biblioteca y libreria en programacion (1)
Estoy tratando de usar las optimizaciones de tiempo de enlace con la -flto
de GCC (6.1.1).
Si bien funciona bien con mi código, no se vincula con una biblioteca estática vinculada. También estoy creando y enlazando con mi proyecto (que es Engine y la biblioteca es glsl-optimizer , solo como referencia).
Aquí está la salida:
...
/usr/bin/ranlib: ir_expression_flattening.cpp.o: plugin needed to handle lto object
/usr/bin/ranlib: opt_function_inlining.cpp.o: plugin needed to handle lto object
/usr/bin/ranlib: opt_copy_propagation_elements.cpp.o: plugin needed to handle lto object
...
Y después de eso, por supuesto, recibo varias "referencias indefinidas" a algunas funciones.
Investigué un poco y descubrí que podría deberse a ar
y debería intentar usar gcc-ar
, pero no estoy seguro de cómo podría hacerlo.
Además, estoy usando CMake que no es compatible con lto (excepto en el compilador de Intel en algunas plataformas, así que leo ...). Aunque intenté usar:
set_property(TARGET glsl_optimizer PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
Lo que no funcionó.
También, probé el -fuse-linker-plugin
de GCC -fuse-linker-plugin
que no funcionó.
¿Supongo que tendré que hacerlo manualmente de la manera antigua directamente usando gcc-ar
, o tal vez hay algún otro método?
Aquí hay un proyecto MCVE CMake que reproduce el problema:
$ ls -R hellow
hellow:
CMakeLists.txt hello.c libhello.c
$ cat hellow/CMakeLists.txt
cmake_minimum_required (VERSION 2.6)
project (hellow)
SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -flto")
SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto")
#SET(CMAKE_AR "gcc-ar")
#SET(CMAKE_C_ARCHIVE_CREATE "<CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>")
#SET(CMAKE_C_ARCHIVE_FINISH true)
add_library(hello STATIC libhello.c)
add_executable(hellow hello.c)
target_link_libraries(hellow hello)
add_dependencies(hellow hello)
$ cat hellow/hello.c
extern void hello(void);
int main(void)
{
hello();
return 0;
}
$ cat hellow/libhello.c
#include <stdio.h>
void hello(void)
{
puts("Hello");
}
La configuración es buena:
$ mkdir build_hellow
$ cd build_hellow/
$ cmake ../hellow
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/imk/dev/so/build_hellow
La construcción falla según el problema:
$ make
Scanning dependencies of target hello
[ 25%] Building C object CMakeFiles/hello.dir/libhello.c.o
[ 50%] Linking C static library libhello.a
/usr/bin/ar: CMakeFiles/hello.dir/libhello.c.o: plugin needed to handle lto object
/usr/bin/ranlib: libhello.c.o: plugin needed to handle lto object
[ 50%] Built target hello
Scanning dependencies of target hellow
[ 75%] Building C object CMakeFiles/hellow.dir/hello.c.o
[100%] Linking C executable hellow
/tmp/ccV0lG36.ltrans0.ltrans.o: In function `main'':
<artificial>:(.text+0x5): undefined reference to `hello''
collect2: error: ld returned 1 exit status
CMakeFiles/hellow.dir/build.make:95: recipe for target ''hellow'' failed
make[2]: *** [hellow] Error 1
CMakeFiles/Makefile2:67: recipe for target ''CMakeFiles/hellow.dir/all'' failed
make[1]: *** [CMakeFiles/hellow.dir/all] Error 2
Makefile:83: recipe for target ''all'' failed
make: *** [all] Error 2
Hay más de una solución. Una es descomentar las 3 líneas comentadas en CMakeLists.txt
arriba. Entonces:
$ cmake ../hellow/
-- The C compiler identification is GNU 5.4.0
-- The CXX compiler identification is GNU 5.4.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/imk/dev/so/build_hellow
$ make
Scanning dependencies of target hello
[ 25%] Building C object CMakeFiles/hello.dir/libhello.c.o
[ 50%] Linking C static library libhello.a
[ 50%] Built target hello
Scanning dependencies of target hellow
[ 75%] Building C object CMakeFiles/hellow.dir/hello.c.o
[100%] Linking C executable hellow
[100%] Built target hellow
$ ./hellow
Hello
Esta solución hace uso de los siguientes hechos.
El problema de construcción:
/usr/bin/ar: CMakeFiles/hello.dir/libhello.c.o: plugin needed to handle lto object
...
/usr/bin/ranlib: libhello.c.o: plugin needed to handle lto object
puede resolverse dando a ar
y ranlib
la opción:
--plugin=$(gcc --print-file-name=liblto_plugin.so)
Sin embargo, GNU ranlib
es simplemente un sinónimo de ar -s
, y gcc-ar
es una envoltura para ar
que proporciona ese complemento.
La plantilla de compilación de CMake para una biblioteca estática de C es:
CMAKE_C_ARCHIVE_CREATE ( = <CMAKE_AR> qc <TARGET> <LINK_FLAGS> <OBJECTS>)
CMAKE_C_ARCHIVE_FINISH ( = <CMAKE_RANLIB> <TARGET>)
que para GNU ar
es equivalente a:
CMAKE_C_ARCHIVE_CREATE ( = <CMAKE_AR> qcs <TARGET> <LINK_FLAGS> <OBJECTS>)
CMAKE_C_ARCHIVE_FINISH ( = true) # Or any other no-op command
Así que con estas configuraciones más:
SET(CMAKE_AR "gcc-ar")
estamos bien.
Para un proyecto de C ++, por supuesto, establece CMAKE_CXX_ARCHIVE_CREATE
y CMAKE_CXX_ARCHIVE_FINISH