Clause
← Toda la documentación

Traducido del original en inglés · 1e3a39c8-dirty · 2026-10-26 · Leer en inglés

Ejecutables

Contrato de los programas construidos con clau -o o con una compilación de proyecto. Las entradas posicionales, o exactamente un objetivo de proyecto seleccionado, se enlazan en la ruta de -o; una compilación de proyecto enlaza cada objetivo ejecutable seleccionado en el output de su manifiesto (enlazado, proyectos).

Selección de la entrada

La entrada es una función exportada de aridad 1 que recibe la lista de argumentos. Un FUNCTION seleccionado sin FUNCTION/1 puede ser en su lugar un FUNCTION/0 exportado: se ejecuta sin los argumentos del programa (las opciones del runtime se siguen extrayendo). Un sufijo /0 o /1 selecciona solo esa aridad, así que --entry benchmarks:run/0 ejecuta run/0 aunque run/1 también esté exportada. Por defecto (sin selección) es siempre main/1.

OrigenEscrituraAlcance
CLI--entry MODULE[:FUNCTION[/ARITY]]Lote posicional, o el único objetivo de proyecto seleccionado
Manifiestoentry = "MODULE[:FUNCTION[/ARITY]]" en una tabla [[targets]]Ese objetivo
Por defectoEl único escript; si no, el único módulo que exporta main/1Solo cuando se pide un ejecutable (-o, o un objetivo de proyecto con output)
FalloDiagnóstico (salida 1)
Módulo ausente del lote<origin>: entry module M is not among the compiled modules (origin: --entry o el manifiesto file:line:col [target t] (entry))
No hay F/1 ni F/0<file>:<line>:<col>: entry function M:F/1 is not defined en la declaración del módulo
Falta el F/A explícito... entry function M:F/A is not defined; found F/N en una definición con el mismo nombre; si no, en la declaración del módulo
Solo otras aridades... is not defined; found F/N, but the entry takes the argument list (FUNCTION/1) or nothing (FUNCTION/0) en esa definición
F/1 (si no, F/0) no exportada<file>:<line>:<col>: entry function M:F/A is not exported en la definición
Sin selección, ninguna exportación de main/1no entry point: no module exports main/1; choose the entry with --entry MODULE[:FUNCTION[/ARITY]] (an exported FUNCTION/1, or FUNCTION/0 run without the program arguments; FUNCTION defaults to main, ARITY to 1, else 0)
Sin selección, variasambiguous entry point: main/1 is exported by a, b; choose the entry with ... (la misma indicación)

Para los objetivos de proyecto, la indicación también nombra la clave del manifiesto: ... --entry MODULE[:FUNCTION[/ARITY]] or with entry = "MODULE[:FUNCTION[/ARITY]]" in this target's [[targets]] table of the project manifest ..., por ejemplo:

[[targets]]
name = "app"
sources = ["src/*.erl"]
entry = "app:start"   # calls app:start/1 (or app:start/0); "app:start/0" calls app:start/0; plain "app" calls app:main/1

Argumentos

Entry(Argv) recibe una lista propia de cadenas (listas de puntos de código Unicode), sin el nombre del programa ni las opciones del runtime iniciales, por lo demás sin cambios y en orden, como escript.

Opciones del runtime

El runtime lee sus opciones de la variable de entorno CLAUSE_FLAGS (palabras separadas por espacios y tabuladores, sin comillas) y después de los argumentos iniciales de la línea de órdenes, así que la línea de órdenes prevalece. Ambas se analizan igual; un valor va en el argumento siguiente o después de =.

OpciónEfecto
--max-atoms NTamaño de la tabla de átomos, de 1 a 2^26 (67.108.864); por defecto 2^20 (1.048.576), como +t de OTP
--max-heap BYTESLímite del bloque de heap, los fragmentos y los binaries off-heap de cada proceso, como mínimo el heap mínimo (233 palabras); sin límite por defecto
--max-stack BYTESLímite de la pila de marcos de cada proceso; sin límite por defecto
--min-heap-size WORDSmin_heap_size por defecto de cada proceso, como mínimo 1, redondeado hacia arriba a un tamaño de heap, como +hms de OTP; como máximo --max-heap; por defecto 233 (dimensionamiento)
--max-memory BYTESLímite de la memoria de todos los procesos juntos (heaps, binaries off-heap, pilas); sin límite por defecto
--schedulers NHilos de trabajo del planificador que ejecutan procesos, de 1 a 1.024; por defecto uno por CPU de --scheduler-cpus o, en su defecto, uno por procesador lógico en el que puede ejecutarse el programa (su máscara de afinidad), como los planificadores en línea de OTP (hilos de trabajo)
--scheduler-cpus SETVincula el hilo de trabajo N a la N-ésima CPU de SET, de forma cíclica, como +sbt/+sct de OTP: performance (la clase de núcleos más rápida: núcleos P de una CPU híbrida, todas las CPU en los demás casos), all o una lista como 0-15 o 2,4,6; todas las CPU enumeradas deben estar en la máscara de afinidad. Sin vinculación por defecto (vinculación a CPU)
--profile FILEEscribe en FILE, cuando termina el programa, un informe de entradas y tiempo propio por función y por proceso (perfilado); desactivado por defecto
--args-file FILEArchivo de opciones como vm.args de OTP: reservado, informa runtime option --args-file is not implemented
--Termina las opciones del runtime; los argumentos siguientes van todos a Entry

