Clause
← Toda a documentação

O original em inglês mudou desde esta tradução, pelo que partes dela podem estar desatualizadas. Ler em inglês

Traduzido do original em inglês · 1e3a39c8-dirty · 2026-10-26

Compilação

O clau compila módulos Erlang/OTP 29 através do LLVM para IR verificada, bitcode ou objetos nativos. -o/--output liga as entradas posicionais (ou um alvo de projeto selecionado), o respetivo objeto de arranque de entrada e o runtime num executável (ligação); as compilações de projetos ligam os alvos executáveis às saídas do seu manifesto (projetos). Os objetos emitidos também podem correr através de um harness C++ ligado ao runtime (ver o exemplo abaixo).

Subconjunto de código-fonte aceite

Módulos com nome da linguagem comum do OTP 29: cláusulas de função ordenadas com padrões e guards; correspondências, construtores, operadores e builtins (builtins); case, if, receive, catch, try ... of ... catch Class:Reason:Stack ... after com rastreios de pilha, maybe ... else ... end; comprehensions de lista, binary e map (padrões); records em tuplo e native records; funs, chamadas locais, remotas e dinâmicas (M:F(...), apply/2,3); processos e portas. As chamadas correm sobre frames de processo explícitos com chamadas de cauda próprias (modelo de execução); a recursão no corpo é limitada pela pilha do processo (sem limite por omissão), não pela pilha nativa. Os módulos que um lote nomeia mas não declara vêm da biblioteca. Os qualificadores de correspondência em comprehensions da funcionalidade experimental compr_assign são rejeitados como [heap expressions] notimpl.

Atributos aceites: module, export, file, record em tuplo e nativo, export_record, import_record, formas de type/spec, doc/moduledoc, behaviour/behavior (behaviours), qualquer atributo informativo (vsn, author, copyright, deprecated, dialyzer, -name(Term) definido pelo utilizador; mantidos para module_info(attributes)), -import(Module, [F/A, ...]) (imports) e -compile com opções que não alteram nada do que o Clause emite: {no_auto_import, ...}, opções de avisos (nowarn_*, warn_*, {nowarn_unused_function, [...]}) e sugestões de otimização, depuração e relatório (inline, {inline, [F/A]}, {inline_size, N}, {inline_effort, N}, inline_list_funcs, debug_info, deterministic, report*, verbose, ...) e a opção própria do Clause {clause_liveness, strict} (vivacidade estrita). {parse_transform, Module} executa o transform no Erlang/OTP do anfitrião antes da análise (parse transforms). on_load, nifs, export_all, outras opções de compile e os módulos parametrizados são rejeitados; o diagnóstico indica-os, por exemplo [behavior-changing attributes] notimpl [module="m" operation="-compile option export_all"]. Todos os módulos recebem module_info/0,1. Os códigos-fonte que começam por #! seguem as regras de escript (módulo implícito e exportação de main/1, -mode aceite). As formas type/spec são analisadas, mas nunca alteram o código gerado. Os modos só de sintaxe (--parse-check, --print-ast, --print-source, ...) aceitam a gramática completa.

Vivacidade estrita

-compile({clause_liveness, strict}). indica à vivacidade dos exports que o módulo nunca nomeia o código que chama através dos seus próprios átomos. Os seus literais de átomo não mantêm exports de outros módulos (o seu próprio nome continua a manter os seus, pois os tuplos de erro nomeiam-no para format_error/1), as suas tags de record não mantêm nenhum, e os seus builtins que produzem átomos e binary_to_term/1,2 não contam como fonte de nomes de módulos nem como chamada dinâmica. Também não pode passar nomes de outros módulos a builtins que os chamam pelo nome, como spawn/4 com um nó ou erlang:get_module_info/1,2. As suas próprias chamadas pelo nome continuam a contar: M:F(...) ou apply/3 com um módulo literal e uma função em tempo de execução mantêm os exports desse módulo, e as chamadas com um módulo em tempo de execução são chamadas dinâmicas, alcançando os módulos que os átomos de outros módulos nomeiam.

