Clause
← Toda la documentación

El original en inglés ha cambiado desde que se hizo esta traducción, por lo que partes de ella pueden estar desactualizadas. Leer en inglés

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

Compilación

clau compila módulos de Erlang/OTP 29 mediante LLVM a IR verificado, bitcode u objetos nativos. -o/--output enlaza las entradas posicionales (o un objetivo de proyecto seleccionado), su objeto de arranque de entrada y el runtime en un ejecutable (enlazado); las compilaciones de proyecto enlazan los objetivos ejecutables en las salidas de su manifiesto (proyectos). Los objetos emitidos también pueden ejecutarse mediante un arnés de C++ enlazado con el runtime (véase el ejemplo más abajo).

Subconjunto de código fuente aceptado

Módulos con nombre del lenguaje ordinario de OTP 29: cláusulas de función ordenadas con patrones y guards; encajes, constructores, operadores y builtins (builtins); case, if, receive, catch, try ... of ... catch Class:Reason:Stack ... after con trazas de pila, maybe ... else ... end; comprehensions de listas, de binaries y de maps (patrones); records de tupla y records nativos; funs, llamadas locales, remotas y dinámicas (M:F(...), apply/2,3); procesos y puertos. Las llamadas se ejecutan sobre marcos de proceso explícitos con llamadas de cola propias (modelo de ejecución); la recursión de cuerpo está acotada por la pila del proceso (sin límite por defecto), no por la pila nativa. Los módulos que un lote nombra pero no declara proceden de la biblioteca. Los calificadores de encaje en comprehensions de la funcionalidad experimental compr_assign se rechazan como [heap expressions] notimpl.

Atributos aceptados: module, export, file, record de tupla y nativo, export_record, import_record, formas type/spec, doc/moduledoc, behaviour/behavior (behaviours), cualquier atributo informativo (vsn, author, copyright, deprecated, dialyzer, -name(Term) definido por el usuario; se conservan para module_info(attributes)), -import(Module, [F/A, ...]) (importaciones) y -compile con opciones que no cambian nada de lo que emite Clause: {no_auto_import, ...}, opciones de advertencias (nowarn_*, warn_*, {nowarn_unused_function, [...]}) e indicaciones de optimización, depuración e informes (inline, {inline, [F/A]}, {inline_size, N}, {inline_effort, N}, inline_list_funcs, debug_info, deterministic, report*, verbose, ...) y la opción propia de Clause {clause_liveness, strict} (vivacidad estricta). {parse_transform, Module} ejecuta la transformación en el Erlang/OTP del host antes del análisis (parse transforms). on_load, nifs, export_all, otras opciones de compile y los módulos parametrizados se rechazan; el diagnóstico los nombra, por ejemplo [behavior-changing attributes] notimpl [module="m" operation="-compile option export_all"]. Todo módulo recibe module_info/0,1. Los fuentes que empiezan por #! siguen las reglas de escript (módulo implícito y exportación de main/1, -mode aceptado). Las formas type/spec se analizan pero nunca cambian el código generado. Los modos solo sintácticos (--parse-check, --print-ast, --print-source, ...) aceptan la gramática completa.

Vivacidad estricta

-compile({clause_liveness, strict}). indica a la vivacidad de las exportaciones que el módulo nunca nombra el código al que llama mediante sus propios átomos. Sus literales de átomo no conservan exportaciones de otros módulos (su propio nombre sigue conservando las suyas, ya que las tuplas de error lo nombran para format_error/1), sus etiquetas de record no conservan ninguna, y sus builtins que producen átomos y binary_to_term/1,2 no cuentan como fuente de nombres de módulo ni como llamada dinámica. Tampoco puede pasar nombres de otros módulos a builtins que los llaman por nombre, como spawn/4 con un nodo o erlang:get_module_info/1,2. Sus propias llamadas por nombre siguen contando: M:F(...) o apply/3 con un módulo literal y una función determinada en tiempo de ejecución conservan las exportaciones de ese módulo, y las llamadas con un módulo determinado en tiempo de ejecución son llamadas dinámicas que alcanzan los módulos nombrados por los átomos de otros módulos.