En la línea de órdenes, el análisis se detiene en el primer argumento que no es una opción del runtime, así que prog data --max-atoms 9 pasa los tres argumentos al programa. En CLAUSE_FLAGS cada palabra debe ser una opción del runtime. Un valor no válido, una palabra de la variable que no es una opción, o --args-file detienen el programa antes de registrar ningún módulo: clau: runtime failure: <reason>, salida 70. El número de procesos no está limitado y la memoria no tiene límite por defecto. Los valores en bytes son decimales sin sufijos y se redondean hacia abajo a palabras completas; un programa que alcanza un límite falla con resource_limit, salida 70 (límite de memoria del runtime).

Estado de salida

ResultadoEstado
La entrada retorna (cualquier valor)0
erlang:halt()0
erlang:halt(N), entero no negativoN (los sistemas POSIX conservan los 8 bits bajos)
erlang:halt(Slogan) con una cadenaSlogan en stderr, después 1 (sin volcado de fallo)
erlang:halt(abort)Aborto nativo (sin vaciado de búferes)
Cualquier excepción que escape de la entrada, incluidos throw y exit(normal)Informe en stderr, 1
Proceso de entrada terminado por una señal de salida (procesos)Se informa como un exit no capturado, 1; razón normal: 0
Fallo de arranque o de infraestructura del runtime (ABI incompatible, registro, memoria antes de la entrada)Mensaje en stderr, 70
Memoria del sistema agotada (crecimiento de heap, de binary off-heap o de pila rechazado; sin límite de memoria por defecto, agotamiento de memoria)clau: runtime failure: entry call failed: out_of_memory, 70

Los argumentos no válidos de halt/1 lanzan badarg en quien llama. Cuando la entrada termina, el programa sale: los demás procesos se detienen sin seguir ejecutándose, como con halt/1 de OTP después de que escript retorne. Un halt en cualquier proceso termina el programa con su estado, y un fallo del runtime en cualquier proceso lo termina con 70; una excepción en un proceso lanzado con spawn solo termina ese proceso (procesos).

halt/0,1, error/1,2,3, exit/1 y throw/1 se pueden llamar con o sin el prefijo erlang:; una definición local o -compile({no_auto_import, ...}) mantiene local el nombre sin cualificar, como en OTP. halt/2 no está disponible. halt(N) conserva los 31 bits bajos de cualquier entero no negativo, como hace OTP. Un slogan es una lista propia de como máximo 1.023 puntos de código Unicode. Un halt desenrolla la entrada a través del canal de errores comprobado como un error, así que solo detiene el programa después de la limpieza generada.

Flujos de salida

Objeto de arranque

Compilar con una entrada explícita (--entry o entry del manifiesto) añade un módulo de arranque después de los módulos del lote. Con --emit se publica como clausev1_start.{obj,o,ll,bc} junto a los artefactos de los módulos (el nombre no puede colisionar con el artefacto de un módulo). Contiene un abi::v1::StartupDescriptor constante (startup.hpp): revisión de la ABI, ancho de término, todos los descriptores de módulo en el orden del código fuente, las grafías del módulo y la función de entrada y un indicador de escript. Su int main(int, char **) llama al CLAUSE_main_v1 del runtime, que:

  1. Comprueba la revisión de la ABI y el ancho del descriptor de arranque y de cada descriptor de módulo antes de registrar nada; una discrepancia sale con 70.
  2. Arranca el runtime y registra todos los módulos; cualquier fallo se detiene antes de la entrada y descarta el runtime (salida 70), de modo que ningún código Erlang se ejecuta sobre un lote parcial.
  3. Crea el proceso de entrada, construye argv y encola la llamada a M:F/1 como proceso principal; después lo ejecuta, junto con todos los procesos que lanza, en los hilos de trabajo del planificador (procesos) hasta que termina.
  4. Convierte el resultado en el estado de salida descrito arriba, imprimiendo los informes después de vaciar stdout; después libera todos los procesos y apaga el runtime en todas las rutas (excepto halt(abort)).

clau -o enlaza estos objetos por sí mismo (enlazado). Enlazado manual (la receta del harness nativo sin fuente de harness):

