Colección de compiladores GNU

format_list_bulleted Contenido keyboard_arrow_down
ImprimirCitar

GNU Compiler Collection (GCC) es un compilador de optimización producido por el Proyecto GNU que admite varios lenguajes de programación, arquitecturas de hardware y sistemas operativos. La Free Software Foundation (FSF) distribuye GCC como software libre bajo la Licencia Pública General GNU (GNU GPL). GCC es un componente clave de la cadena de herramientas de GNU y el compilador estándar para la mayoría de los proyectos relacionados con GNU y el kernel de Linux. Con aproximadamente 15 millones de líneas de código en 2019, GCC es uno de los programas gratuitos más grandes que existen. Ha jugado un papel importante en el crecimiento del software libre, como herramienta y como ejemplo.

Cuando fue lanzado por primera vez en 1987 por Richard Stallman, GCC 1.0 fue nombrado Compilador GNU C ya que solo manejaba el lenguaje de programación C. Se amplió para compilar C++ en diciembre de ese año. Posteriormente se desarrollaron interfaces para Objective-C, Objective-C++, Fortran, Ada, D y Go, entre otros. Las especificaciones OpenMP y OpenACC también son compatibles con los compiladores C y C++.

GCC ha sido portado a más plataformas y arquitecturas de conjuntos de instrucciones que cualquier otro compilador, y se implementa ampliamente como herramienta en el desarrollo de software libre y propietario. GCC también está disponible para muchos sistemas integrados, incluidos los chips basados ​​en ARM y Power ISA.

Además de ser el compilador oficial del sistema operativo GNU, GCC ha sido adoptado como el compilador estándar por muchos otros sistemas operativos informáticos modernos similares a Unix, incluida la mayoría de las distribuciones de Linux. La mayoría de los sistemas operativos de la familia BSD también cambiaron a GCC poco después de su lanzamiento, aunque desde entonces, FreeBSD, OpenBSD y Apple macOS se han pasado al compilador Clang, en gran parte debido a razones de licencia. GCC también puede compilar código para Windows, Android, iOS, Solaris, HP-UX, AIX y DOS.

Historia

A fines de 1983, en un esfuerzo por arrancar el sistema operativo GNU, Richard Stallman le pidió permiso a Andrew S. Tanenbaum, el autor del Amsterdam Compiler Kit (también conocido como Free University Compiler Kit) para usar ese software para GNU. Cuando Tanenbaum le informó que el compilador no era gratuito y que solo la universidad era gratuita, Stallman decidió trabajar en un compilador diferente. Su plan inicial era reescribir un compilador existente del Laboratorio Nacional Lawrence Livermore de Pastel a C con la ayuda de Len Tower y otros.Stallman escribió una nueva interfaz C para el compilador Livermore, pero luego se dio cuenta de que requería megabytes de espacio de pila, algo imposible en un sistema Unix 68000 con solo 64 KB, y concluyó que tendría que escribir un nuevo compilador desde cero. Ninguno de los códigos del compilador de Pastel terminó en GCC, aunque Stallman usó la interfaz C que había escrito.

GCC se lanzó por primera vez el 22 de marzo de 1987, disponible por FTP del MIT. Stallman fue incluido como el autor, pero citó a otros por sus contribuciones, incluido Tower por "partes del analizador, generador de RTL, definiciones de RTL y de la descripción de la máquina Vax", Jack Davidson y Christopher W. Fraser por la idea de usar RTL como un lenguaje intermedio, y Paul Rubin por escribir la mayor parte del preprocesador. Descrito como el "primer éxito del software libre" por Peter H. Salus, el compilador GNU llegó justo en el momento en que Sun Microsystems estaba desagregando sus herramientas de desarrollo de su sistema operativo, vendiéndolas por separado a un precio combinado más alto que el paquete anterior, que llevó a muchos de los usuarios de Sun a comprar o descargar GCC en lugar de las herramientas del proveedor.Si bien Stallman consideraba a GNU Emacs como su proyecto principal, en 1990, GCC admitía trece arquitecturas informáticas, superaba a varios compiladores de proveedores y varias empresas lo utilizaban comercialmente.