La opción no cambia el código generado, solo qué exportaciones conserva un ejecutable. Una promesa incorrecta omite una exportación que el módulo llama por nombre, lo que entonces lanza undef. Los módulos de biblioteca la establecen donde sus átomos son solo datos: epp (nombres de tokens y macros, la máquina, nombres de aplicaciones), erl_error (un átomo de relleno en las listas de argumentos impresas; error_info nombra los módulos del código que lanza el error), erl_features (la lista de funcionalidades de un archivo beam) y file (motivos de error, etiquetas de petición; los módulos nombrados por una petición de E/S son átomos de quien la solicita). Sin ella, el apply/3 de file:io_request/3 y el list_to_atom/1 de epp conservaban todas las exportaciones de un programa que preprocesa un archivo, todo erl_eval incluido; con ella (y las condiciones -if evaluadas en C++), su tiempo de compilación adicional respecto a un hola mundo se reduce aproximadamente un 40%.

Ejecutar el ejemplo de módulos compilados

client:main/1 convierte el ejemplo en un programa:

./build/debug/bin/clau -O2 -o build/demo examples/compile/answer.erl examples/compile/client.erl
./build/demo     # prints 42, -7 and {record,map,binary,list,integer,other}

Los mismos módulos también se ejecutan mediante un arnés de C++. Desde un Developer PowerShell de Windows x64 con el compilador ya construido:

$tool = './build/debug/bin/clau.exe'
& $tool -O0 --emit obj --artifact-dir build/example-aot examples/compile/answer.erl examples/compile/client.erl
cmake -S examples/compile -B build/example-native -G Ninja -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_BUILD_TYPE=Debug "-DGENERATED_DIR:PATH=$((Resolve-Path build/example-aot).Path)"
cmake --build build/example-native
./build/example-native/bin/Debug/compiled_modules.exe

Imprime 42, -7, record, map, binary, list, integer, other, uno por línea. El arnés registra los módulos explícitamente, crea un contexto y decodifica los resultados; es un anfitrión de ejemplo, no un punto de entrada de producción. En Unix se usan build/debug/bin/clau, clang++ y -DGENERATED_DIR="$PWD/build/example-aot". La prueba de CTest codegen_examples ejecuta estas órdenes con cada política.

Otras acciones sobre los mismos fuentes:

& $tool -O2 --emit llvm-ir --artifact-dir build/example-ir examples/compile/answer.erl examples/compile/client.erl
& $tool --print-types --verbose examples/compile/answer.erl examples/compile/client.erl
& $tool --print-ir --print-optimized-ir examples/compile/answer.erl examples/compile/client.erl
& $tool -O2 --no-type-specialization --verbose examples/compile/answer.erl examples/compile/client.erl

Impresión del formato abstracto

--print-abstr (una acción del frontend) imprime cada módulo analizado como las formas del formato abstracto de OTP que epp entregaría a un parse transform, un término de file:consult/1 por línea, los mismos términos que escribe erlc +to_abstr (transforms).

Impresión del código fuente

--print-source (una acción del frontend, como --print-ast) imprime cada módulo analizado como código fuente de Erlang; --print-types imprime el mismo texto con anotaciones de tipos. El impresor (print_source, expression_source, type_source en printing.hpp; compiler/src/printing/source_*) es reutilizable:

Opciones