A opção não altera o código gerado, apenas os exports que um executável mantém. Uma promessa errada deixa de fora um export que o módulo chama pelo nome, o que depois lança undef. Os módulos da biblioteca definem-na onde os seus átomos são apenas dados: epp (nomes de tokens e macros, a máquina, nomes de aplicações), erl_error (um átomo de substituição nas listas de argumentos impressas; error_info nomeia os módulos do código que lança o erro), erl_features (a lista de funcionalidades de um ficheiro beam) e file (motivos de erro, tags de pedidos; os módulos nomeados num pedido de io são átomos de quem o faz). Sem ela, o apply/3 de file:io_request/3 e o list_to_atom/1 de epp mantinham todos os exports de um programa que pré-processa um ficheiro, incluindo todo o erl_eval; com ela (e as condições -if avaliadas em C++), o tempo de compilação adicional face a um hello-world diminui cerca de 40%.

Correr o exemplo de módulos compilados

client:main/1 faz do exemplo um 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}

Os mesmos módulos também correm através de um harness C++. A partir de uma Developer PowerShell do Windows x64 com o compilador compilado:

$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, um por linha. O harness regista os módulos explicitamente, cria um contexto e descodifica os resultados; é um anfitrião de exemplo, não um ponto de entrada de produção. Em Unix, use build/debug/bin/clau, clang++ e -DGENERATED_DIR="$PWD/build/example-aot". O teste CTest codegen_examples executa estes comandos em todas as políticas.

Outras ações sobre os mesmos códigos-fonte:

& $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

Impressão do formato abstrato

--print-abstr (uma ação do frontend) imprime cada módulo analisado como as formas do formato abstrato do OTP que o epp entregaria a um parse transform, um termo file:consult/1 por linha, os mesmos termos que erlc +to_abstr escreve (transforms).

Impressão do código-fonte

--print-source (uma ação do frontend, como --print-ast) imprime cada módulo analisado como código-fonte Erlang; --print-types imprime o mesmo texto com anotações de tipos. O impressor (print_source, expression_source, type_source em printing.hpp; compiler/src/printing/source_*) é reutilizável:

Opções