Horquilla EGCS

Como GCC tenía la licencia GPL, los programadores que querían trabajar en otras direcciones, en particular aquellos que escribían interfaces para lenguajes que no fueran C, tenían la libertad de desarrollar su propia bifurcación del compilador, siempre que cumplieran con los términos de la GPL, incluidos los requisitos para distribuir el código fuente. código. Sin embargo, las bifurcaciones múltiples demostraron ser ineficientes y difíciles de manejar, y la dificultad para que el proyecto oficial de GCC aceptara el trabajo fue muy frustrante para muchos, ya que el proyecto favorecía la estabilidad sobre las nuevas características. La FSF mantuvo un control tan estricto sobre lo que se agregó a la versión oficial de GCC 2.x (desarrollada desde 1992) que GCC se utilizó como un ejemplo del modelo de desarrollo de "catedral" en el ensayo de Eric S. Raymond The Cathedral and the Bazaar.

En 1997, un grupo de desarrolladores formó el Sistema de compilación GNU experimental/mejorado (EGCS) para fusionar varias bifurcaciones experimentales en un solo proyecto. La base de la fusión fue una instantánea de desarrollo de GCC (tomada alrededor de la versión 2.7.2 y luego seguida hasta la versión 2.8.1). Las fusiones incluyeron g77 (Fortran), PGCC (GCC optimizado para Pentium P5), muchas mejoras de C++ y muchas nuevas arquitecturas y variantes del sistema operativo.

Si bien ambos proyectos siguieron de cerca los cambios del otro, el desarrollo de EGCS demostró ser considerablemente más vigoroso, tanto que la FSF detuvo oficialmente el desarrollo de su compilador GCC 2.x, bendijo a EGCS como la versión oficial de GCC y designó al proyecto EGCS como GCC. mantenedores en abril de 1999. Con el lanzamiento de GCC 2.95 en julio de 1999, los dos proyectos se unieron una vez más. Desde entonces, GCC ha sido mantenido por un variado grupo de programadores de todo el mundo bajo la dirección de un comité directivo.

GCC 3 (2002) eliminó una interfaz para CHILL debido a la falta de mantenimiento.

Antes de la versión 4.0, el front-end de Fortran era g77, que solo admitía FORTRAN 77, pero luego se abandonó a favor del nuevo GNU Fortran front-end que también admite Fortran 95 y gran parte de Fortran 2003 y Fortran 2008.

A partir de la versión 4.8, GCC se implementa en C++.

El soporte para Cilk Plus existió desde GCC 5 hasta GCC 7.

GCC ha sido portado a una amplia variedad de arquitecturas de conjuntos de instrucciones y se implementa ampliamente como una herramienta en el desarrollo de software libre y propietario. GCC también está disponible para muchos sistemas integrados, incluidos Symbian (llamado gcce), chips basados ​​en ARM y basados ​​en Power ISA. El compilador puede apuntar a una amplia variedad de plataformas, incluidas consolas de videojuegos como PlayStation 2, Cell SPE de PlayStation 3 y Dreamcast. Ha sido portado a más tipos de procesadores y sistemas operativos que cualquier otro compilador.

Idiomas admitidos

A partir de mayo de 2021, la reciente versión 11.1 de GCC incluye interfaces para los lenguajes de programación C (gcc), C++ (g++), Objective-C, Fortran (gfortran), Ada (GNAT), Go (gccgo) y D (gdc, desde 9.1), con las extensiones de lenguaje paralelo OpenMP y OpenACC son compatibles desde GCC 5.1. Las versiones anteriores a GCC 7 también admitían Java (gcj), lo que permitía la compilación de Java en código de máquina nativo.

