compiler construction - programacion - ¿Hay compiladores de código nativo Lisp?
primer compilador (6)
¿Existen compiladores de código nativo para Lisp? ¿Hasta qué punto se puede compilar, con toda su naturaleza dinámica, recolección de basura, macros y qué más?
Hay muchos compiladores Lisp que compilan a código nativo. CMUCL, SBCL, ClozureCL son conocidos entre los compiladores Lisp de fuente abierta.
La recolección de basura no es un obstáculo para la compilación del código nativo. Además, en algunos casos, Lisp puede usar la asignación de pila que no necesita GC y puede mejorar enormemente el rendimiento (utilizando una declaración de extensión dinámica, al menos SBCL lo admite).
Las macros (y cualquier código que se ejecute en tiempo de lectura (leer macros y read-eval), tiempo de compilación (macros, macros de compilación, código en eval-when)) requieren compilación incremental (se debe compilar la primera función macro, y luego se puede compilar el código que usa macro). Esto de alguna manera complica la compilación, pero no es demasiado problema. Además, las macros y las macros de compilación incluso ayudan al proceso de compilación porque permiten al programador escribir generadores de código y optimizadores de código, esencialmente personalizando el compilador.
Entonces, el compilador es más complicado que algunos lenguajes más simples (como C), pero la complejidad es manejable (ver Diseño de CMU Common Lisp ).
La naturaleza dinámica de Common Lisp es controlable y está diseñada para ser eficientemente compilable. A diferencia de algunos otros lenguajes dinámicos (por ejemplo, Python), el dinamismo está restringido (por ejemplo, no se puede tomar el entorno léxico actual en tiempo de ejecución), lo que les da a los compiladores cierta libertad para optimizar.
Hay un gran número de compiladores Lisp en código nativo, consulte http://www.thefreecountry.com/compilers/commonlisp.shtml y, por ejemplo, el compilador Common Lisp de CMU.
Muchos compiladores Lisp compilan el código ''nativo''. ''Nativo'' significa aquí ''código máquina'' (x86 en modo de 32 bits o 64 bits, PowerPC, SPARC, ...).
Otras preguntas:
¿Pueden los compiladores ''non-native code'' generar archivos ejecutables de un solo archivo? -> Sí.
¿Pueden los compiladores de "código nativo" generar archivos ejecutables de un solo archivo? -> Sí.
¿Qué tan "nativo" es "nativo"? -> El sistema Lisp tendrá la mayoría del tiempo su propio diseño interno de estructura de datos (clases CLOS), su propio manejo de errores (''condiciones''), su propia administración de memoria (recolección de basura), sus propias bibliotecas, ...
puede ejecutar Lisp sin un GC? -> Por lo general, no. Hay excepciones.
¿y el tamaño de la aplicación? -> Por defecto, las formas simples de generar una aplicación Lisp a menudo conducen a archivos ejecutables de gran tamaño. Los ejecutables incluyen todo el Lisp, incluida su biblioteca, los nombres de todos los símbolos, información sobre las listas de argumentos para las funciones, el compilador, el depurador, la información de ubicación del código fuente y más. Algunos compiladores también generan código grande (SBCL es un ejemplo).
¿Hay formas de reducir el tamaño de las aplicaciones? -> Eso depende del sistema Lisp. Los sistemas Lisp comerciales como LispWorks y Allegro CL pueden. Para la entrega de aplicaciones, pueden eliminar el código no utilizado, eliminar la información de depuración, eliminar partes de Lisp (bibliotecas, compilador, ...) y más.
pueden los sistemas Common Lisp generar pequeños ejecutables. Quiero decir realmente pequeño. -> No realmente. Los archivos ejecutables son grandes (CCL) o muy grandes (SBCL). Algunos sistemas Common Lisp pueden generar ejecutables de tamaño mediano. Pero ninguno realmente puede generar ejecutables pequeños.
¿Realmente no hay forma de generar ejecutables realmente pequeños? -> Hace años se escribieron compiladores que generan código C relativamente compacto sin grandes bibliotecas. Pero estos compiladores no se mantienen.
¿Hay otras formas de reducir los ejecutables? -> Si desea ejecutar más de una aplicación Lisp, tiene sentido reutilizar el tiempo de ejecución, el compilador y las bibliotecas en una o más bibliotecas compartidas. De esta forma, el código que se entregará será más pequeño, cuando el tiempo de ejecución ya esté instalado como una biblioteca compartida (o similar).
¿Cómo averiguo que el Lisp que uso admite como entrega de aplicaciones? -> lea el manual y pregunte a otros usuarios.
está bien, entonces la mayoría de los sistemas Common Lisp no pueden generar pequeñas aplicaciones. ¿Hay otros dialectos de Lisp que puedan generar ejecutables más pequeños? -> Sí, algunos compiladores de Scheme pueden.
¿Cómo maneja Common Lisp los errores de tiempo de ejecución? -> depende de la forma en que generes la aplicación. Por defecto, obtienes un depurador Lisp (a menos que lo hayas eliminado). Pero puede usar sus propias rutinas de manejo de errores en su aplicación y evitar que aparezca el depurador.
¿Cuáles son las fortalezas particulares de Common Lisp, cuando la generación de ejecutables realmente pequeños no es uno? -> puede incluir un REPL para interactuar con la aplicación, puede usar un compilador incluido para compilar código nuevo (o modificado) en tiempo de ejecución, puede usar el cargador FASL (código Lisp compilado) para CARGAR código nativo adicional en tiempo de ejecución (piense complementos, parches, extensiones, ...), es posible el manejo sofisticado de errores, incluida la recuperación de errores, ...
pero Lisp es dinámico? -> Sí, dinámico significa que puede cambiar muchas cosas durante el tiempo de ejecución. Por ejemplo, en Common Lisp puede cambiar una clase CLOS en tiempo de ejecución y las instancias de la clase adoptarán los cambios. Pero los diversos sistemas Lisp tienen diferentes formas de eliminar algunas de las características dinámicas. Las estructuras son menos dinámicas que las clases CLOS. Puede declarar tipos y compilar con diferentes configuraciones de optimización (velocidad, seguridad, depuración, ...). Usted puede alinear funciones. Y más.
Una forma simple de ver el código compilado para las funciones es usar la función Common Lisp DESMONTAR. Ejemplo en Clozure CL en una Mac x86-64
? (defun foo (x y) (if (= x y) (sin x) (* y (cos x))))
FOO
? (disassemble ''foo)
L0
[0] (leaq (@ (:^ L0) (% rip)) (% fn))
[7] (cmpl ($ 16) (% nargs))
[10] (jne L209)
[16] (pushq (% rbp))
[17] (movq (% rsp) (% rbp))
...
[172] (pushq (@ 77752))
[179] (jmpq (@ 10 (% temp0)))
L189
[189] (leaq (@ (:^ L0) (% rip)) (% fn))
[196] (jmpq (@ .SPNVALRET))
L209
[209] (uuo-error-wrong-number-of-args)
NIL
La salida de DISASSEMBLE obviamente depende de la arquitectura del procesador, el sistema operativo, el compilador Lisp utilizado y la configuración de optimización actual.
No olvide Chicken Scheme.
Sí. Ver http://en.wikipedia.org/wiki/Common_Lisp . Menciona que Steel Bank Common Lisp (una implementación bastante popular) compila todo de forma nativa por defecto. El hecho de que se utilicen recolecciones de basura y cosas similares no es un obstáculo para el código nativo. Eso solo significa que se necesita algún tipo de tiempo de ejecución. ¿Y qué? Incluso C tiene un tiempo de ejecución.
Tu apostaste Chez Scheme (un compilador comercial) es uno de los mejores. Gambit y Larceny son compiladores de investigación que también generan código nativo.