Troubleshooting

The build succeeding is not the same as the wrapper being complete. Most "bugs" are a missing TOML entry. This page is symptom → what to edit.

Missing from the wrapper, or wrong at runtime

What you seeLook at
A C++ template type is missing, or members are Any[types] templates / template_headers
A struct from a header has no fields-fstandalone-debug in [compile] flags
A struct became an opaque blob with a layout warningUnmodellable member; read the warning's named type
A macro-based API is absent (no error)[wrap.macros] + shim_headers
Macro values are wrong but everything compiledShim header resolved to a system copy of the same name — use a more specific path or an explicit -I
printf-style function only takes its fixed arguments[wrap.varargs]
invalid type '…' in [wrap.varargs.f]You wrote C types; varargs want Julia types (Cint, Cstring, …)
must be a list of type listsYou wrote f = ["Cint"]; write f = [["Cint"]]
Memory grows on every string-returning call[wrap.cstring_owned]
Unrelated symbols from tests/examples in the wrapperexclude on the dependency
A TU fails to compile with a missing header[compile] include_dirs — a directory that does not exist is passed to clang as is, so check the spelling
A TU fails on an identifier upstream's build defines[compile] flags / [compile.defines]
A setting seems to have no effectTypos are silent (no unknown-key warning). Also check the ignored-keys list in Edit the TOML
using MyProject loads an old build after you edited the projectThe package loads the build vendored last. use("myproject"), or register again, vendors the new one; then start a new session (Registry)
use() keeps building an old copy of the sourcesThe project was registered by an earlier RepliBuild, which copied its sources into the registry. Register it again from the project
A wrapper warns it was generated by an older RepliBuildRun wrap(toml) again. A fix in what build extracts also needs build(toml; clean=true) first: a build whose inputs did not change is skipped

Details and examples for each key: Edit the TOML.

Build and environment

What you seeWhat to do
RepliBuild supports Linux and WindowsIt does. macOS is refused because the AAPCS64 ABI classifier is unbuilt, not because it is untested.
check_environment() marks a tool FAIL or WARNThe advice under that line is the fix. Install has the whole setup.
LLVM Toolchain not found building C++No LLVM 21+ on PATH (or in LLVM_CONFIG). See Install.
C++ wrap fails, C worksThe JLCS dialect library is not built: Install → The JLCS dialect.
JLCS dialect library not found at: …Same: build the dialect. The message names the folder to build in.
check_environment(): libJLCS "built against LLVM X, but llvm-config is Y"The system LLVM/MLIR moved to another minor version. Build the dialect again.
Failed to initialize JIT for lib….so when a C++ wrapper loadsThat library's Tier 2 functions will not work; its ccall functions still do. The error under it says why. Usually the dialect is missing or will not load, or llvm-dwarfdump is not on PATH; check_environment() checks all three.
Windows: every C file fails on its first system #includeThe Clang JLL has no headers of its own. Install MSYS2 CLANG64, or set REPLIBUILD_C_SYSROOT.
Windows: libJLCS.dll will not load (The specified module could not be found)It imports libLLVM-<N>.dll and libc++.dll from C:\msys64\clang64\bin. Put that directory on the Windows PATH and restart Julia. If it is already there, MSYS2 has moved to another LLVM and the DLL it was built against is gone: build the dialect again.
Windows: The specified module could not be found opening a thunks .dllThe missing module is libJLCS.dll, not the thunks library — see the row above.
Windows: C++ stopped working after upgrading RepliBuildEach version installs into a new folder, which has no dialect library yet. Build it there (Install).
Windows: An Application Control policy has blocked this fileSmart App Control, or another App Control policy, refused to load a library RepliBuild just built. Such policies block new, unsigned binaries, and everything RepliBuild builds is one. Event 3077 in Event Viewer (Applications and Services Logs → Microsoft → Windows → CodeIntegrity → Operational) names the blocked file. RepliBuild cannot sign what it builds; whether to change the policy is your decision.
Windows: clean fails because a file is in useA running process still has the library loaded, usually the Julia session that included the wrapper. Close it and run clean again.
Configuration file not foundRun discover first, or pass the path to the TOML.
Library not found: …/julia/lib….soRun build before wrap.
No compilation_metadata.json next to …build writes it beside the library, and wrap takes every type from it. Run build(toml).
No source files to compile[compile] source_files is empty and the scan found nothing. If the sources come from a [dependencies] entry, look further up for Failed to clone dependency.
Failed to clone dependency … (a warning)The git dependency was not fetched, and the build carries on without it, so it fails later on missing headers or sources. Check the URL, the tag and the network, then build again.
Dependency HEAD disagrees with commitThe tag moved. Update commit (full 40 hex) or pin a different tag.
Shim #include resolved outside the projectshim_headers hit a system header. More specific path, or -I.
Wrapper generation refused (undeclared type in a ccall)A type did not make it into the module. Usually a missing template, or a header-only struct without -fstandalone-debug.
Wrapper generation refused for another reasonThese refusals name a RepliBuild limitation, not a mistake in your TOML. [wrap] exclude_symbols leaves the named function out so the rest of the wrapper is written. Please report the case.