& $tool --emit obj --entry app --artifact-dir build/app app.erl helper.erl
clang-cl /MT build/app/*.obj build/debug/lib/clause_runtime.lib /Fe:app.exe

Cualquier enlazado compatible con Clang de los objetos con Clause::generated_program funciona igual (véase tests/compiler/linking/startup.cmake).

Enlazado

clau [-O0|-O2|-Os] -o PATH a.erl b.erl ... (o --project FILE [--target T] -o PATH para un objetivo seleccionado) compila el lote en memoria, añade el objeto de arranque para la entrada y enlaza un ejecutable:

clau -O2 -o build/demo examples/compile/answer.erl examples/compile/client.erl
./build/demo          # build/demo.exe on Windows

-Os además coloca cada función y objeto de datos generados y del runtime en su propia sección y enlaza con --gc-sections (ELF), -dead_strip (Mach-O) o /OPT:REF /OPT:ICF (MSVC), de modo que se elimina el código al que no llega ninguna ruta desde la entrada.

--lto compila los módulos y el módulo de arranque a bitcode de LLVM en lugar de a objetos y enlaza con -flto -fuse-ld=lld, de modo que LLD optimiza el código generado del programa como una sola unidad frente al archivo nativo del runtime. Los descriptores de módulo y de arranque, las entradas exportadas y main siguen referenciados y se conservan; los programas se comportan igual que sin la opción. Solo LLD lee el bitcode de este compilador, así que --lto se acepta para destinos Windows MSVC y ELF; los demás fallan antes del enlazado con --lto is not supported for target <triple>: it needs LLD. --lto necesita una salida ejecutable (-o o una compilación de proyecto que enlace). Clang/LLD instalados deben ser de la misma versión de LLVM que clau (23.1).

Vivacidad de las exportaciones

Un ejecutable omite las exportaciones que no puede alcanzar, de modo que el dead-stripping de -Os y --lto eliminan el código de biblioteca al que el programa nunca llama. Justo después de la resolución de llamadas, antes de la inferencia de tipos, un análisis de todo el lote empieza en la función de entrada y marca como vivo todo lo que una función viva llama directamente (también mediante -import y las autoimportaciones de OTP), cada fun F/A y cada fun M:F/A literal, y los destinos literales de apply/3, spawn/3, spawn_link/3, spawn_monitor/3, spawn_opt/4,5, spawn_request/3,5, hibernate/3 y make_fun/3 (todas las aridades de M:F cuando la lista de argumentos no es literal), y file:write/2 en cuanto io:format/3, io:fwrite/3, io:put_chars/2 o io:nl/1 está vivo (sus builtins escriben mediante ella en un dispositivo de proceso). Es conservador:

Una función a la que nada vivo llega no recibe ningún código. Una exportación omitida conserva su nombre en la tabla de exportaciones del módulo sin código, de modo que function_exported/3 y module_info(exports) responden como si estuviera exportada, mientras que una llamada dinámica que la alcance lanza undef (diferencias). Eso solo puede ocurrir cuando un nombre de módulo procede de fuera del análisis: una traza de pila, un término de excepción o datos externos al programa. --verbose traza el resultado por módulo (phase=liveness detail="dropped-exports=3", o detail="kept-all-exports reason='m' is used as a value in main:main/1").

Una función a la que nada vivo llega tampoco se infiere nunca ni se comprueba frente a su -spec: la inferencia cubre solo el código vivo, lo que es más rápido para programas que usan poco de módulos de biblioteca grandes y solo puede estrechar los hechos de las funciones vivas, ya que los llamantes inalcanzables ya no unen sus argumentos. Por tanto, una especificación contradicha solo en código inalcanzable se informa para los artefactos de --emit, pero no para el ejecutable.

--keep-exports (o la opción de proyecto keep_exports = true) mantiene invocables todas las exportaciones. El análisis se aplica a los ejecutables (-o o una compilación de proyecto que enlace) y a las inspecciones de IR y ensamblador con una entrada (--entry o el entry del manifiesto del objetivo), que entonces muestran el código del ejecutable; los artefactos de --emit, destinados a otros programas, conservan todas las exportaciones.

-g conserva las tablas de líneas de Erlang para los depuradores: en el ejecutable (ELF) o en un <name>.pdb publicado junto a él (destinos MSVC) (depuración).

Fallo (salida 1)Diagnóstico
No hay Clangcannot find clang++ or clang on PATH; install LLVM/Clang or pass --linker / linker not found: X
No hay runtimeruntime library not found: P; build the clause_runtime target or pass --runtime-library
No es un archivoruntime library is not a static library: P: ...
Destino incorrectoruntime library P contains x86_64 coff objects, but the executable targets T; ...
Error de enlazadolinking O failed: <clang> exited with status N: seguido de la salida del enlazador (los primeros 64 KiB)
Destino de salida incorrectooutput directory does not exist: D, artifact destination is not a regular file: O, artifact destination aliases an input: O

Escripts

Un archivo fuente cuya primera línea empieza por #! se compila como escript, en cualquier modo y con cualquier nombre de archivo (entradas posicionales o archivos .erl de proyecto). Las reglas siguen el escript de OTP 29 para scripts en código fuente:

Comparación con OTP

Los goldens de los fixtures de programas ejecutan la entrada bajo OTP con las mismas reglas (oráculo); el mismo oráculo genera los casos golden de ejecutables que el ejecutor de extremo a extremo enlaza y ejecuta con cada política. Diferencias con escript para los módulos ordinarios: las excepciones no capturadas salen con 1 en lugar de 127, y main/1 debe estar exportada. Los fuentes de escript conservan las reglas de OTP (véase arriba).