‎Uso de Jam‎ en Haiku Os

 



‎ Haiku utiliza una bifurcación personalizada de ‎‎Perforce's Jam‎‎. Este ‎‎ hilo de la lista de correo‎‎ ayuda a explicar la decisión de bifurcar el atasco. ‎

‎ A partir de agosto de 2019, esta es la versión actual. Si se informa de una versión diferente, deberá compilar e instalar jam desde el origen. ‎
jam -v
Jam 2.5-haiku-20111222. OS=LINUX. Copyright 1993-2002 Christopher Seiwald.

‎Opciones de línea de comandos‎

‎ Sólo algunas de las opciones se están discutiendo aquí. Consulte ‎‎jam -h para obtener‎‎ una lista completa de las opciones disponibles. ‎
  • -q

    ‎ Normalmente, jam intentará crear todos los destinos, incluso si se encuentra un error. '-q' indica a jam que se cierre inmediatamente después de encontrar un error. Esto es preferible, ya que ayuda a encontrar la causa real de la falla de compilación. ‎
  • ‎J #‎

    ‎ Donde # representa el número de subprocesos que se van a utilizar. Esto es útil cuando se construye en máquinas SMP o multinúcleo. ‎
  • -a

    ‎ Cree todos los objetivos, incluso si son actuales. Normalmente, esto no es necesario. Es posible que deba hacer esto de vez en cuando porque algunas de las reglas de atasco no son perfectas y no establecen las dependencias entre archivos correctamente. El caso más frecuente es cuando actualizamos nuestra copia de Freetype: esto impedirá que cualquiera pueda construir sin el switch -a. También puede usar este interruptor si algo no parece actualizarse después de algún cambio que haya realizado. Este es el caso cuando modifica un jamfile: Jam no comprueba eso y no reconstruirá las cosas que deberían verse afectadas por los cambios. ‎
  • -sx=y

    ‎ Establezca la variable x=y, reemplazando el entorno. Un ejemplo es: Esto asegurará que los objetivos de lanzamiento*se construyan según las especificaciones exactas de ‎‎DefaultBuildProfiles‎‎ de Haiku. ‎
        jam -sHAIKU_IGNORE_USER_BUILD_CONFIG=1 -q @release-raw
    
  • -dX

    ‎ Habilita el resultado de depuración, donde X puede ser uno de los siguientes: ‎
    • ‎a)acciones‎
    • ‎c)causas‎
    • ‎d)dependencias‎
    • ‎m)hacer árbol‎
    • ‎(x)comandos‎
    • ‎(0-9) niveles de depuración‎
  • -n

    ‎ En realidad, no ejecute las acciones de actualización. Esto parece ser útil para probar Jamfiles. ‎

‎Posibles objetivos‎

‎Objetivos de lanzamiento oficial‎

‎Los siguientes destinos se definen en ‎‎build/jam/DefaultBuildProfiles‎

  • ‎@release crudo‎

    ‎ Crea una imagen preliminar como una imagen sin procesar. Esto se puede escribir directamente en el disco o usar con Qemu ‎
  • @release-vmware

    ‎ Crea una imagen preliminar para su uso con VMWare. Esto también se puede utilizar con VirtualBox. ‎
  • @release-cd

    ‎ Un CD ISO de una sola pista. 'mkisofs' es necesario para construir esto. ‎
  • @release-anyboot

    ‎ Un archivo personalizado que se puede grabar en un CD o escribir directamente en el disco o utilizar con Qemu. Se compone de un Master Boot Record (MBR), una imagen de arranque de El Torito y una imagen raw BFS. El MBR ocupa los primeros 512 bytes de la imagen de El Torito, que suele estar vacía. La imagen BFS simplemente está concatenada al final. Dentro del MBR hay una entrada de tabla de particiones, que se asigna a la imagen BFS. ‎

‎Objetivos no release‎

‎Además de mirar ‎‎DefaultBuildProfiles‎‎, también hay una forma de encontrar posibles objetivos mirando las diversas ‎‎declaraciones "NotFile‎‎". Una instrucción "NotFile" se utiliza generalmente para crear un destino de compilación con un nombre más fácil de usar. Objetivos como estos deben verse como una base mínima.‎

‎Personalizar la compilación, habilitar la depuración, etc.‎

‎Varios aspectos del sistema de compilación son personalizables a través del ‎‎archivo UserBuildConfig‎‎.‎

