Pautas de Empaquetado de C y C++
Introducción
El lenguaje C y C++ y tiempo de ejecución son uno de los más comunes de los marcos de trabajo de desarrollo para paquetes en Fedora. Tales como hay una variedad amplia de estilo de calidad, y convención en todos los paquetes. El siguiente documento proporciona la mejor práctica para ciertos aspectos de empaquetado de C y C++.
Empaquetado
BuildRequires y Requires
Si su aplicación es C o C++, debe incluir BuildRequires en gcc, gcc-c++ o clang. Estos paquetes incluirán todo lo necesario para compilar una aplicación C o C++ conforme a los estándares.
Si su biblioteca incluye encabezados C estándar o C++, debe enumerar BuildRequires junto a gcc, gcc-c++ o clang para instalar los encabezados necesarios que cumplan con los estándares.
Si en tiempo de ejecución se usa cpp para procesar encabezados de lenguaje C o C++, no queda más remedio que usar Requires para gcc, gcc-c++ o clang para instalar los encabezados necesarios para una aplicación C o C++ que cumpla con el estándar. En el futuro, esto cambiaría si un proveedor específico proporciona un conjunto de encabezados de lenguaje C o C++ estándar, por ejemplo, c-headers o c++-headers.
No es necesario incluir BuildRequires ni Requires en glibc-headers ni en ningún otro paquete de implementación principal de C o C++, a menos que tenga una necesidad específica. Por ejemplo, la compilación estática requiere los paquetes de biblioteca .*-static, como BuildRequires: glibc-static. El caso de uso predeterminado de una aplicación de C o C++ compilada dinámicamente lo gestionan los paquetes gcc, gcc-c++ y clang.
Refiérase a Pautas del compilador para obtener la lista de compiladores compatibles con C y compiladores de C++.
PyR de empaquetado
-
¿Necesito un
Requires: glibcpara asegurar que tengo el runtime de C instalado para mi aplicación?No. RPM determinará automáticamente cuales bibliotecas ELF necesita basándose en los binarios en su paquete. Esto es suficiente para causar que glibc sea instalado.
-
¿Necesito incluir un
Requires: libgcc?Si usa una API directamente de
libgcc, sí, debe tenerRequires: libgcc. Sin embargo,glibcgeneralmente requierelibgcc, por lo que siempre está instalado.
Bibliotecas
Las bibliotecas deben tener nombres de objeto compartidos únicos (SONAME mediante -Wl,-soname=libfoo.so) que no entren en conflicto con otros SONAME de bibliotecas utilizados en la distribución. Por ejemplo, solo debe haber un libfoo.so en la distribución. La excepción se da cuando existen múltiples implementaciones de la misma biblioteca libfoo.so proporcionadas por diferentes autores y cada una entra en conflicto con la otra. En este caso, ambas libfoo.so deben proporcionar exactamente la misma interfaz, pero con una implementación diferente. Tener dos libfoo.so, cada una con una API diferente, es una mala práctica y dificulta el empaquetado y la distribución de esos paquetes.
Símbolos Versionados
Sin símbolos versionados, RPM generará una expresión de dependencia que nombre la biblioteca, pero sin una versión, estableciendo "$Major.0.0" como la versión mínima. Los símbolos versionados proporcionan la información requerida para garantizar que las bibliotecas sean lo suficientemente nuevas como para ejecutar el software que las enlaza.
Examine las capacidades que ofrece el rpm binario: rpm -qp --provides <paquete>. Un paquete con bibliotecas compartidas la listará como libc.so.6()(64bit) y, si la biblioteca proporciona símbolos versionados, también la listará como libm.so.6(GLIBC_2.41)(64bit).
Se recomienda a los mantenedores de paquetes que trabajen con proyectos anteriores para agregar símbolos versionados a las bibliotecas que aún no los incluyen.
Añadir versiones de símbolos es sencillo para la mayoría de las bibliotecas; inicialmente solo requiere un mapa de símbolos y un argumento adicional para el enlazador durante el proceso de compilación.
generate_initial_map.sh:
#!/bin/sh
echo "# Evite modificar un conjunto de símbolos después de su publicación"
echo "# Al agregar funciones en una nueva versión, agregue un nuevo conjunto"
echo "# La retirada de funciones es un cambio radical"
echo "$2 {"
echo " global:"
objdump -T $1 | \
grep -F .text | \
awk '{print $7;}' | \
c++filt | \
awk '/[() ]/ {print " \"" $0 "\";";} \
!/[() ]/ {print " " $0 ";";}' | \
sort
echo "}"
Ejecutar generate_initial_map.sh /ruta/para/library.so.1 <BIBLIOTECA>_<VERSIÓN> para generar un archivo de mapeo.
Añadir script-versión para Automate
El manual de la Biblioteca de Portabilidad de GNU incluye ejemplos de utilizar version-script en automake. En Makefile.am:
=== Añadir un version-script a CMake
La licencia BSD-3-Clause link:https://github.com/protocolbuffers/protobuf[proyecto protobuf] incluye ejemplos de uso de version-script en CMake.
En CMakeLists.txt, compruebe el enlazador para que admita:
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map "{ global: main; local: *; };") # Módulo CheckLinkerFlag disponible en CMake >=3.18. if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.18) include(CheckLinkerFlag) check_linker_flag(CXX -Wl,--version-script=${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map project_HAVE_LD_VERSION_SCRIPT) endif() file(REMOVE ${CMAKE_CURRENT_BINARY_DIR}/cmaketest.map)
Y, donde está definida la biblioteca:
if(project_HAVE_LD_VERSION_SCRIPT) target_link_options(libfoo PRIVATE -Wl,--version-script=${protobuf_source_dir}/src/libfoo.map) set_target_properties(libfoo PROPERTIES LINK_DEPENDS ${project_source_dir}/src/libfoo.map) endif()
=== Añadir script de versión a Meson
El enlace link:https://github.com/mesonbuild/meson/blob/master/test%20cases/linuxlike/3%20linker%20script/meson.build[prueba casos] de Meson incluye ejemplos de uso con version-script.
En Solaris 11.4 ld admite --version-script solo cuando además especificas
-z gnu-version-script-compat
if meson.get_compiler('c').get_linker_id() == 'ld.solaris' add_project_link_arguments('-Wl,-z,gnu-version-script-compat', language: 'C') endif
Archivo map estático mapfile = 'bob.map' vflag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), mapfile)
l = shared_library('bob', 'bob.c', link_args : vflag, link_depends : mapfile) `
Want to help? Learn how to contribute to Fedora Docs ›