OpçãoComportamento
--emit obj|llvm-ir|llvm-bcPublica um artefacto por módulo
--artifact-dir DIRRaiz dos artefactos (requer --emit)
-o PATH / --output PATHLiga um executável (ligação); incompatível com --emit
--linker PATH, --runtime-library PATHDriver do Clang e arquivo do runtime para -o
--no-cacheNão lê nem escreve as caches de compilação
--cache-inference-in-dirs PATTERNRepetível: os módulos em diretórios correspondentes guardam os seus resultados de inferência na cache de compilação, além dos diretórios implícitos das aplicações OTP (cache de inferência)
--build-dir DIROnde o Clause guarda ficheiros temporários (abaixo de DIR/tmp); substitui o build_dir de cada alvo de projeto selecionado; as entradas posicionais não têm nenhum sem esta opção (diretório de compilação)
--entry MODULE[:FUNCTION[/ARITY]]Função/1 de entrada do executável (caso contrário função/0; /0 ou /1 seleciona uma); validada em todos os modos de compilação e acrescenta o artefacto de arranque clausev1_start (executáveis); as inspeções de IR e de assembly deixam então de fora o que ela não consegue alcançar (vivacidade dos exports)
--target-triple TRIPLEMáquina alvo; --target é a seleção do alvo do projeto
-O0 / -O2 / -OsCódigo genérico por omissão + LLVM O0 / especialização limitada + LLVM O2 / LLVM Os, sem especialização, uma secção por símbolo e eliminação pelo ligador do código e dos dados não referenciados
--no-type-specializationDesativa as variantes independentemente da ordem das opções
--jobs <n>Otimiza e emite módulos objeto em n threads (por omissão: todas as threads de hardware), cada módulo no seu próprio contexto LLVM; os objetos são iguais para qualquer número; --jobs 1 e as inspeções de IR e assembly mantêm todos os módulos num contexto
--ltoLiga os módulos como bitcode com otimização em tempo de ligação do LLD (alvos Windows MSVC e ELF; exige -o ou uma compilação de projeto com ligação) (ligação)
--keep-exportsMantém todos os exports de um executável chamáveis em vez de deixar de fora os que ele não consegue alcançar; exige -o, uma compilação de projeto com ligação ou uma inspeção de IR/assembly (vivacidade dos exports)
--shellLiga a shell interativa de Erlang e todos os módulos da biblioteca, mantendo todos os exports chamáveis; sem --entry, o executável inicia a shell, pelo que clau --shell -o erl sem entradas compila uma shell apenas sobre a biblioteca; exige -o ou uma compilação de projeto com ligação (shell interativa)
--fips=PATHFixa o programa no modo FIPS com o fornecedor FIPS do OpenSSL fornecido pelo utilizador em PATH (módulo e fipsmodule.cnf, copiados para junto do executável); implica --with-crypto; um fornecedor em falta ou mal formado faz falhar a compilação (FIPS)
--with-crypto[=PATH]Liga o arquivo crypto do runtime e acrescenta o módulo crypto da biblioteca ao lote, para programas que só alcançam crypto através de chamadas dinâmicas (os programas que o chamam já são ligados com ele); PATH é uma instalação ou árvore de código-fonte do OpenSSL ≥ 3.1.2 a ligar em vez daquela com que o Clause foi compilado; exige -o ou uma compilação de projeto com ligação (crypto)
-gTabelas de linhas Erlang nos objetos e nos executáveis ligados (CodeView/PDB em alvos MSVC, DWARF nos restantes) (depuração)
--print-ir / --print-optimized-irIR verificada antes/depois das passagens do LLVM, com as linhas do código-fonte Erlang como comentários
--print-asmO assembly do alvo de cada módulo depois do pipeline selecionado, com cada sequência de código máquina comentada com a instrução IR e a linha Erlang de onde veio (listagens assembly)
--print-typesCada módulo como código-fonte Erlang anotado com os tipos inferidos (análise semântica); para antes do LLVM
--verboseEventos das fases [pp], [parse] e [comp] no stderr, depois o resumo do índice de diretórios [index] ...
--print-stage-times[time] <stage> <subject>: <ms> ms no stderr: plan por manifesto de projeto (carregá-lo e expandir os padrões de cada alvo selecionado), preprocess, parse e transform (módulos com parse transforms) por ficheiro de código-fonte, compile por lote (número de módulos, alvo de projeto), link por executável; (cached) segue uma fase que reutilizou um resultado da cache. Antes do total compile de um lote vêm as suas fases com o mesmo sujeito: index, calls, liveness (executáveis e inspeções com uma entrada), declared-types, inference-cache (com N of M covered modules reused, cache de inferência), inference, inference-store, contracts, lower, optimize, emit (as que correram; com saída de objetos em várias threads --jobs, optimize também move cada módulo para o seu próprio contexto LLVM e verifica-o, e emit verifica e emite os módulos em paralelo). Depois de inference: linhas inference pass N com os passos de trabalho da passagem face ao orçamento de trabalho da inferência (N of BUDGET work steps) e a forma como terminou (inputs changed, fun results changed, settled, ou a passagem final após passagens não estabilizadas), indicando a função em execução quando o orçamento se esgotou, depois (em cada passagem após a primeira) ; skipped: N components, W work steps: componentes mantidos do seu último percurso porque nada do que leem mudou e o trabalho que esses percursos tinham custado (contado nos passos de trabalho da passagem), depois ; N lattice joins executados pela passagem (contando os aninhados) com , costly: C components given term() inputs quando componentes recursivos dispendiosos perderam as suas entradas locais (inferência), e depois (em cada passagem que recolheu entradas locais) ; inputs: F functions, S slots changed (kinds) com o tipo de alteração de cada slot de entrada alterado (first a partir de nenhum, integer bound, union member no topo, shape, deeper para aninhamento de contentores, function types, term()) e N fun reads not final (valores fun F/A que leram um resumo que mudou mais tarde), depois ; graph: N nodes (+M), W widenings desde a passagem anterior e ; clean: C of K components (A inputs differ, B callees differ), X changed, T ms (P% of pass), S work steps: componentes cujas entradas dos membros e resumos das funções diretamente chamadas são iguais aos da passagem anterior, aqueles cujos resumos mudaram mesmo assim, e o tempo e trabalho gastos neles; depois inference lattice (sem tempo) com a frequência de cada operação do reticulado em todas as passagens (join de dois membros, contando os aninhados, widen, meet, within, subtract, truncate) e quantas chamadas repetiram uma com os mesmos operandos antes na sua passagem e em qualquer passagem (as respostas que o grafo mantém servem-nas, e as operações que uma resposta executou aninhadas não voltam a ser executadas nem contadas), depois as junções de um número de membros diferente de dois e as pesquisas de aninhamento de contentores com aquelas cuja resposta o grafo manteve (seguir as repetições torna a inferência com profiling cerca de 7% mais lenta); depois inference churn com o tempo gasto a recolher entradas e quantos slots de entrada locais mudaram uma vez, duas, ... em todas as passagens, e inference churned <module>:<function>/<arity> #<argument> (sem tempo) para os 10 slots mais alterados com o tipo da sua última alteração e os factos antes e depois dela (cada um limitado a 200 caracteres); depois (sem tempo) até 10 componentes inference clean-changed <module>:<function>/<arity> que estavam limpos mas mudaram, com a passagem que primeiro o observou e a frequência (uma dependência que não é uma entrada nem uma chamada direta, como fun F/A); depois (sem tempo) inference facts N após cada passagem que recolheu entradas: os factos de cada resumo e entrada local, o maior tamanho e o tamanho médio das suas árvores (nós contados uma vez por caminho), a união mais larga, quantos atingem os orçamentos de profundidade de contentores, membros de união e elementos de tuplo/map, os resumos com mais (32) tipos de função e os factos dependentes; depois inference largest com o maior facto de cada um dos 3 componentes que mais demoraram (limitado a 200 caracteres); depois inference slowest <module>:<function>/<arity> para as 10 funções (os grupos recursivos indicam um membro and N more) que mais demoraram em todas as passagens, com os seus passos de trabalho e a parte desse trabalho no orçamento das passagens que as executaram (877450 work steps, 43.9% of 10 passes of 200000 budget), widened to term() quando um orçamento alargou um dos seus factos, e as junções do reticulado que os seus percursos executaram e os nós do grafo que criaram; depois inference costliest <module>:<function>/<arity> para as 10 funções de pelo menos 10 ms que mais demoraram por passo de trabalho, com esse tempo em microssegundos, os seus passos de trabalho, junções do reticulado (e junções por passo de trabalho) e nós criados; depois inference rounds <module>:<function>/<arity> and N more para os 10 grupos recursivos mais lentos: resoluções em todas as passagens, rondas executadas face ao limite por resolução (8 + 4 por membro), resoluções que atingiram o limite ou gastaram o seu oitavo do orçamento da passagem (cada membro alargado a term()), resoluções que desistiram de imediato porque uma passagem anterior o fez (remembered) ou terminaram com o orçamento da passagem gasto, percursos de membros (e os saltados porque nada do que leem mudou, e os repetidos: uma resolução posterior repetiu o último percurso do membro porque nada do que leu mudou) e a parte dos percursos e repetições que alterou um resumo (cresceu, entradas de tipo função alteradas, ou voltou a um dos 4 últimos resumos do membro), e os membros alterados por ronda da última resolução em dez grupos de rondas, depois ; N solves repeated the previous fixed point, M reached it after R rounds in total: resoluções que terminaram nos resumos com que a passagem anterior terminou, e resoluções que os atingiram antes de convergir, com as rondas necessárias (o que começar a partir deles evitaria). Uma compilação em cache não imprime fases
--asn1-option OPTION, --asn1-outdir DIR, --generate-asn1Compila entradas .asn/.asn1/.set.asn em Module.erl e Module.hrl com uma opção asn1ct (repetível), em DIR (acrescentado ao caminho de include), ou apenas os gera (ASN.1)
--print-envImprime o ambiente de compilação resolvido como TOML no stdout e termina sem processar códigos-fonte (relatório do ambiente)
--print-inputsPré-processa e analisa as entradas, acrescenta os módulos que elas nomeiam tal como a compilação faz, depois lista todos os códigos-fonte do lote no stdout e para antes da compilação (projetos)