Con respecto a la compatibilidad con la versión de lenguaje para C++ y C, desde GCC 11.1, el objetivo predeterminado es gnu++17, un superconjunto de C++17, y gnu11, un superconjunto de C11, con soporte estándar estricto también disponible. GCC también proporciona soporte experimental para C++20 y el próximo C++23.

Existen interfaces de terceros para muchos lenguajes, como Pascal (gpc), Modula-2, Modula-3 y VHDL (GHDL). Existen algunas ramas experimentales para admitir lenguajes adicionales, como el compilador GCC UPC para Unified Parallel C o Rust.

Diseño

La interfaz externa de GCC sigue las convenciones de Unix. Los usuarios invocan un programa de controlador específico del idioma (gccpara C, g++para C++, etc.), que interpreta los argumentos del comando, llama al compilador real, ejecuta el ensamblador en la salida y luego, opcionalmente, ejecuta el enlazador para producir un binario ejecutable completo.

Cada uno de los compiladores de lenguaje es un programa separado que lee el código fuente y genera código de máquina. Todos tienen una estructura interna común. Una interfaz por idioma analiza el código fuente en ese idioma y produce un árbol de sintaxis abstracta ("árbol" para abreviar).

Estos se convierten, si es necesario, a la representación de entrada del extremo medio, denominada forma GENÉRICA; el extremo medio luego transforma gradualmente el programa hacia su forma final. Las optimizaciones del compilador y las técnicas de análisis de código estático (como FORTIFY_SOURCE, una directiva del compilador que intenta descubrir algunos desbordamientos de búfer) se aplican al código. Estos funcionan en múltiples representaciones, principalmente la representación GIMPLE independiente de la arquitectura y la representación RTL dependiente de la arquitectura. Finalmente, el código de máquina se produce utilizando la coincidencia de patrones específica de la arquitectura basada originalmente en un algoritmo de Jack Davidson y Chris Fraser.

GCC se escribió principalmente en C, excepto por partes de la interfaz de Ada. La distribución incluye las bibliotecas estándar para Ada y C++ cuyo código está mayoritariamente escrito en esos lenguajes. En algunas plataformas, la distribución también incluye una biblioteca de tiempo de ejecución de bajo nivel, libgcc, escrita en una combinación de C independiente de la máquina y código de máquina específico del procesador, diseñada principalmente para manejar operaciones aritméticas que el procesador de destino no puede realizar directamente.

GCC usa muchas herramientas adicionales en su compilación, muchas de las cuales están instaladas de forma predeterminada en muchas distribuciones de Unix y Linux (pero que, normalmente, no están presentes en las instalaciones de Windows), incluidas Perl, Flex, Bison y otras herramientas comunes. Además, actualmente requiere la presencia de tres bibliotecas adicionales para construir: GMP, MPC y MPFR.

En mayo de 2010, el comité directivo de GCC decidió permitir el uso de un compilador de C++ para compilar GCC. El compilador estaba destinado a escribirse principalmente en C más un subconjunto de características de C++. En particular, esto se decidió para que los desarrolladores de GCC pudieran usar las características destructoras y genéricas de C++.

En agosto de 2012, el comité directivo de GCC anunció que GCC ahora usa C++ como lenguaje de implementación. Esto significa que para compilar GCC a partir de fuentes, se requiere un compilador de C++ que comprenda el estándar ISO/IEC C++03.

El 18 de mayo de 2020, GCC pasó del estándar ISO/IEC C++03 al estándar ISO/IEC C++11 (es decir, necesario para compilar, arrancar, el compilador mismo; sin embargo, de forma predeterminada, compila versiones posteriores de C++).

Frente termina

Cada front-end usa un analizador para producir el árbol de sintaxis abstracta de un archivo fuente determinado. Debido a la abstracción del árbol de sintaxis, los archivos de origen de cualquiera de los diferentes idiomas admitidos pueden ser procesados ​​por el mismo back-end. GCC comenzó usando analizadores LALR generados con Bison, pero gradualmente cambió a analizadores de descenso recursivo escritos a mano para C ++ en 2004, y para C y Objective-C en 2006. A partir de 2021, todas las interfaces utilizan analizadores de descenso recursivo escritos a mano..