‎Algunas notas‎

  • ‎sudo <opciones>‎

    ‎No debe usar el comando sudo al ejecutar jam.‎
    ‎ En primer lugar, todos y cada uno de los archivos en $ (HAIKU_OUTPUT_DIR)--típicamente /path/haiku/haiku/generated/ solo serán accesibles a root. Para solucionar esto, es necesario ejecutar ‎‎chown -R <user>:<group> <path>‎‎. En segundo lugar, los errores del usuario se vuelven mucho más dañinos cuando se usa 'sudo jam', ya que podría sobrescribir fácilmente la partición incorrecta. ‎

    ‎ ‎

    ‎El método preferido es aplicar permisos a su dispositivo primero.‎

    ‎ En este ejemplo se utiliza el perfil de compilación 'walter-sda2', que se define en la página ‎‎UserBuildConfig & BuildProfiles‎‎. ‎

    ‎Para las distribuciones de Linux que utilizan udev para mantener /dev, esto solo funcionará hasta que reinicie. Para permitir que su usuario tenga acceso de lectura permanente al disco completo y acceso de escritura a la partición Haiku, debe pedirle a udev que lo haga por usted después de cada arranque. Para hacer eso, cree un archivo de regla udev para los cambios locales (para openSUSE, el archivo podría llamarse '/etc/udev/rules.d/99-local.rules') y agréguelo:‎

    ‎ ‎

    ‎Para activar los cambios para la sesión actual, invoque ‎

    sudo chmod o+r /dev/sda
    sudo chmod o+rw /dev/sda2
    jam -q @walter-sda2
    
    KERNEL=="sda", MODE="0664"
    KERNEL=="sda2", OWNER="your_username"
    
    sudo udevadm trigger

  • ‎Limpieza de atributos emulados‎

    ‎ Al crear Haiku en un sistema de archivos que no es BFS ni utiliza una ‎‎implementación suficiente de xattr‎‎, el sistema de compilación emulará atributos. Se creará una carpeta en la carpeta generada. Será necesario eliminar manualmente la carpeta de atributos emulados, idealmente antes de cada ciclo de compilación. De lo contrario, pueden producirse algunos problemas. ‎

    ‎Nota: Esto supone que su HAIKU_OUTPUT_DIR ‎‎se genera /‎‎ !!‎

    attributes/
    cd /path/haiku/haiku/
    jam clean
    rm -Rf generated/attributes/
    jam <options> <target>
    

Miscellaneous Links

The Art of Jamming - All Parts

‎Cuerpo‎

‎Parte 1‎

‎Antes de que los músicos de la audiencia se emocionen demasiado, no voy a hablar de reunirme con amigos para sacar algunas melodías. Tampoco los cocineros de la audiencia encontrarán instrucciones para hacer las conservas de frutas perfectas. No, cuando digo Jamming, me refiero al acto de usar la herramienta de compilación Jam.‎

‎En esta primera parte de mi serie sobre la herramienta de compilación Jam, voy a proporcionar una visión general de alto nivel, así como mostrar el producto de algunos de mis trabajos recientes con Jam: el motor Jamfile. Para aquellos que han desarrollado en BeOS durante una cantidad decente de tiempo, esto puede sonar familiar. Debería, porque esencialmente he tomado la funcionalidad del motor Be makefile y la he "portado" a Jam.‎

‎¿Qué tipo de motor?‎

‎Para aquellos que no están familiarizados con el motor makefile, eche un vistazo a su directorio ‎‎/system/develop/etc‎‎ algún tiempo. En pocas palabras, esta herramienta proporciona un archivo de creación bien comentado que completa como un formulario para usar en la creación de su aplicación. Proporcione el nombre de la aplicación, los archivos de origen desde los que se compila, las bibliotecas a las que vincular, los directorios de inclusión adicionales, etc. En la parte inferior de la plantilla makefile hay un comando que incluye el motor makefile, que hace todo el trabajo para crear su proyecto. La misma plantilla makefile también se puede usar para crear bibliotecas y controladores.‎

‎Así que como puedes ver, creo que el motor makefile es otra gran idea, originalmente de Be, Inc., y decidí crear un tributo basado en Jam. Por supuesto, hay buenas razones para hacer esto además de pagar un homenaje. Una es que simplemente no parece correcto tener a Jam como la herramienta de compilación oficial de Haiku, pero dejar a nuestros desarrolladores de aplicaciones utilizando un sistema de compilación basado en la fabricación.‎

‎Mermelada desde 10,000 pies‎

‎De un alto nivel Jam es esencialmente un lenguaje de scripting interpretado con una especialidad en la construcción de cosas. Considero que es una buena evolución de la marca, ya que es más potente y, en general, más fácil de usar. Por supuesto, a las personas que están acostumbradas a hacer probablemente no les gustará Jam al principio porque es muy diferente y requiere un tipo diferente de pensamiento al crear un script de compilación.‎

‎Entonces, ¿cómo se crea un script de compilación de Jam? Primero defina las variables que pueda necesitar o que sean utilizadas por las reglas a las que llamará y, a continuación, llame a esas reglas. Las reglas son algo así como funciones o métodos en lenguajes de programación: tienen parámetros y realizan alguna función útil, que para Jam generalmente implica crear una cosa a partir de otra. Para facilitar la creación de scripts de compilación, Jam tiene una sintaxis de lenguaje capaz y bastantes reglas integradas que realizan funciones comunes de herramientas de compilación, como compilar archivos C o C ++ y vincular aplicaciones. Entraré en más detalles sobre el lenguaje Jam y las reglas incorporadas en mi próximo artículo, pero debo explicar una cosa en detalle ahora: el uso de jam de los espacios en blanco. Es importante aprender esto temprano y bien: Jam interpreta los scripts de compilación como una lista de tokens separados por espacios en blanco, y para que los archivos que cree se interpreten correctamente, debe tener espacios en blanco en todas partes. Esto incluye poner el espacio en blanco antes del punto y coma (;) que termina una línea. Es importante aprender esto ahora porque debe hacerlo cuando use el motor Jamfile que se describe a continuación. Si olvida poner espacios en blanco en áreas importantes, Jam producirá errores que pueden ser difíciles de resolver (créanme, lo sé).‎