Listagens assembly

--print-asm executa o pipeline selecionado (como faz --print-optimized-ir) e depois imprime o assembly de cada módulo de entrada a partir da mesma máquina alvo que escreve os objetos, um módulo de cada vez. Os comentários usam o marcador do alvo (# em x86, // em AArch64 ELF, ; na Apple, @ em 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

Relatório do ambiente

--print-env valida toda a linha de comandos (conflitos, entradas posicionais legíveis, planeamento do projeto) e depois imprime o que esse comando usaria como um único documento TOML no stdout, termina com 0 e não lê nenhum código-fonte. Os caminhos são absolutos, com /.

# 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"

(Os arrays imprimem um item por linha.) actions lista as ações do frontend (print-pp, parse-check, print-ast, print-source, print-abstr, caso contrário preprocess-check; print-inputs sozinha substitui-as), caso contrário as inspeções (print-types, print-ir, print-optimized-ir, print-asm), caso contrário emit, link (-o) ou compile. Numa compilação de projeto, os alvos com um output também ligam. Os módulos encontrados mais tarde pelo nome (através de source_search_paths ou da biblioteca) não são listados: encontrá-los exige a análise sintática (é isso que --print-inputs faz). --print-env não pode ser combinado com --new-project.

Cache de compilação

Um lote com um diretório de compilação (cada alvo de projeto, as entradas posicionais com --build-dir) guarda o resultado da sua compilação na cache de compilação: os diagnósticos por ordem, a falha e, quando um executável ou --emit precisa deles, os objetos (ou o bitcode) de cada módulo e do módulo de arranque. Uma compilação posterior do mesmo lote com as mesmas opções reproduz os diagnósticos e liga ou publica os objetos guardados exatamente como se fossem novos; --print-stage-times mostra então [time] compile ... (cached). --print-ir, --print-optimized-ir, --print-asm e --print-types recalculam sempre, e --no-cache não lê nem escreve.

Backend

SDK do LLVM

LLVM estável 23.1.x, no mínimo 23.1.1. O LLVM é uma dependência do anfitrião: a arquitetura, a biblioteca padrão de C++ e o CRT do Windows têm de corresponder aos da ferramenta do compilador. O código do projeto mantém exceções/RTTI; nenhuma exceção pode propagar-se através do LLVM. O runtime nunca usa o LLVM.

Configuração de referência em Windows x64: clang-cl 23.1.2 do anfitrião em C:/Program Files/LLVM/bin, SDK thirdparty/clang+llvm-23.1.2-x86_64-pc-windows-msvc, ferramentas x64 do Visual Studio 18, Windows SDK 10.0.26100.0, Ninja, /MT, _ITERATOR_DEBUG_LEVEL=0. A seleção automática aplica as definições /MT e do iterador; um LLVM_DIR explícito não o faz, e a sonda de ligação falha nesse caso.

PCRE2

Os builtins re do runtime usam o PCRE2 10.47, a release que o OTP 29 inclui (erts/emulator/pcre/vendor.info), pelo que a sintaxe dos padrões, as opções e as capturas se comportam como no OTP: unidades de código de 8 bits, suporte Unicode, sem JIT, pcre2_match de origem (o patch de cedência do OTP não é transposto). O PCRE2 é licenciado sob BSD-3-Clause com a exceção PCRE2 para binários compilados; nenhum ficheiro do PCRE2 é submetido no repositório. O CMake (cmake/Pcre2Dependencies.cmake) resolve-o por esta ordem:

  1. -DCLAUSE_PCRE2_ROOT=<source directory> tem precedência (sem transferência); a versão no seu configure.ac tem de ser 10.47.
  2. Um PCRE2 instalado de versão 10.47 ou superior (CLAUSE_PCRE2_SYSTEM=ON, o valor por omissão): o pacote CMake (find_package(pcre2 CONFIG COMPONENTS 8BIT), com preferência pelas bibliotecas estáticas), caso contrário o pkg-config libpcre2-8, com preferência por um libpcre2-8.a estático em vez da biblioteca partilhada.
  3. A release fixada, descarregada para thirdparty/pcre2-10.47 e verificada (pcre2-10.47.tar.bz2, SHA-256 47fe8c99461250d42f89e6e8fdaeba9da057855d06eb7fc08d9ca03fd08d7bc7); -DCLAUSE_DOWNLOAD_PCRE2=OFF desativa a transferência.

Um diretório de código-fonte (1 ou 3) compila a biblioteca de objetos clause_pcre2 a partir dos ficheiros .c listados, com os ficheiros distribuídos config.h.generic, pcre2.h.generic e pcre2_chartables.c.dist copiados para a árvore de compilação (sem passo de geração, sem as flags de aviso do projeto, fora do clang-tidy e do Lizard), e os seus objetos são acrescentados ao próprio clause_runtime: o arquivo é autossuficiente e cada consumidor (ligações do clau, programas de teste aninhados, runtime_link, examples/compile) obtém o PCRE2 com ele. Uma biblioteca instalada torna-se, em vez disso, uma entrada adicional do ligador registada em clause_runtime.link ao lado do arquivo (uma entrada por linha), que o clau acrescenta a cada ligação; uma biblioteca partilhada torna os executáveis dependentes dela em tempo de execução. Por plataforma: o Windows usa a transferência (na prática, não se procura nenhum PCRE2 do sistema); o Linux e o macOS usam um PCRE2 10.47 ou mais recente instalado, quando existe, caso contrário a transferência. O PCRE2 é sempre ligado ao runtime, também nos programas que nunca chamam re.

zlib

O módulo zlib do runtime e os termos externos comprimidos usam o zlib 1.3.2, a release que o OTP 29 inclui (erts/emulator/zlib/vendor.info), pelo que os bytes comprimidos são iguais aos do OTP. O CMake compila os fontes da sua biblioteca (cmake/ZlibDependencies.cmake, clause_add_runtime_zlib) na biblioteca de objetos clause_runtime_zlib, cujos objetos se juntam a clause_runtime como os do PCRE2; -DCLAUSE_RUNTIME_ZLIB_ROOT=<source directory> tem precedência, caso contrário a release é descarregada para thirdparty/zlib-1.3.2 e verificada (SHA-256 bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16) em todos os anfitriões. A licença do zlib é a licença zlib. O LLVM do compilador mantém o seu próprio zlib; os dois nunca se encontram num mesmo binário.

zstd

O módulo zstd do runtime usa zstd 1.5.7, a release que o OTP 29 inclui (erts/emulator/zstd/vendor.info), pelo que os frames são iguais aos do OTP. O CMake compila os fontes da sua biblioteca (common, compress, decompress; numa única thread, sem o descodificador assembly; cmake/ZstdDependencies.cmake, clause_add_runtime_zstd) na biblioteca de objetos clause_runtime_zstd, cujos objetos se juntam a clause_runtime como os do zlib; -DCLAUSE_RUNTIME_ZSTD_ROOT=<source directory> tem precedência, caso contrário a release é descarregada para thirdparty/zstd-1.5.7 e verificada (SHA-256 eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3), o mesmo arquivo que a compilação do LLVM para Windows usa. A licença do zstd é BSD-3-Clause (ou GPL-2.0).

OpenSSL

Os builtins crypto do runtime usam a libcrypto do OpenSSL, fixada em 4.1.0, sendo aceite qualquer release desde 3.1.2 (a mais recente com um fornecedor validado para FIPS), num arquivo separado clause_runtime_crypto que só os programas que chamam crypto ligam. A sua proveniência, como o Clause e o clau a compilam a partir do código-fonte, a ligação (--with-crypto[=PATH]) e o modo FIPS (--fips=PATH) estão descritos em crypto.

Outros pré-requisitos: CMake ≥ 3.28, um compilador C++23, Boost ≥ 1.90, toml++ 3.4.0 e as ferramentas de qualidade. O OTP só é necessário para auditorias opcionais e para regenerar fixtures.