OpciónComportamiento
--emit obj|llvm-ir|llvm-bcPublica un artefacto por módulo
--artifact-dir DIRRaíz de artefactos (requiere --emit)
-o PATH / --output PATHEnlaza un ejecutable (enlazado); incompatible con --emit
--linker PATH, --runtime-library PATHDriver de Clang y archivo del runtime para -o
--no-cacheNo lee ni escribe las cachés de compilación
--cache-inference-in-dirs PATTERNRepetible: los módulos de los directorios que coinciden conservan sus resultados de inferencia en la caché de compilación, además de los directorios implícitos de aplicaciones de OTP (caché de inferencia)
--build-dir DIRDónde guarda Clause los archivos temporales (bajo DIR/tmp); sustituye el build_dir de cada objetivo de proyecto seleccionado; las entradas posicionales no tienen ninguno sin esta opción (directorio de compilación)
--entry MODULE[:FUNCTION[/ARITY]]Función/1 de entrada del ejecutable (si no, función/0; /0 o /1 selecciona una); se valida en todos los modos de compilación y añade el artefacto de arranque clausev1_start (ejecutables); las inspecciones de IR y de ensamblador omiten entonces lo que no puede alcanzar (vivacidad de las exportaciones)
--target-triple TRIPLEMáquina de destino; --target es la selección de objetivo del proyecto
-O0 / -O2 / -OsCódigo genérico por defecto + LLVM O0 / especialización acotada + LLVM O2 / LLVM Os, sin especialización, una sección por símbolo y eliminación por el enlazador del código y los datos no referenciados
--no-type-specializationDesactiva las variantes independientemente del orden de las opciones
--jobs <n>Optimiza y emite módulos objeto en n hilos (por defecto: todos los hilos de hardware), cada módulo en su propio contexto de LLVM; los objetos son iguales con cualquier cantidad; --jobs 1 y las inspecciones de IR y de ensamblador mantienen todos los módulos en un contexto
--ltoEnlaza los módulos como bitcode con la optimización en tiempo de enlazado de LLD (destinos Windows MSVC y ELF; necesita -o o una compilación de proyecto que enlace) (enlazado)
--keep-exportsMantiene invocables todas las exportaciones de un ejecutable en lugar de omitir las que no puede alcanzar; necesita -o, una compilación de proyecto que enlace o una inspección de IR/ensamblador (vivacidad de las exportaciones)
--shellEnlaza el shell interactivo de Erlang y todos los módulos de biblioteca, manteniendo invocables todas las exportaciones; sin --entry el ejecutable inicia el shell, por lo que clau --shell -o erl sin entradas construye un shell solo sobre la biblioteca; necesita -o o una compilación de proyecto que enlace (shell interactivo)
--fips=PATHFija el programa en modo FIPS con el proveedor FIPS de OpenSSL aportado por el usuario en PATH (módulo y fipsmodule.cnf, copiados junto al ejecutable); implica --with-crypto; un proveedor ausente o mal formado hace fallar la compilación (FIPS)
--with-crypto[=PATH]Enlaza el archivo del runtime de crypto y añade al lote el módulo de biblioteca crypto, para programas que alcanzan crypto solo mediante llamadas dinámicas (los programas que lo llaman se enlazan con él de todos modos); PATH es una instalación o árbol de fuentes de OpenSSL ≥ 3.1.2 para enlazar en lugar del usado para construir Clause; necesita -o o una compilación de proyecto que enlace (crypto)
-gTablas de líneas de Erlang en los objetos y en los ejecutables enlazados (CodeView/PDB en destinos MSVC, DWARF en los demás) (depuración)
--print-ir / --print-optimized-irIR verificado antes/después de las pasadas de LLVM, con las líneas del fuente Erlang como comentarios
--print-asmEl ensamblador del destino de cada módulo tras la cadena seleccionada, con cada tramo de código máquina comentado con la instrucción del IR y la línea de Erlang de la que procede (listados de ensamblador)
--print-typesCada módulo como código fuente de Erlang anotado con los tipos inferidos (semántica); se detiene antes de LLVM
--verboseEventos de las fases [pp], [parse] y [comp] en stderr y después el resumen del índice de directorios [index] ...
--print-stage-times[time] <stage> <subject>: <ms> ms en stderr: plan por manifiesto de proyecto (cargarlo y expandir los patrones de cada objetivo seleccionado), preprocess, parse y transform (módulos con parse transforms) por archivo fuente, compile por lote (número de módulos, objetivo del proyecto), link por ejecutable; (cached) sigue a una etapa que reutilizó un resultado en caché. Antes del total compile de un lote aparecen sus fases con el mismo sujeto: index, calls, liveness (ejecutables e inspecciones con entrada), declared-types, inference-cache (con N of M covered modules reused, caché de inferencia), inference, inference-store, contracts, lower, optimize, emit (las que se ejecutaron; con salida de objetos en varios hilos de --jobs, optimize también mueve cada módulo a su propio contexto de LLVM y lo verifica, y emit verifica y emite los módulos en paralelo). Tras inference: líneas inference pass N con los pasos de trabajo de la pasada sobre el presupuesto de trabajo de la inferencia (N of BUDGET work steps) y cómo terminó (inputs changed, fun results changed, settled, o la pasada final tras pasadas sin estabilizar), nombrando la función en ejecución cuando se agotó el presupuesto, después (en cada pasada tras la primera) ; skipped: N components, W work steps: componentes conservados de su último recorrido porque nada de lo que leían cambió y el trabajo que habían costado esos recorridos (contado en los pasos de trabajo de la pasada), después ; N lattice joins ejecutados por la pasada (se cuentan los anidados), con , costly: C components given term() inputs cuando los componentes recursivos costosos perdieron sus entradas locales (inferencia), y después (en cada pasada que recopiló entradas locales) ; inputs: F functions, S slots changed (kinds) con el tipo de cambio de cada slot de entrada modificado (first desde ninguno, integer bound, union member en el nivel superior, shape, deeper para anidamiento de contenedores, function types, term()) y N fun reads not final (valores fun F/A que leen un resumen que cambió después), después ; graph: N nodes (+M), W widenings desde la pasada anterior y ; clean: C of K components (A inputs differ, B callees differ), X changed, T ms (P% of pass), S work steps: componentes cuyas entradas de miembros y resúmenes de los llamados directos son iguales a los de la pasada anterior, aquellos de ellos cuyos resúmenes cambiaron de todos modos, y el tiempo y trabajo dedicados a ellos; después inference lattice (sin tiempo) con la frecuencia de cada operación del retículo en todas las pasadas (join de dos miembros, contando los anidados, widen, meet, within, subtract, truncate) y cuántas llamadas repitieron una con los mismos operandos antes en su pasada y en cualquier pasada (las respuestas que conserva el grafo las atienden, y las operaciones que una respuesta ejecutó de forma anidada no se ejecutan ni se cuentan otra vez), después las uniones de una cantidad de miembros distinta de dos y las consultas de anidamiento de contenedores con aquellas cuya respuesta conservó el grafo (rastrear repeticiones ralentiza la inferencia perfilada aproximadamente un 7%); después inference churn con el tiempo dedicado a recopilar entradas y cuántos slots de entrada locales cambiaron una vez, dos veces, ... en todas las pasadas, e inference churned <module>:<function>/<arity> #<argument> (sin tiempo) para los 10 slots con más cambios, con el tipo de su último cambio y los hechos antes y después de él (cada uno recortado a 200 caracteres); después (sin tiempo) hasta 10 componentes inference clean-changed <module>:<function>/<arity> que estaban limpios pero cambiaron, con la pasada que lo observó primero y cuántas veces (una dependencia distinta de las entradas y las llamadas directas, como fun F/A); después (sin tiempo) inference facts N tras cada pasada que recopiló entradas: los hechos de cada resumen y entrada local, su tamaño de árbol máximo y medio (nodos contados una vez por ruta), la unión más ancha, cuántos alcanzan los presupuestos de profundidad de contenedores, miembros de unión y elementos de tupla/map, los resúmenes con más tipos de función (32) y los hechos dependientes; después inference largest con el mayor hecho de cada uno de los 3 componentes que más tardaron (recortado a 200 caracteres); después inference slowest <module>:<function>/<arity> para las 10 funciones (los grupos recursivos nombran un miembro and N more) que más tardaron en el conjunto de las pasadas, con sus pasos de trabajo y la parte de ese trabajo respecto al presupuesto de las pasadas que las ejecutaron (877450 work steps, 43.9% of 10 passes of 200000 budget), widened to term() cuando un presupuesto amplió uno de sus hechos, y las uniones del retículo que ejecutaron sus recorridos y los nodos del grafo que crearon; después inference costliest <module>:<function>/<arity> para las 10 funciones de al menos 10 ms que más tardaron por paso de trabajo, con ese tiempo en microsegundos, sus pasos de trabajo, uniones del retículo (y uniones por paso de trabajo) y nodos creados; después inference rounds <module>:<function>/<arity> and N more para los 10 grupos recursivos más lentos: resoluciones en el conjunto de las pasadas, rondas ejecutadas frente al tope por resolución (8 + 4 por miembro), resoluciones que alcanzaron el tope o gastaron su octava parte del presupuesto de la pasada (todos los miembros ampliados a term()), resoluciones que se abandonaron de inmediato porque una pasada anterior lo hizo (remembered) o terminaron con el presupuesto de la pasada agotado, recorridos de miembros (y los omitidos porque nada de lo que leen cambió, y los reproducidos: una resolución posterior repitió el último recorrido del miembro porque nada de lo que leía cambió) y la parte de recorridos y reproducciones que cambió un resumen (creció, cambiaron entradas de tipo función o volvió a uno de los últimos 4 resúmenes del miembro), y los miembros cambiados por ronda de la última resolución en diez grupos de rondas, después ; N solves repeated the previous fixed point, M reached it after R rounds in total: resoluciones que terminaron con los resúmenes con los que terminó la pasada anterior, y resoluciones que los alcanzaron antes de converger, con las rondas que necesitaron (las que se omitirían al partir de ellos). Una compilación en caché no imprime fases
--asn1-option OPTION, --asn1-outdir DIR, --generate-asn1Compila entradas .asn/.asn1/.set.asn en Module.erl y Module.hrl con una opción de asn1ct (repetible), en DIR (se añade a la ruta de inclusión), o solo los genera (ASN.1)
--print-envImprime en stdout el entorno de compilación resuelto como TOML y termina sin procesar fuentes (informe del entorno)
--print-inputsPreprocesa y analiza las entradas, añade los módulos que nombran como hace la compilación y después enumera en stdout cada fuente del lote y se detiene antes de la compilación (proyectos)