‎Atascando las cosas‎

‎Así que ahora que tienes algunos conocimientos básicos de Jam, déjame explicarte cómo configurar el motor Jamfile. Solía ser más complicado: descargue e instale 'jam' y un archivo del motor Jamfile, pero ahora es muy fácil: 'jam' ya está preinstalado con Haiku y el motor Jamfile se puede instalar con HaikuDepot o una instalación rápida de pkgman jamfile_engine en Terminal.‎

  1. ‎Encuentra una buena aplicación BeOS/Haiku para la que tengas el código fuente, para que puedas crear un nuevo Jamfile con el que construirlo. Sería una ventaja si la aplicación que elija ya tuviera un makefile que use el motor makefile. Un makefile de este tipo se puede detectar mediante una línea inicial como esta: El número de versión puede ser diferente, pero si se ve así, tiene un makefile genérico que utiliza el motor makefile.‎
    ## BeOS/Haiku Generic Makefile v2.0 ##

‎Una vez que haya hecho lo anterior, puede proceder a completar la plantilla Jamfile para esta aplicación:‎

  1. ‎Copie el Jamfile desde la ubicación en la que se instalaron los archivos Jamfile-engine (que de forma predeterminada es ‎‎/system/develop/etc‎‎.)‎
  2. ‎Abra el Jamfile copiado y el makefile antiguo, si hay uno.‎
  3. ‎Rellene el Jamfile como se especifica en los comentarios, o copiando desde el makefile. Recuerde la discusión anterior sobre el espacio en blanco.‎

‎Una vez que haya completado la plantilla a su satisfacción, abra un Terminal, ‎‎cd‎‎ a su directorio de aplicaciones y escriba ‎‎jam‎‎. Si ha proporcionado los conjuros de Jam correctos en su plantilla, debe encontrar un nuevo ‎‎obj. Directorio X86‎‎ en el directorio de la aplicación que contiene los archivos de objeto y la aplicación final para el proyecto. Si obtiene algún error del motor Jamfile, debe ser bastante amigable y apuntarle en la dirección correcta. Si tiene algún error de Jam oscuro y difícil de entender, revise su plantilla nuevamente y asegúrese de tener todos los espacios necesarios.‎

‎Una nota final para cualquier propietario de PowerPC en la audiencia: desde que usé el Be makefile-engine como una especie de plantilla para mi Jamfile-engine, he tratado de incluir soporte para máquinas PPC similar a lo que estaba en el makefile-engine. Pero como solo tengo una máquina x86, no pude probar esta funcionalidad. Si alguien quisiera probar el motor Jamfile en una máquina PPC (en BeOS) y me hiciera saber cómo va, ¡se lo agradecería!‎

‎En mi próximo artículo, repasaré la implementación del motor Jamfile y daré más detalles sobre cómo funciona Jam y cómo puede usarlo de manera más avanzada en cualquier proyecto en el que pueda estar trabajando.‎

‎Parte 2‎

‎Si abre el archivo de texto Jamfile-engine, notará que comienza con una sección de comentarios bastante estándar al principio:‎

##  Haiku Generic Jamfile Engine v1.0.2
## Does all the hard work for the Generic Jamfile
## which simply defines the project parameters.

## Most of the real work is done in the Jambase
## embedded into the jam executable.
##
## Inspired by the Be Makefile Engine
##
## Supports Generic Jamfile v1.0.1
##
## Copyright (c) 2002-2010 Ryan Leavengood
## Copyright (c) 2011 Peter Poláčik
## Released under the Terms of the MIT License, see
## http://www.opensource.org/licenses/mit-license.html


‎A partir de esto te darás cuenta de que los comentarios en Jam comienzan con un símbolo hash () y continúan hasta el final de la línea. En este caso se utilizan dos hashes para hacer que este comentario destaque más e indicar que describe el archivo como un todo y no solo como un detalle de implementación. ‎#

‎Después del comentario inicial comienza el código real. En la primera parte del motor Jamfile, se definen varias reglas de utilidad que se pueden usar y reutilizar más adelante en el archivo. Las primeras reglas son simples:‎

# AddResources <Application Name> : <Resource Files> ;

# Adds the given resources to the given application.

rule AddResources
{
Depends $(<) : $(>) ;
}

actions AddResources
{
$(XRES) -o "$(<)" $(>)
}

# MimeSet <Application Name>;
# Sets the mime type of the given application to be an application.
actions MimeSet
{
$(MIMESET) -f "$(<)"
}

‎Reglas de Jam: Procedimiento y Acciones‎

