Date: 2026-06-17
A file-mode body (ADR 26) is read as text and concatenated with the
namespace preamble and the generated wrapper into one source.zig, written
into the content-addressed cache directory and compiled there. Zig resolves
@import("util.zig") relative to the importing file's own path, which is
now source.zig in the cache directory, so a sibling import of a file in
the user's source tree does not resolve. Compiler-provided modules such as
@import("std") are unaffected, since the compiler supplies them.
The namespace preamble (ADR 28: a co-located .zig plus defz and
deftypez) already shares helpers, @cImport blocks, and types across the
functions of a namespace, which is the common reason to reach for an
import. What it does not cover is a body split across several .zig files
or a vendored multi-file Zig library that uses relative @import between
its own files.
A file-mode body may @import other .zig files by relative path.
clj-zig resolves the transitive closure of relative @import targets
starting from the body file, copies those files into the cache directory
at their paths relative to the body file, and includes each copied file's
content in the content hash. An edited imported file therefore changes the
hash and recompiles.
The generated source.zig is the compiled root, so its directory is the
module path. Sibling and subdirectory imports resolve there, and an
imported file may itself use .. as long as it stays within that
directory. An import that escapes the body's directory hits Zig's own
"import outside module path" rule, exactly as it would were the body
compiled directly as a root file; that import and any compiler-provided
module (std, builtin) or absolute path is left for the compiler, not
copied.
A body can be organized across several files within its directory, and a vendored Zig library whose files import each other by relative path compiles unchanged. The cache stays content-addressed: the artifact records the exact contents of every file that produced it, so keep-last- good and per-function recompilation hold across the import graph.
clj-zig gains a small Zig-import scanner and transitive resolution, which
is new surface to keep correct. The scan reads @import string literals;
an import computed at comptime is out of scope and is left for the
compiler. The body's directory bounds the module, matching Zig; sharing
across sibling directories is a named-module concern, below.
Compile the generated source in place in the user's source tree so sibling imports resolve directly. Rejected: it abandons the content-addressed cache directory that per-function recompilation and keep-last-good depend on, and it litters the project with generated artifacts.
Register the user's directory as a named Zig module with -M/--dep.
Rejected as the primary mechanism: module flags address named imports
(@import("mylib")), not the bare relative @import("util.zig") a Zig
author writes between sibling files. Named-module dependencies can be added
later as a separate capability without conflicting with this one.
Require all sharing to go through the namespace preamble and forbid file imports. Rejected: the preamble covers in-namespace helpers but cannot absorb a multi-file vendored library that imports its own files.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |