¿Por qué las herramientas de compilación utilizan un lenguaje de script diferente al lenguaje de programación subyacente?

23

Recientemente he estado usando algunas herramientas de compilación para un proyecto Nodejs en el trabajo cuando me di cuenta de que la herramienta / sistema de compilación principal de la mayoría de los lenguajes usa un lenguaje diferente al lenguaje de programación subyacente.

Por ejemplo, make no usa C o C ++ para escribir scripts y ant (ni Maven) no usa Java como su lenguaje para los scripts.

Los lenguajes más nuevos como Ruby usan el mismo lenguaje para crear herramientas como rake , lo que tiene sentido para mí. Pero, ¿por qué no siempre ha sido así? ¿Cuál es la ventaja de tener una herramienta de compilación que utiliza un idioma diferente del idioma subyacente?

joshin4colours
fuente
14
¿Quizás el lenguaje de uso general no es lo suficientemente adecuado para el uso especializado de la herramienta? Por ejemplo, ¡no me gustaría escribir archivos make en C! A veces un DSL es mejor.
Andres F.
13
Míralo desde otro ángulo: ¿por qué no usar el software de aplicación make para escribir?
whatsisname
44
Este artículo trata principalmente de lo que el autor cree que hace que Lisp sea excelente, pero tiene información relevante sobre por qué Ant usa XML en lugar de Java.
8bittree
66
Si quisieras escribir un programa en C que automatice la creación de programas en C, ¿no terminarías escribiendo makenuevamente (que de todos modos se implementa en C)?
Brandin
66
@ joshin4colours make está escrito en C. Sin embargo, el lenguaje que hace uso es un lenguaje declarativo que invoca el shell según sea necesario.

Respuestas:

36

La elección de qué lenguaje de programación usar para hacer algo debe depender de las características específicas de ese objetivo y no de las otras tareas relacionadas con ese proyecto.

Una herramienta de compilación realiza un trabajo muy específico, y no importa qué idioma esté utilizando para el proyecto principal, una herramienta de compilación es un software en sí misma.

Intentar vincular el proyecto principal y su herramienta de construcción podría ser una muy mala decisión. Lo que debe necesitar con una herramienta de compilación es principalmente un proceso rápido de reglas simples, con una administración rápida de archivos e IO.

Si lenguajes como el rubí se utilizan para implementar su herramienta de construcción, se relaciona más con las características de ese lenguaje que con la supuesta necesidad de mantener todo escrito con el mismo idioma.

Nicolás
fuente
18

No es imposible escribir una herramienta de compilación que use un lenguaje como C o Java como sus lenguajes de script. Sin embargo, las herramientas de construcción se benefician del uso de más lenguajes de script declarativos . Imagina el dolor y la repetición de escribir un archivo MAKE (o build.xml, o lo que sea) en C.

Las herramientas de construcción se benefician del uso de DSL, una tarea para la cual C no es una opción particularmente buena. C es demasiado general para una herramienta de compilación y demasiado preocupado por los detalles propensos a errores y de bajo nivel. Por ejemplo, no desea preocuparse por la gestión explícita de la memoria en una herramienta de compilación. Entonces, incluso si usa una sintaxis tipo C, probablemente usaría la recolección de basura en su herramienta de scripting, en ese momento ¿por qué no simplemente usar un DSL dedicado?

Tiene sentido que se pueda usar Ruby para esto, ya que es un lenguaje de nivel superior y más declarativo que C o Java. Ver también: Gradle, sbt.