Hasta GCC 4.0, la representación en árbol del programa no era totalmente independiente del procesador al que se apunta. El significado de un árbol era algo diferente para los front-end de diferentes idiomas, y los front-end podían proporcionar sus propios códigos de árbol. Esto se simplificó con la introducción de GENERIC y GIMPLE, dos nuevas formas de árboles independientes del idioma que se introdujeron con la llegada de GCC 4.0. GENERIC es más complejo, basado en la representación intermedia de GCC 3.x Java front-end. GIMPLE es un GENERICO simplificado, en el que varias construcciones se reducen a múltiples instrucciones GIMPLE. Los front-end de C, C++ y Java producen GENERIC directamente en el front-end. En cambio, otros front-end tienen diferentes representaciones intermedias después del análisis y las convierten en GENERIC.

En cualquier caso, el llamado "gimplificador" convierte esta forma más compleja en la forma GIMPLE más simple basada en SSA que es el lenguaje común para una gran cantidad de potentes optimizaciones globales (alcance de la función) independientes del lenguaje y la arquitectura.

GENÉRICO y GIMPLE

GENERIC es un lenguaje de representación intermedio que se utiliza como "extremo medio" al compilar el código fuente en archivos binarios ejecutables. Un subconjunto, llamado GIMPLE, es el objetivo de todos los front-ends de GCC.

La etapa intermedia de GCC realiza todo el análisis y la optimización del código, trabajando independientemente del lenguaje compilado y la arquitectura de destino, comenzando desde la representación GENÉRICA y expandiéndola al lenguaje de transferencia de registros (RTL). La representación GENÉRICA contiene solo el subconjunto de las construcciones de programación imperativa optimizadas por el extremo medio.

Al transformar el código fuente a GIMPLE, las expresiones complejas se dividen en un código de tres direcciones utilizando variables temporales. Esta representación se inspiró en la representación SIMPLE propuesta en el compilador McCAT por Laurie J. Hendren para simplificar el análisis y optimización de programas imperativos.

Mejoramiento

La optimización puede ocurrir durante cualquier fase de la compilación; sin embargo, la mayor parte de las optimizaciones se realizan después del análisis sintáctico y semántico del front-end y antes de la generación de código del back-end; por lo tanto, un nombre común, aunque algo contradictorio, para esta parte del compilador es el "extremo medio".

El conjunto exacto de optimizaciones de GCC varía de una versión a otra a medida que se desarrolla, pero incluye los algoritmos estándar, como la optimización de bucles, subprocesos de salto, eliminación de subexpresiones comunes, programación de instrucciones, etc. Las optimizaciones RTL tienen menos importancia con la adición de optimizaciones globales basadas en SSA en árboles GIMPLE, ya que las optimizaciones RTL tienen un alcance mucho más limitado y tienen menos información de alto nivel.

Algunas de estas optimizaciones realizadas en este nivel incluyen la eliminación de código inactivo, la eliminación de redundancia parcial, la numeración de valores globales, la propagación constante condicional dispersa y el reemplazo escalar de agregados. También se realizan optimizaciones basadas en la dependencia de matrices, como la vectorización automática y la paralelización automática. La optimización guiada por perfiles también es posible.

Back-end

El back-end de GCC está parcialmente especificado por macros de preprocesador y funciones específicas de una arquitectura de destino, por ejemplo, para definir su endianidad, tamaño de palabra y convenciones de llamada. La parte frontal del back-end los usa para ayudar a decidir la generación de RTL, por lo que aunque el RTL de GCC es nominalmente independiente del procesador, la secuencia inicial de instrucciones abstractas ya está adaptada al objetivo. En cualquier momento, las instrucciones RTL reales que forman la representación del programa deben cumplir con la descripción de la máquina de la arquitectura de destino.