Calling the wrapper

What you seeWhat to do
ABI Safety Trap: cannot call 'f'RepliBuild could not prove a safe way to call f (a long double, a record it cannot pass by value, or a type whose name several types in the library share, for example), so the wrapper has a stub that raises instead of a call that would corrupt memory. The message says which. The rest of the module works.
FFI Safety Trap: Cannot call function 'f'A type in f's signature has no Julia mapping. Name one under [types.custom] (MyHandle = "Ptr{Cvoid}"), then build and wrap again.
C++ exception: …The C++ code threw. It arrives as RepliBuild.JITManager.CxxException; catch it like any Julia exception.
MethodError passing a Ref to a struct parameterA parameter declared as a struct takes the struct itself. Only a pointer parameter (S*) takes a Ref or a Ptr.
MethodError passing an Int where the signature says Cdouble or Int32Some parameters take exactly one Julia type: floating point in a C++ wrapper, and fixed-width integers such as int32_t. Write 2.0 or Int32(2). The function's signature says which.
MethodError: … method too new to be called from this world context after useuse defines the module while your code runs. Call use at top level, or call into the module with Base.@invokelatest M.f(x).
register warns it could not add the package to a Julia environmentThe message says why: the target was a package's own Project.toml, the environment already has a different package of that name, or Pkg failed. use still loads it; pass env an environment, or nothing.
A crash calling a C++ method on T()T() is a zeroed Julia value, not a constructed C++ object. Construct one in place with the constructor wrapper — Call a wrapper.
UndefVarError for dispatch_tier or DISPATCH_TIERThey exist only in a wrapper that mixes tiers. A single-tier wrapper names its one tier in a comment instead.

C vs C++ mix-ups

[wrap] language selects the toolchain, not just the generator. A C project forced to "cpp" needs a system LLVM you may not have. A C++ project forced to "c" will wrap the extern "C" surface and drop classes, methods, and virtual dispatch.

Ingest is C only. Ingesting a C++ .so will not give you a usable class API — build that library from source.

Cache

Per-file IR is keyed on source plus compile fingerprint (flags, defines, includes, LLVM version). Changing flags rebuilds without a manual clean.

The project hash (.replibuild_cache/project_hash) covers the TOML, the sources, the include directories and the toolchain, but not RepliBuild's own version. After an upgrade, build reports cache: project unchanged and keeps the metadata the old version extracted. build(toml; clean=true) re-extracts it, starting from nothing; deleting .replibuild_cache/project_hash re-runs the link and the extraction but keeps the compiled IR.

~/.replibuild/builds/<hash>/ is the use() cache. The hash includes the generator version. clean(toml) removes project-local build/, julia/, and .replibuild_cache/. It does not touch the registry or the use() cache; use(name; force_rebuild=true) rebuilds one registered package from nothing.

Loud vs silent

A typo'd TOML key is accepted and ignored. If a setting "does nothing", check spelling against the section reference before anything else.

Hard errors (the useful kind): bad commit shape, bad [wrap.varargs] shape, a shim include that escaped the tree, a wrapper that would name an undeclared type. Those messages name the fix.