Andres F.
fuente
13
Imagine the pain and boilerplate of writing a makefile (or build.xml, or whatever) in C.Imagine el dolor y el desorden de tratar de expresar una lógica condicional no trivial (ya sabe, material imperativo estándar) en un script XML declarativo. Oh, espera, no tienes que imaginarte; probablemente has tenido que lidiar con eso, y probablemente fue un desastre y medio, ¿no? Las compilaciones son una de las peores opciones posibles para un lenguaje de scripting declarativo, porque los problemas serios terminan rápidamente chocando con los límites de la declarativa, y los que no son lo suficientemente simples como para no necesitar una herramienta de compilación.
Mason Wheeler
77
@MasonWheeler Hay casos en los que las herramientas de compilación existentes me han hecho sufrir, sí. Ninguno de ellos habría sido ayudado mediante el uso de un lenguaje imperativo tipo C de bajo nivel. Veo algo como Ruby como probablemente ideal: lo suficientemente declarativo e imperativo, según sea necesario. C me daría pesadillas para esta tarea. Para mí, los sistemas de compilación son un buen caso de uso para (en su mayoría) DSL declarativas: le importa qué hacer, no cómo hacerlo (la mayoría de las veces).
Andres F.
2
Lo suficientemente justo. Siempre he pensado que C es una de esas tecnologías "si X es la respuesta que estás haciendo la pregunta equivocada", para ser sincero; es solo que trabajar con "scripts" XML ha sido una pesadilla cada vez que he tenido que sumergirme en uno. Estoy de acuerdo en que un lenguaje imperativo de nivel superior con capacidades DSL sería ideal.
Mason Wheeler
@AndresF .: Cosas como crear archivos requieren una combinación de enfoques. El estado de salida deseado se especifica de forma declarativa, pero las acciones necesarias para lograr ese estado se especifican de forma imperativa.
supercat
1
@MasonWheeler Creo que es un problema tanto para las personas que diseñaron el lenguaje de configuración como para el propio XML. El error común de los autores de tales lenguajes es suponer que solo porque algo está en XML, automáticamente será legible para los humanos. (Sé que he cometido este error más de lo que me siento cómodo. Es muy tentador). Un lenguaje de configuración bien diseñado y esbelto puede funcionar tan bien sobre XML como en cualquier otra forma.
biziclop
12

Vamos a darte un ejemplo del mundo real.

Hace unos 15 años trabajé en portar un gran sistema escrito en C desde Unix a Windows, tenía aproximadamente 3 millones de líneas de código. Para darle una idea de la escala, se tardó más de 24 horas en compilar en algunos de nuestros sistemas Unix (RS6000), Windows podría compilar el sistema en aproximadamente 4 horas.

(También teníamos 2 millones de líneas de código en nuestro propio lenguaje interpretado, pero decidimos no usar nuestro lenguaje para los sistemas de compilación, ya que nunca fue diseñado para el procesamiento de archivos. También necesitábamos un sistema de compilación para compilar el código C que implementaba nuestro lenguaje .)

En el momento en que el sistema de compilación se escribió en una combinación de scripts de shell y archivos de creación, estos no eran portátiles para Windows, por lo tanto, decidimos escribir nuestro propio sistema de compilación.

Podríamos haber usado C, sin embargo, decidimos usar Python, había pocas razones. (También reescribimos nuestro sistema de control de código fuente en Python al mismo tiempo, esto está muy integrado con el sistema de compilación, por lo que los desarrolladores pueden compartir los archivos de objetos para los módulos registrados).

  • La mayor parte de nuestro código podría construirse con unas pocas reglas simples (solo unos pocos miles de líneas de python para todas las plataformas, Windows, VMS y 6 versiones de Unix) que se derivaron de las convenciones de nomenclatura de los archivos.

  • En ese momento, RegEx no era muy estándar entre los sistemas C en diferentes plataformas, Python había incorporado RegEx.

  • Algunos módulos necesitaban pasos de compilación personalizados, Python permitió que los archivos de clase se cargaran dinámicamente. Permitimos que se usara una clase personalizada para construir un módulo (lib), basado en tener el archivo python con un nombre mágico en la carpeta. Esta fue la razón asesina para usar Python.

  • Consideramos Java, pero en ese momento no se distribuía en todas las plataformas.

(La interfaz de usuario de nuestro sistema de control de código fuente utilizaba un navegador web, ya que era portátil en toda la plataforma. Esto fue 6 meses antes de tener una conexión a Internet. ¡Tuvimos que descargar el navegador a través de X25!)