El archivo de descripción de la máquina contiene patrones RTL, junto con restricciones de operandos y fragmentos de código para generar el ensamblaje final. Las restricciones indican que un patrón RTL particular podría aplicarse solo (por ejemplo) a ciertos registros de hardware, o (por ejemplo) permitir desplazamientos de operandos inmediatos de solo un tamaño limitado (por ejemplo, 12, 16, 24,... desplazamientos de bits, etc.). Durante la generación de RTL, se verifican las restricciones para la arquitectura de destino dada. Para emitir un fragmento determinado de RTL, debe coincidir con uno (o más) de los patrones RTL en el archivo de descripción de la máquina y satisfacer las restricciones de ese patrón; de lo contrario, sería imposible convertir el RTL final en código de máquina.

Hacia el final de la compilación, el RTL válido se reduce a una forma estricta en la que cada instrucción se refiere a registros reales de la máquina y un patrón del archivo de descripción de la máquina de destino. Formar RTL estricto es una tarea complicada; un paso importante es la asignación de registros, donde se eligen registros de hardware reales para reemplazar los pseudo-registros asignados inicialmente. A esto le sigue una fase de "recarga"; todos los pseudo-registros a los que no se les asignó un registro de hardware real se 'vierten' en la pila, y se genera RTL para realizar este vertido. Del mismo modo, los desplazamientos que son demasiado grandes para caber en una instrucción real deben dividirse y reemplazarse por secuencias RTL que obedezcan las restricciones de desplazamiento.

En la fase final, el código de la máquina se construye llamando a un pequeño fragmento de código, asociado con cada patrón, para generar las instrucciones reales del conjunto de instrucciones del objetivo, utilizando los registros finales, las compensaciones y las direcciones elegidas durante la fase de recarga. El fragmento de código de generación de ensamblado puede ser solo una cadena, en cuyo caso se realiza una sustitución de cadena simple de los registros, compensaciones y/o direcciones en la cadena. El fragmento de código de generación de ensamblaje también puede ser un bloque corto de código C, que realiza un trabajo adicional, pero finalmente devuelve una cadena que contiene el código de ensamblaje válido.

Biblioteca estándar de C++ (libstdc++)

El proyecto GCC incluye una implementación de la biblioteca estándar de C++ llamada libstdc++, con licencia GPLv3 con la excepción de vincular la aplicación de código cerrado cuando las fuentes se construyen con GCC. La versión actual es la 11.

Otras características

Algunas características de GCC incluyen:Optimización del tiempo de enlaceLa optimización del tiempo de enlace se optimiza a través de los límites del archivo de objeto para mejorar directamente el binario enlazado. La optimización del tiempo de enlace se basa en un archivo intermedio que contiene la serialización de alguna representación de Gimple incluida en el archivo del objeto. El archivo se genera junto con el archivo de objeto durante la compilación fuente. Cada compilación fuente genera un archivo de objeto independiente y un archivo auxiliar de tiempo de enlace. Cuando los archivos de objeto están vinculados, el compilador se ejecuta nuevamente y usa los archivos auxiliares para optimizar el código en los archivos de objeto compilados por separado.ComplementosLos complementos amplían el compilador GCC directamente. Los complementos permiten que un compilador estándar se adapte a necesidades específicas mediante un código externo cargado como complementos. Por ejemplo, los complementos pueden agregar, reemplazar o incluso eliminar pases intermedios que operan en representaciones de Gimple. Ya se han publicado varios complementos de GCC, en particular:

  • El complemento de Python, que se vincula con libpython, y permite invocar scripts de Python arbitrarios desde el interior del compilador. El objetivo es permitir que los complementos de GCC se escriban en Python.
  • El complemento MELT proporciona un lenguaje similar a Lisp de alto nivel para extender GCC.