‎Después de mirar la plantilla anterior, muchos lectores pueden estar confundidos. ¿Por qué se define AddResources dos veces, una vez usando la palabra y luego con la palabra? La razón es que las reglas de Jam se crean en dos partes: ‎ruleactions

  1. ‎El procedimiento‎‎ (definido usando la palabra clave):‎
    ‎ Un conjunto de sentencias de lenguaje Jam que se ejecutan cuando se invoca la regla y que generalmente configuran variables que se utilizarán en las acciones.‎
    rule

  2. ‎Las acciones‎‎:‎
    ‎ comandos de shell que se ejecutan cuando un destino necesita actualización (y hacen uso de las variables configuradas en el procedimiento).‎

‎En el caso anterior de AddResources, el procedimiento establece una dependencia entre el primer parámetro y el segundo parámetro: ‎

‎ depende ‎

‎ del significado de que cuando cambia, debe actualizarse.‎
$(<)$(>)$(>)$(<)

‎Parámetros de regla‎

‎Las variables utilizadas aquí, y son alias para y , que son el primer y segundo parámetros pasados a la regla, respectivamente. Hasta 9 parámetros, , se pueden pasar a las reglas. Si bien todos se pueden usar en el procedimiento, solo los dos primeros se pueden usar en las acciones.‎$(<)$(>)$(1)$(2)$(1) - $(9)

‎En el caso de las acciones para AddResources, el comando xres se llama usando la variable , siendo la salida el valor citado de (las comillas permiten espacios en el nombre de la aplicación), y con los archivos de recursos de entrada siendo el valor de .‎$(XRES)(-o)$(<)$(>)

‎Al definir reglas de actualización, o generalmente se considera que es el destino (lo que creará la regla) y/o es el origen (s) (a partir del cual se creará el destino).‎$(1)$(<)$(2)$(>)

‎Aunque se menciona brevemente, debe ser evidente que es solo una referencia a una variable global definida en otra parte del motor Jamfile (que solo tiene el nombre del comando xres). Esto muestra que cualquier variable dentro del ámbito se puede usar en las acciones de una regla.‎$(XRES)

‎Después de AddResources, se crea la regla MimeSet, pero en este caso no hay ningún procedimiento porque no se necesitan variables ni dependencias para esta regla. De hecho, esta regla solo tiene un parámetro: el nombre de la aplicación en la que se debe ejecutar el comando mimeset.‎

‎ Después de las reglas anteriores se define una regla más complicada:‎

# ProcessLibs <List of Library Names> ;

# Prepends -l to any library names that aren't _APP_ or _KERNEL_ or
# that don't have .a or .so file extensions. The result will be given
# to the linker so that it links to the right libraries.
rule ProcessLibs
{
local result ;

for i in $(1)
{
if ( ( $(i) in _APP_ _KERNEL_ ) || ( $(i:S) in .so .a ) )
{
result += $(i) ;
}
else
{
result += -l$(i) ;
}
}

return $(result) ;
}


‎Hay muchas cosas sucediendo en la regla, pero lo primero que debe mencionarse es que, a diferencia de la regla MimeSet, esta regla solo tiene un procedimiento pero no acciones asociadas. En este caso, la regla es solo una regla de procesamiento de cadenas que itera sobre una lista de nombres de biblioteca y agrega un prefijo -l a aquellos que no son _APP_ o _KERNEL_ o que no terminan en .so o .a. Para implementar esta funcionalidad, se utiliza gran parte del lenguaje Jam incorporado.‎

‎Sintaxis básica‎

‎ Lo primero que se hace en esta regla es la declaración de una variable local llamada . La palabra clave proporciona un alcance dinámico (como en C o C ++): si existe otra variable con nombre cuando se llama a esta regla, se guardará ese valor antiguo, el nuevo valor no tendrá nada que ver con el anterior y, a continuación, una vez finalizada la regla, se descarta el nuevo valor y se restaura el antiguo.‎resultlocalresult

‎Después de la declaración de la variable de resultado local, hay otra nueva pieza de sintaxis: el bucle for. En este caso, la palabra clave se utiliza para iterar sobre los elementos de la lista (el primer y único parámetro de esta regla), estableciendo la variable en cada elemento a su vez. ‎for$(1)i

‎Después de la instrucción for loop está su bloque asociado, que contiene las instrucciones que deben ejecutarse en cada iteración de bucle. Este bloque contiene una sola instrucción, que es muy similar a la if.. else construct en C. La condición de que esta instrucción if verifique es bastante compleja, pero cuando se desglosa es simple: en el primer conjunto de paréntesis, la palabra clave se usa para ver si el valor actual de está en la lista [_APP_ _KERNEL_].‎if..elsein$(i)

‎Manejo de listas‎

‎La palabra clave, como probablemente se pueda adivinar, devuelve true si el primer parámetro es un subconjunto del segundo. Tenga en cuenta el uso del subconjunto de términos: ambos "parámetros" de la palabra clave son listas, y el resultado solo es verdadero si cada elemento de la primera lista está en la segunda lista. (En este caso, solo se utiliza una lista de un solo elemento para el primer parámetro).‎inin