Listados de ensamblador

--print-asm ejecuta la cadena seleccionada (como hace --print-optimized-ir) y después imprime el ensamblador de cada módulo de entrada desde la misma máquina de destino que escribe los objetos, un módulo cada vez. Los comentarios usan el marcador del destino (# en x86, // en AArch64 ELF, ; en Apple, @ en ARM):

# erlang answer.erl:3: value() -> 42.
#     ir store i64 687, ptr %frame.slots, align 8
	movq	$687, 32(%r15,%r12,8)
#     ir br i1 %4, label %return.inline, label %return.service

Informe del entorno

--print-env valida toda la línea de órdenes (conflictos, entradas posicionales legibles, planificación del proyecto) y después imprime lo que usaría esa orden como un documento TOML en stdout, termina con 0 y no lee ningún fuente. Las rutas son absolutas, con /.

# clau compile environment (--print-env)
command = ["clau", "--print-env", "-O2", "-o", "app", "main.erl"]  # as given
actions = ["link"]          # see below
working_directory = "/work"

[[targets]]                 # one per selected project target; one for positional inputs
name = "app"                # project targets only
project = "/work/project.toml"
sources = ["/work/src/main.erl"]           # globs and search paths resolved
library_directory = "/clau/library"     # application dirs, searched before source_search_paths
build_dir = "/work/build"   # "" for positional inputs without --build-dir
entry = "main:main"         # or "auto" when linking without --entry
output = "/work/app"        # linking only: final name (".exe" on Windows)
linker = "/usr/bin/clang++" # linking only; "" when none is found
runtime_library = "/clau/lib/libclause_runtime.a"

[targets.options]           # manifest option names
source_search_paths = []    # directories, patterns expanded
include_dirs = []           # search order, patterns expanded
defines = []
applications = { "stdlib" = "/otp/lib/stdlib" }  # last mapping wins
enabled_features = ["maybe_expr"]                # OTP defaults plus changes

[targets.backend]
target_triple = "x86_64-unknown-linux-gnu"  # host when not given
optimization = "O2"
type_specialization = true  # O2 without --no-type-specialization
debug_info = false
lto = false
keep_exports = false        # --keep-exports or the project option
shell = false               # --shell or the project option
emit = "none"               # or obj, llvm-ir, llvm-bc
artifact_dir = "/work/build/aot"

(Los arrays imprimen un elemento por línea.) actions enumera las acciones del frontend (print-pp, parse-check, print-ast, print-source, print-abstr, si no preprocess-check; print-inputs las sustituye por sí sola), si no las inspecciones (print-types, print-ir, print-optimized-ir, print-asm), si no emit, link (-o) o compile. En una compilación de proyecto, los objetivos con un output también enlazan. Los módulos encontrados más tarde por nombre (mediante source_search_paths o la biblioteca) no se enumeran: encontrarlos requiere el análisis sintáctico (eso lo hace --print-inputs). --print-env no puede combinarse con --new-project.

Caché de compilación

Un lote con directorio de compilación (cada objetivo de proyecto, las entradas posicionales con --build-dir) guarda el resultado de su compilación en la caché de compilación: los diagnósticos en orden, el fallo y, cuando un ejecutable o --emit los necesitan, los objetos (o el bitcode) de cada módulo y del módulo de arranque. Una compilación posterior del mismo lote con las mismas opciones reproduce los diagnósticos y enlaza o publica los objetos conservados exactamente igual que los nuevos; --print-stage-times muestra entonces [time] compile ... (cached). --print-ir, --print-optimized-ir, --print-asm y --print-types siempre recalculan, y --no-cache ni lee ni escribe.

Backend

SDK de LLVM

LLVM estable 23.1.x, como mínimo 23.1.1. LLVM es una dependencia del anfitrión: la arquitectura, la biblioteca estándar de C++ y el CRT de Windows deben coincidir con los de la herramienta del compilador. El código del proyecto mantiene excepciones/RTTI; ninguna excepción puede propagarse a través de LLVM. El runtime nunca usa LLVM.

Configuración de referencia en Windows x64: clang-cl 23.1.2 del anfitrión en C:/Program Files/LLVM/bin, SDK thirdparty/clang+llvm-23.1.2-x86_64-pc-windows-msvc, herramientas x64 de Visual Studio 18, Windows SDK 10.0.26100.0, Ninja, /MT, _ITERATOR_DEBUG_LEVEL=0. La selección automática aplica /MT y los ajustes de iteradores; un LLVM_DIR explícito no lo hace, y entonces la prueba de enlazado falla.

PCRE2

Los builtins re del runtime usan PCRE2 10.47, la versión que incluye OTP 29 (erts/emulator/pcre/vendor.info), de modo que la sintaxis de patrones, las opciones y las capturas se comportan como en OTP: unidades de código de 8 bits, soporte de Unicode, sin JIT, pcre2_match estándar (no se traslada el parche de cesión de OTP). PCRE2 tiene licencia BSD-3-Clause con la excepción de PCRE2 para binarios compilados; no se incluye en el repositorio ningún archivo de PCRE2. CMake (cmake/Pcre2Dependencies.cmake) lo resuelve en este orden:

  1. -DCLAUSE_PCRE2_ROOT=<source directory> tiene prioridad (sin descarga); la versión de su configure.ac debe ser 10.47.
  2. Un PCRE2 instalado de al menos 10.47 (CLAUSE_PCRE2_SYSTEM=ON, por defecto): el paquete de CMake (find_package(pcre2 CONFIG COMPONENTS 8BIT), con preferencia por las bibliotecas estáticas) o, si no, libpcre2-8 de pkg-config, con preferencia por una libpcre2-8.a estática frente a la biblioteca compartida.
  3. La versión fijada, descargada en thirdparty/pcre2-10.47 y verificada (pcre2-10.47.tar.bz2, SHA-256 47fe8c99461250d42f89e6e8fdaeba9da057855d06eb7fc08d9ca03fd08d7bc7); -DCLAUSE_DOWNLOAD_PCRE2=OFF desactiva la descarga.

Un directorio de fuentes (1 o 3) construye la biblioteca de objetos clause_pcre2 a partir de los archivos .c enumerados con los config.h.generic, pcre2.h.generic y pcre2_chartables.c.dist distribuidos, copiados en el árbol de compilación (sin paso de generación, sin las opciones de advertencia del proyecto, fuera de clang-tidy y Lizard), y sus objetos se añaden al propio clause_runtime: el archivo es autosuficiente y todo consumidor (los enlazados de clau, los programas de prueba anidados, runtime_link, examples/compile) obtiene PCRE2 con él. Una biblioteca instalada, en cambio, se convierte en una entrada adicional del enlazador registrada en clause_runtime.link junto al archivo (una entrada por línea), que clau añade a cada enlazado; una biblioteca compartida hace que los ejecutables dependan de ella en tiempo de ejecución. Por plataforma: Windows usa la descarga (en la práctica no se busca ningún PCRE2 del sistema); Linux y macOS usan un PCRE2 10.47 o posterior instalado cuando existe y, si no, la descarga. PCRE2 siempre se enlaza en el runtime, también en los programas que nunca llaman a re.

zlib

El módulo zlib del runtime y los términos externos comprimidos usan zlib 1.3.2, la versión que incluye OTP 29 (erts/emulator/zlib/vendor.info), de modo que los bytes comprimidos son iguales a los de OTP. CMake compila sus fuentes de biblioteca (cmake/ZlibDependencies.cmake, clause_add_runtime_zlib) en la biblioteca de objetos clause_runtime_zlib, cuyos objetos se unen a clause_runtime como los de PCRE2; -DCLAUSE_RUNTIME_ZLIB_ROOT=<source directory> tiene prioridad y, si no, la versión se descarga en thirdparty/zlib-1.3.2 y se verifica (SHA-256 bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16) en todos los anfitriones. La licencia de zlib es la licencia zlib. El LLVM del compilador conserva su propia zlib; ambas nunca coinciden en un mismo binario.

zstd

El módulo zstd del runtime usa zstd 1.5.7, la versión que incluye OTP 29 (erts/emulator/zstd/vendor.info), de modo que las tramas son iguales a las de OTP. CMake compila sus fuentes de biblioteca (common, compress, decompress; con un solo hilo, sin el decodificador en ensamblador; cmake/ZstdDependencies.cmake, clause_add_runtime_zstd) en la biblioteca de objetos clause_runtime_zstd, cuyos objetos se unen a clause_runtime como los de zlib; -DCLAUSE_RUNTIME_ZSTD_ROOT=<source directory> tiene prioridad y, si no, la versión se descarga en thirdparty/zstd-1.5.7 y se verifica (SHA-256 eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3), el mismo archivo que usa la compilación de LLVM para Windows. La licencia de zstd es BSD-3-Clause (o GPL-2.0).

OpenSSL

Los builtins crypto del runtime usan libcrypto de OpenSSL, con la versión 4.1.0 fijada, aceptando cualquier versión desde 3.1.2 (la última con un proveedor validado para FIPS), en un archivo separado clause_runtime_crypto que solo enlazan los programas que llaman a crypto. Su procedencia, cómo Clause y clau lo construyen desde los fuentes, el enlazado (--with-crypto[=PATH]) y el modo FIPS (--fips=PATH) se describen en crypto.

Otros requisitos previos: CMake ≥ 3.28, un compilador de C++23, Boost ≥ 1.90, toml++ 3.4.0 y las herramientas de calidad. OTP solo es necesario para auditorías opcionales y para regenerar fixtures.