Ian
fuente
Después de haber trabajado en varios sistemas grandes, a veces siento que tengo una idea de cómo se escala el desarrollo. Luego leo historias como esta. Sheesh
dmckee
@immibis Esto era lo que había de moda hace 15 años. Aún más, esta práctica fue respaldada y alentada por los principales proveedores de Unix (SGI y DEC en particular, pero IBM también).
oakad
1
La gente tiende a olvidar que Unix solía significar "caro". Windows ganó la guerra de escritorio / estación de trabajo al ser más barato. Es por la misma razón que Linux luego ganó la guerra del servidor.
slebetman
1
Si quiero que una computadora ejecute el software que he escrito yo mismo, entonces quiero que sea flexible y tenga 101 opciones de cómo se compilan los núcleos, etc. Sin embargo, si estoy vendiendo software para instalarlo en la computadora del cliente, quiero que el cliente sea ejecutar un sistema operativo que no es flexible, por lo que sé que funcionará en su computadora si funciona en la mía. Ese fue un factor importante al considerar a Linux como un proveedor de software: el soporte parecía demasiado caro. Linux ha ganado las guerras de software de servidor alojado , donde el proveedor de software proporciona el servidor, por ejemplo, la mayoría del software implementado en la web.
Ian
3
@slebetman Es justo: Unix ganó la "guerra" anterior al ser más barato (en comparación con las máquinas LISPM y similares). Fue absolutamente horrible, terriblemente diseñado y se estrelló constantemente (¡pero arranca mucho más rápido que un LISPM!: P), usando C como lenguaje de programación principal (una caída bastante alta de LISP y similar), pero fue mucho más barato. De hecho, muchos lo adoptaron porque era gratuito (ha habido muchas mutaciones gratuitas mucho antes de Linux). De hecho, he conocido a muchos LISP de la vieja escuela que preferían MS-DOS a los unixes de la época. Sí que horrible.
Luaan
3

La respuesta corta a esta pregunta es que esto es lo que es una herramienta de compilación . Una herramienta que automatiza el uso de otras herramientas, con el objetivo de construir un producto final a partir de algunos archivos fuente. Si estamos escribiendo el script de compilación en el mismo idioma que el producto en sí, estamos en el ámbito de las herramientas específicas del lenguaje, que no se considerarían herramientas de compilación de la misma manera.

Esto plantea la pregunta: ¿por qué los compiladores no proporcionan el tipo de automatización de compilación a la que estamos acostumbrados desde herramientas como make? A lo que la respuesta es simplemente porque make existe . La filosofía de Unix de "hacer una cosa y hacerlo bien" sugiere que no es responsabilidad del compilador proporcionar esto *. Dicho esto, personalmente he pasado por mi parte de hacer dolores de cabeza, y estaría interesado en probar un compilador que proporcione su propio sistema de construcción "nativo" entre comillas.

Para ver un ejemplo de un compilador diseñado de esta manera, vea el Jai de Jon Blow (aún no publicado), un lenguaje destinado a reemplazar a C ++. Aquí se recopilan enlaces a charlas y demostraciones del compilador . Este lenguaje se compila en código de bytes que se ejecuta dentro del compilador, y la compilación en binario es una función estándar proporcionada por la biblioteca, accesible desde el código de bytes. La intención es permitir tanto la automatización de compilación como la metaprogramación dentro de la sintaxis nativa del lenguaje.

* Una mirada al Visual Studio de Microsoft le mostrará un ejemplo de la filosofía opuesta. :)

Haddon CD.
fuente
2

La herramienta de compilación es ante todo una herramienta, al igual que 'gcc', 'ls', 'awk' o 'git'. Alimenta la herramienta con una entrada (nombre de archivo, parámetros, etc.) y hará algunas cosas en consecuencia.

Todas estas herramientas le permiten pasar su entrada de manera que sea lo suficientemente simple como para escribir y comprender. En el caso particular de las herramientas de compilación, la entrada es un archivo de receta, un archivo que describe cómo su proyecto va desde los archivos de origen hasta el producto terminado.

Si su receta es tan simple como pasar la carpeta que contiene el proyecto y el compilador a utilizar, entonces un "lenguaje" declarativo es suficiente. Una vez que la receta se vuelve más y más complicada, con más lógica, se vuelve problemático manejarla con lenguajes declarativos y se utilizan lenguajes de propósito más general.

Ahora debería ser evidente que no hay conexión entre el idioma utilizado para escribir sus recetas de compilación y los idiomas utilizados para escribir el código de su producto simplemente porque tienen diferentes propósitos y requisitos. No hay conexión ni siquiera entre el idioma en el que está escrita la herramienta de compilación y el "idioma" en el que deben escribirse las recetas de compilación. ¡Utilice siempre la mejor herramienta para el trabajo!

Tibos
fuente