‎Tenga en cuenta también que las listas literales en el lenguaje Jam (como en este caso) no necesitan ningún delimitador (donde la sintaxis C requeriría corchetes rizados ({ y }), comas (,) y comillas dobles (") para crear una lista de cadenas). Esta es una de las ventajas de la sintaxis de Jam (y una de las razones de todo el espacio en blanco). Esto realmente comienza a ilustrar que en el fondo Jam es solo un lenguaje de procesamiento de listas (¡hola fanáticos de LISP!) De hecho, cambiar la sintaxis de Jam para que sea como LISP probablemente no sería demasiado difícil, pero eso se dejará como un ejercicio para el lector. ‎_APP__KERNEL_

‎Operadores‎

‎Después de la primera condición en el si es una disyunción o (), que funciona igual que el equivalente C (el resultado solo es falso si ambos lados son falsos). El segundo lado del or es una condición similar a la primera: comprueba si hay algo en una lista. En este caso, sin embargo, se utiliza uno de los modificadores variables de Jam, , .‎||:S

‎Lo que hace es devolver el último sufijo de nombre de archivo de la variable dada, en otras palabras, la extensión del nombre de archivo. Si la extensión del nombre de archivo está en la lista ".so.a", entonces esta instrucción será true.‎:S

‎Siempre que la condición if (que observará que tiene espacios en blanco que separan todos los tokens) devuelve true, la expresión se usa para agregar el valor no modificado de a la lista de resultados. El operador funciona igual que en C: el valor del resultado se establece en el valor antiguo del resultado más el valor de . Pero dado que Jam es un lenguaje orientado a listas, esta adición no es matemática, sino que es una adición de lista: el nuevo valor se agrega como un nuevo elemento al final de la lista. De hecho, Jam no tiene ninguna sintaxis para hacer matemáticas en absoluto.‎+=$(i)+=$(i)

‎En el caso de que la condición if sea falsa, se ejecutará el bloque bajo la cláusula else. Este bloque agrega el valor de con el prefijo a la lista de resultados. ‎$(i)-l

‎Expansión variable‎

‎Aunque realmente no entra en juego aquí, ahora es un buen momento para mencionar cómo funciona la "expansión variable" de Jam. Cuando se concatenan varias variables o una variable con uno o más literales, el resultado es una lista que es un ‎‎producto‎‎ de los componentes de las variables que se combinan.‎

‎Por ejemplo, en el caso simple de la declaración anterior, el resultado será el valor de con antepuesto a ella. Dado que el bucle for asegura que es una lista de un solo elemento, el resultado es simple, pero si tuviera más de un elemento (como ) el resultado sería: ‎

‎ .‎
-l$(i)$(i)-l$(i)$(i)[be media midi][-lbe -lmedia -lmidi]

‎Dado ‎‎que‎‎ el valor de , el resultado de sería:‎$(i)$(i)$(i)

[bebe bemedia bemidi mediabe mediamedia mediamidi midibe midimedia midimidi].

‎Intenta decir eso tres veces rápido.‎

‎Dos notas finales con respecto a la expansión variable: si una lista contiene la cadena nula (""), el resultado de la expansión sigue siendo un producto, pero solo de elementos no nulos. Por ejemplo, si una variable era la lista y era , la expansión de sería . La otra nota es que cualquier expansión que utilice una variable indefinida da como resultado una lista vacía.‎$(x)[A ""]$(y)["" 1]*$(x)$(y)*[*A* *A1* ** *1*]

‎Después de ProcessLibs es una regla de procesamiento de cadenas similar:‎

# MkObjectDirs <List of Source Files> ;
# Makes the necessary sub-directories in the object target directory based
# on the sub-directories used for the source files.
rule MkObjectDirs
{
local dir ;

for i in $(1)
{
dir = [ FDirName $(LOCATE_TARGET) $(i:D) ] ;
Depends $(i:S=$(SUFOBJ)) : $(dir) ;
MkDir $(dir) ;
}
}


‎Esta regla se utiliza para crear subdirectorios para los archivos de objeto que reflejan la estructura de directorios de los archivos de origen del proyecto. De forma similar a ProcessLibs, se declara una variable local y se utiliza un bucle for, que en este caso itera sobre los nombres de archivo de origen. En el cuerpo del bucle, la variable dir se establece como el resultado de una llamada a la regla FDirName integrada, que toma los elementos de la lista que se le ha pasado y los concatena con separadores de directorios entre cada elemento.‎

‎El parámetro fDirName es una lista que contiene el directorio de destino en el que se construye todo (definido más adelante en el motor Jamfile) y el directorio del archivo de origen (que es lo que devuelve el modificador de variables). A continuación, se establece una dependencia entre el archivo de objeto para el archivo de origen y el nombre del directorio creado.‎:D

‎El modificador utilizado con reemplaza la extensión de archivo de la variable con el sufijo dado, en este caso la variable , que es .o en BeOS. Al crear esta dependencia entre el archivo de objeto y el directorio en el que se crea, podemos asegurarnos de que el directorio se cree correctamente antes que el archivo de objeto. ‎:S=$(i)$(SUFOBJ)

‎Después de configurar la dependencia, se llama a la regla MkDir real con el directorio dado. Esta regla crea el directorio dado si aún no existe, incluidos los directorios principales necesarios, como el comando GNU con la opción.‎mkdir-p

‎Después de la regla MkObjectDirs hay algunas reglas más simples:‎

# RmApp <Pseudotarget Name> : <Application Name> ;

# Removes the given application file
# when the given pseudotarget is specified.
rule RmApp
{
Depends $(<) : $(>) ;
}

actions RmApp
{
rm -rf "$(>)"
}

# RunApp <Pseudotarget Name> : <Application Name> ;
# Runs the given application in the background

# when the given pseudotarget is specified.
rule RunApp
{
Depends $(<) : $(>) ;
}

actions RunApp
{
"$(>)" &
}

Pseudotargets

‎Estas reglas se parecen mucho a AddResources, y su función en el motor Jamfile debería ser obvia. Una cosa que puede no ser obvia es cuáles son los parámetros, particularmente el primer nombre de pseudotarget.‎

‎Un pseudotarget es un nombre que define un destino que se puede especificar en la línea de comandos para atascar, pero que no es realmente un destino del sistema de archivos que se puede crear. Esta distinción se especifica utilizando ciertas reglas de Jam, que se describirán más adelante. Basta con decir que cuando los pseudoobjetivos pasados a las reglas anteriores se especifican en la línea de comandos de jam, se ejecutarán las acciones para esas reglas.‎

‎Por ejemplo, si se especificó más adelante en el motor Jamfile(que lo es), ejecutar "jam test" en la línea de comandos ejecutaría la aplicación en segundo plano (después de crearla si es necesario). ‎RunApp test : $(APP) ;

‎ Ahora para el siguiente conjunto de reglas:‎

# InstallDriver1 <Pseudotarget Name> : <Driver File> ;
# Installs the given driver in the correct location
# when the given pseudotarget is specified.
rule InstallDriver1
{
Depends $(<) : $(>) ;
USER_BIN_PATH = /boot/home/config/add-ons/kernel/drivers/bin ;
USER_DEV_PATH = /boot/home/config/add-ons/kernel/drivers/dev ;
}

actions InstallDriver1
{
copyattr --data "$(>)" "$(USER_BIN_PATH)/$(>:B)"
mkdir -p $(USER_DEV_PATH)/$(DRIVER_PATH)
ln -sf "$(USER_BIN_PATH)/$(>:B)" "$(USER_DEV_PATH)/$(DRIVER_PATH)/$(>:B)"
}


# InstallDriver <Pseudotarget Name> : <Driver File> ;
# Installs the given driver in the correct location
# when the given pseudotarget is specified
# (after making sure that this is actually a driver)
rule InstallDriver
{
if ( $(TYPE) = DRIVER )
{
InstallDriver1 $(<) : $(>) ;
}
}

>

‎Estas reglas, como sus nombres lo indican, se utilizan para instalar controladores. Los comandos en las acciones se toman casi textualmente desde el motor Be makefile (como dicen: si no está roto, no lo arregles).‎

‎La razón por la que hay una regla y se debe a la necesidad de verificar la variable antes de realizar realmente la acción. Si esto no es realmente un controlador, no tiene sentido intentar instalarlo en los directorios del controlador. Por lo tanto, la regla a la que deben llamar los usuarios de este conjunto de reglas es , que hará lo correcto en función del tipo dado de proyecto BeOS. Este estilo de nomenclatura (anexando al nombre de la regla para la regla de trabajo) se utiliza en el archivo Jambase, por lo que también se utiliza en el motor Jamfile.‎InstallDriver1InstallDriver$(TYPE)InstallDriver1

‎Finalmente, las dos últimas reglas definidas son:‎

# Link <Application Name> : <List of Object Files> ;

# Replaces the actions for the default Jam Link rule with one that
# handles spaces in application names.
actions Link bind NEEDLIBS
{
$(LINK) $(LINKFLAGS) -o "$(<)" $(UNDEFS) $(>) $(NEEDLIBS) $(LINKLIBS)
}

# BeMain <Application Name> : <List of Source Files> ;
# This is the main rule that builds the project.

rule BeMain
{
MkObjectDirs $(>) ;

if ( $(TYPE) = STATIC )
{
Library $(<) : $(>) ;
}
else
{
Main $(<) : $(>) ;
}

if ( $(RSRCS) )
{
AddResources $(<) : $(RSRCS) ;
}

MimeSet $(<) ;
}

‎Como ilustra el comentario, la primera "regla" es en realidad solo una redefinición de las acciones para la regla link incorporada. Las acciones de la regla Link en jambase se han cambiado añadiendo comillas alrededor del nombre de la aplicación.‎$(<)

‎Esto muestra que cualquiera de las reglas de Jam integradas se puede modificar libremente en cualquier Jamfiles que cree. De hecho, la Jambase incorporada se puede reemplazar por completo especificando la opción de Jam en la línea de comandos (aunque esto puede no ser demasiado útil ya que la mayor parte de la utilidad de Jam proviene de las reglas definidas en la Jambase incorporada).‎-f

‎La regla principal‎

‎La regla final, BeMain, es el verdadero caballo de batalla en el motor Jamfile: esto es realmente lo que construye el proyecto. Sin embargo, debido a todo el trabajo realizado en el resto del motor Jamfile, esto es realmente bastante simple.‎

‎En primer lugar, se llama a la regla MkObjectDirs con los archivos de origen del proyecto, que crearán los directorios de objetos necesarios como se describió anteriormente. A continuación, se utiliza una instrucción if para determinar si el tipo de proyecto es una biblioteca estática. Si es así, se llama a la biblioteca de reglas de Jam incorporada, que compila los archivos de origen dados y luego los archiva en una biblioteca estática del nombre dado. De lo contrario, se llama a la regla de Jam main integrada, que compila los archivos de origen dados y luego los vincula como el nombre de la aplicación dado.‎

‎En este punto se debe mencionar que ambos y hacer uso de la regla, que utiliza la regla, que es inteligente en el sentido de que mira la extensión de archivo del archivo de origen dado y luego llama a la regla apropiada para compilarlo. Los archivos que terminan con o se compilan con la regla, mientras que los archivos se compilan con la regla y los archivos se compilan con , etc. Por lo tanto, las fuentes pueden ser una lista mixta de cualquier archivo compatible con Jam y todos se compilarán correctamente y se vincularán en una aplicación o biblioteca. (También hay una manera bastante fácil de agregar soporte para compilar otros tipos de archivos, como archivos Pascal o ASM, por ejemplo, que se explicarán en el próximo artículo).‎LibraryMainObjectsObject.cpp.cc.CC++.cCc.lLex

‎El resto del motor Jamfile es en su mayoría definiciones de varias variables, y solo unas pocas partes de él utilizan conceptos de Jam que aún no se han explicado. Esas son las únicas partes que se explicarán aquí, comenzando con esto: ‎

# Set the directory where object files and binaries will be created.
# The pre-defined Jam variable OSPLAT will indicate what platform we

# are on (X86 vs PPC, etc.)
LOCATE_TARGET = obj.$(OSPLAT) ;

‎Como se describe brevemente en la explicación de la regla, esta variable define dónde deben ubicarse los objetivos, es decir, dónde se crean. En este caso, se establece que sea "obj." con la plataforma anexada. La variable es una de las pocas variables realmente compiladas en Jam (y por lo tanto no establecidas en Jambase), y es una descripción en mayúsculas del tipo de CPU (como X86, PPC o SPARC).‎MkObjectDirs$(OSPLAT)

‎Jam se ejecuta en muchas plataformas, y un Jamfile correctamente escrito debería poder funcionar en muchas de ellas, sin modificaciones. Por ejemplo, el motor Jamfile debería teóricamente ejecutar cualquier plataforma Haiku como lo es hoy en día (el término teóricamente se usa aquí ya que nadie ha probado el motor Jamfile en una máquina que no sea x86 todavía).‎

‎Además, aunque se usa en , es en realidad una variable de Jambase que se usa ampliamente en todas las reglas de Jam incorporadas. Por supuesto, una cosa que un usuario útil de Jamfile-engine descubrió es que a pesar de la configuración de esta variable, los archivos fuente que existen en subdirectorios se crean en subdirectorios similares en , no directamente en él. Esta es la razón por la que se creó la regla, porque de lo contrario el compilador se queja cuando intenta colocar archivos de objetos en directorios inexistentes.‎MkObjectsDirLOCATE_TARGETLOCATE_TARGETMkObjectDirs

‎ Después de la definición vienen algunas definiciones más:‎LOCATE_TARGET

# Set some defaults

if ( ! $(NAME) )
{
ECHO "No NAME defined!" ;
NAME = NameThisApp ;
}
if ( ! $(TYPE) )
{
ECHO "No TYPE defined...defaulting to APP" ;
TYPE = APP ;
}
if ( ! $(SRCS) )
{
ECHO "NO SRCS defined...defaulting to *.cpp in current directory" ;
SRCS = [ GLOB . : *.cpp ] ;
}
if ( ! $(DRIVER_PATH) )
{
DRIVER_PATH = misc ;
}

‎Todos estos son probablemente bastante obvios. Los pocos puntos interesantes son:‎

  • ( ! $(SOME_VAR) )‎ será true para una variable indefinida o vacía.‎
  • ‎La regla devuelve los archivos que coinciden con los criterios especificados en el directorio dado. Las reglas de patrón se explicarán más detalladamente en el próximo artículo.‎GLOB
  • ‎La sintaxis de los corchetes ([]) alrededor de una invocación de regla expande los resultados de esa regla en una lista que luego se puede asignar a una variable.‎

‎Siguiendo las definiciones anteriores hay una gran sección que define variables basadas en el tipo de CPU. Una vez más, la mayor parte de esto se basa en el motor Be makefile, con algunos ajustes debido a la sintaxis más capaz de Jam. Uno de esos ajustes es el uso de la instrucción Jam en lugar de una serie de declaraciones if. Dado que esa es la única pieza nueva de la sintaxis de Jam, eso es todo lo que se describirá de esta sección del motor Jamfile:‎switch

switch $(OPTIMIZE)
{
case FULL : OPTIMIZER = -O3 ;
case SOME : OPTIMIZER = -O1 ;
case NONE : OPTIMIZER = -O0 ;

# Default to FULL
case * : OPTIMIZER = -O3 ;
}

‎La instrucción Jam probablemente parezca familiar para los programadores de C o C ++. En general, funciona igual, pero tiene algunas características más agradables. Por ejemplo, no hace coincidencias basadas en la equivalencia numérica simple, sino en la coincidencia de cadenas.‎switch

‎En el caso anterior, si se establece en cualquiera de los casos enumerados explícitamente, se ejecuta la instrucción coincidente. No hay necesidad de una instrucción de interrupción como en C, solo se ejecuta la instrucción coincidente. Tampoco hay una rama predeterminada, aunque se puede tener la misma funcionalidad utilizando como criterios de coincidencia, como se hizo anteriormente. De hecho, la instrucción descrita anteriormente en realidad utiliza la sintaxis coincidente de la instrucción ( se implementó antes ), y de nuevo la sintaxis coincidente se describirá más detalladamente en el próximo artículo.‎$(OPTIMIZE)*GLOBswitchswitchGLOB

‎Hay otra nueva regla de Jam que forma parte de esta sección dependiente del procesador del motor Jamfile, justo al final:‎

else
{
EXIT "Your platform is unsupported" ;
}

‎La regla imprime la declaración dada y luego detiene la ejecución de Jam. Esto se usa mejor en casos de error grave, como se hizo anteriormente cuando no es X86 o PPC. ‎EXIT$(OSPLAT)

‎La siguiente serie de instrucciones en el motor Jamfile son configuraciones independientes de la plataforma. Lo único realmente nuevo aquí es la definición de los diversos pseudotargets utilizados por el motor Jamfile:‎

# Set up the driverinstall target...this makes it easy to install drivers
# for testing
Always driverinstall ;
NotFile driverinstall ;
InstallDriver driverinstall : $(NAME) ;

# Set up the rmapp target...this removes only the application
Always rmapp ;
NotFile rmapp ;
RmApp rmapp : $(NAME) ;

# Set up the test target...this runs the application in the background
#Always test ;
NotFile test ;
RunApp test : $(NAME) ;

‎Como se mencionó anteriormente al describir el , y las reglas, se define un pseudoobjetivo y luego se pasa a cada regla para que actúe como el destino que se puede pasar a Jam en la línea de comandos para realizar la acción dada. En el caso de RunApp, se utiliza "test", que se configura como un pseudotarget por las llamadas a las reglas De Jam incorporadas y .‎RmAppRunAppInstallDriverAlwaysNotFile

‎ La regla marca un destino para que siempre se actualice, incluso si existe. Esta regla se puede usar con objetivos reales basados en archivos, así como con pseudotargets, aunque en general es más útil con pseudotargets. Si no se usa esta regla, el pseudoobjetivo solo funcionará la primera vez (generalmente cuando se crea por primera vez el objetivo del que depende). ‎Always

‎La regla es la regla que realmente hace que un objetivo sea un pseudoobjetivo, al informar a Jam que no es realmente un archivo, por lo que no se puede construir. Cuando se combina con , esto permite especificar objetivos convenientes al llamar a Jam, de modo que, por ejemplo, eliminará una aplicación creada por el motor Jamfile, "jam test" ejecutará esa aplicación e instalará un controlador en el lugar correcto.‎NotFileAlwaysjam rmappjam driverinstall

‎ Finalmente, la última instrucción en el Motor Jamfile es una llamada a la regla descrita anteriormente:‎BeMain

##-------------------------------------------------------------------
## OK, let's build
##-------------------------------------------------------------------

BeMain $(NAME) : $(SRCS) ;

‎Así que a estas alturas ya deberías entender un poco más sobre Jam y también cómo funciona el misterioso motor Jamfile. Como puede ver, el motor Jamfile realmente no es tan complicado, y en general es bastante más simple que el motor Be makefile (aunque con todos mis comentarios tienen aproximadamente la misma longitud). También debería ser evidente que, aunque Jam es probablemente más complicado que hacer, la funcionalidad adicional es muy útil, y la independencia de la plataforma de la mayoría de los Jamfiles alivia la necesidad de scripts de configuración complicados.‎

‎ El próximo artículo de esta serie será un libro de cocina de Jam que describirá cómo se pueden resolver varios problemas y desafíos de construcción con Jam. El autor ya tiene algunas ideas para algunas "recetas", pero le pediría a cualquiera que lea esto y tenga otros desafíos, por favor envíeme un correo electrónico. Especialmente las cosas que piensas que "no se pueden hacer con Jam". Puede que tenga razón, pero haré todo lo posible para mostrar cómo se puede hacer.‎

‎Terminaré con una pequeña anécdota: con frecuencia veo a personas que trabajan en Haiku quejarse de que "escribiría un Jamfile, pero no sé cómo". Mi esperanza es que al final de esta serie de artículos, nadie tenga que decir eso de nuevo.‎