El soporte de complementos fue una vez un tema polémico en 2007.Memoria transaccional de C++El lenguaje C++ tiene una propuesta activa para la memoria transaccional. Se puede habilitar en GCC 6 y versiones posteriores al compilar con -fgnu-tm.Identificadores UnicodeAunque el lenguaje C++ requiere soporte para caracteres Unicode que no sean ASCII en los identificadores, la función solo se admite desde GCC 10. Al igual que con el manejo existente de literales de cadena, se supone que el archivo fuente está codificado en UTF-8. La función es opcional en C, pero también está disponible desde este cambio.extensiones CGNU C amplía el lenguaje de programación C con varias características no estándar, incluidas funciones y typeofexpresiones anidadas.

Arquitecturas

Las familias de procesadores de destino de GCC a partir de la versión 11.1 incluyen:

  • AArco64
  • Alfa
  • BRAZO
  • AVR
  • aleta negra
  • eBPF
  • Epifanía (CCG 4.8)
  • H8/300
  • HC12
  • IA-32 (x86)
  • IA-64 (Intel Itanium)
  • MIPS
  • motorola 68000
  • MSP430
  • GPU Nvidia
  • Nvidia PTX
  • PA-RISC
  • PDP-11
  • PowerPC
  • R8C/M16C/M32C
  • RISC-V
  • SPARC
  • Súper H
  • Sistema/390/serie z
  • VAX
  • x86-64

Los procesadores de destino menos conocidos admitidos en la versión estándar incluyen:

  • 68HC11
  • A29K
  • C6x
  • CR16
  • D30V
  • DSP16xx
  • ETRAX CRIS
  • FR-30
  • FR-V
  • IBM ROMP
  • Intel i960
  • IP2000
  • M32R
  • MCORE
  • MIL-STD-1750A
  • MMIX
  • MN10200
  • MN10300
  • motorola 88000
  • NS32K
  • RL78
  • tormentoso16
  • V850
  • xtensa

Procesadores adicionales han sido compatibles con versiones de GCC mantenidas por separado de la versión de FSF:

  • Cortus APS3
  • ARCO
  • AVR32
  • C166 y C167
  • D10V
  • EISC
  • eSi-RISC
  • Hexágono
  • LatticeMico32
  • LatticeMico8
  • MeP
  • microblaze
  • motorola 6809
  • MRISC32
  • MSP430
  • Arquitectura NEC SX
  • Nios II y Nios
  • OpenRISC
  • PDP-10
  • PIC24/dsPIC
  • PIC32
  • Hélice
  • Saturno (HP48XGCC)
  • Sistema/370
  • TIGCC (variante m68k)
  • TMS9900
  • tricore
  • Z8000
  • ZPU

El compilador de Java GCJ puede apuntar a una arquitectura de lenguaje de máquina nativo o al código de bytes de Java de la máquina virtual de Java. Al redirigir GCC a una nueva plataforma, a menudo se usa el arranque. Motorola 68000, Zilog Z80 y otros procesadores también se incluyen en las versiones de GCC desarrolladas para varias calculadoras gráficas programables de Texas Instruments, Hewlett Packard, Sharp y Casio.

Licencia

GCC tiene la licencia GNU General Public License versión 3. La excepción de tiempo de ejecución de GCC permite la compilación de programas propietarios (además del software libre) con GCC. Esto no afecta los términos de la licencia del código fuente de GCC.

Contenido relacionado

Microsoft Excel

Microsoft Excel es una hoja de cálculo desarrollada por Microsoft para Windows, macOS, Android e iOS. Cuenta con capacidades de cálculo o computación...

Criptografía

La criptografía, o criptología es la práctica y el estudio de técnicas para comunicación segura en presencia de un comportamiento antagónico. De manera...

Clang

Clang es una interfaz de compilación para los lenguajes de programación C, C++, Objective-C y Objective-C++, así como para los marcos OpenMP, OpenCL...
Más resultados...
Tamaño del texto:
undoredo
format_boldformat_italicformat_underlinedstrikethrough_ssuperscriptsubscriptlink
save