Projects
Partly written. §1–§6 were written with milestone M7 of the Lyric 5 plan (slices S1, S4, S5a–S6e, S8a), §7 with M8a; the rest follows, spec-first: each rule lands here with its conformance case before or with its implementation. Source of the decisions: 11 Tooling and interop W2/W3, 07 Modules.
Scope
lyric.toml, profiles, targets, the lock file, out/, build scripts and their trust rule, reproducibility.
1. The manifest
A package's manifest, lyric.toml at its root, is read and never run
(11 P1, 07 V7).
Conformance. conformance/cases/15-project/, package cases; the TOML subset in the
toolchain's own tests (tests/Lyric5.Tests, ManifestTests), the programs and the toolchain pin
in ProgramTests.
- A manifest is TOML, the part of it a manifest needs: tables and arrays of tables; bare,
quoted and dotted keys; basic and literal strings, integers, booleans, arrays and inline
tables; comments. Floats, dates and times, and multi-line strings are refused, as is what TOML
itself refuses — a key or a table defined twice, a value where a table is needed
(
LYR-PKG0001, at its line and column). [package]is required. Itsnameis a lowercase letter followed by lowercase letters, digits and_— the first segment of every module path of the package (04 §2) — and notstd, the standard library's (07 M3, D1). Itsversionis a semantic version,MAJOR.MINOR.PATCHwith optional pre-release and build parts. Itseditionnames the edition of the language the package is written in (07 V9):"5", the one there is, and the default. A missing or malformed field is refused (LYR-PKG0002).[package]may also holddescription,licenseandrepository— strings — andauthors, an array of strings: they describe the package and change no build (LYR-PKG0002for another type).- A key or a section the toolchain does not know is refused (
LYR-PKG0003), as an unknown option is (14 §1.1).[dependencies],[override],includeandexcludeare §2's.[profile]is §4's,[native]§5's,[build-dependencies]and[trust]§8's.[lints]holdsallow,warnanddeny, each an array of lints, groups orwarnings— the levels of the package's lints in its files (16 §5):[lints] deny = ["unused"]; a selector that names nothing, or stands in two of them, is refused (LYR-PKG0002), another key (LYR-PKG0003). - A package's programs are its
src/main.lyr, whose binary is named after the package (14 §1.2), and each[[bin]]:name = "tool"— a lowercase letter, then letters, digits,_and-—, its binary's, andentry = "src/tool.lyr", a module of the package undersrc/(LYR-PKG0002, as for an entry that is no file and for two programs of one name; another key isLYR-PKG0003). Without any program, the package is a library (P2). A package's root module is itssrc/lib.lyr(04 §2 rule 1a), whatimport geo { … }names; it is no program, and a package may hold both.lyric buildbuilds every program;runand--emitthe one--binnames, elsesrc/main.lyr's, else the only one — of several,--binnames it (LYR-CLI0007). toolchain = "5.1"— or">=5.1"— in[package]is the least toolchain that builds the package (11 P12): a toolchain below what any package of the program asks for refuses the program (LYR-PKG0009, exit 2, 14 §1.3), a development build of a version counting as that version. Another form is refused (LYR-PKG0002). The root package's pin also chooses the toolchain: a command in the package is handed to an installed toolchain that meets it, where the one started does not (14 §13 rule 11).comptimeBudget = 100_000_000in[package]is the steps onecomptimesite may take (11 §2 rule 5), for the whole program but the standard library where it stands in the root manifest; a dependency's changes no build. A number that is not positive, or another value, is refused (LYR-PKG0002).
2. Dependencies
The packages a package imports from (11 W2, 07 V7).
Conformance. conformance/cases/15-project/, package cases that hold their dependencies in
their own directories, and the git repositories they read as their versions
(the suite's README); the toolchain's own tests
(tests/Lyric5.Tests: DependencyTests, GitDependencyTests, PackageContentTests).
[dependencies]names them, each where it is read from: a directory,geo = { path = "../geo" }, relative to the manifest — or a git repository,http = { git = "https://…", tag = "v1.2.0" }. The directory, or the root of the repository, holds a manifest that names the package (LYR-PKG0004). A version alone,geo = "1.2", is a registry's form, and 5.0 has no registry (LYR-PKG0003) (07 P8).- A git dependency reads one revision of its repository
(11 P9): a
tag, abranch, a commit —rev, its id or the first 7 to 64 hexadecimal digits of it — or, naming none, the branch the repository'sHEADnames. Itsgitis a URL —https://,http://,ssh://,git://,file://— oruser@host:path(LYR-PKG0002, as for two revisions, or a revision beside apath). The URL is compared, cached and locked in its normal form (the review's M7-10): a/and a.gitat the end dropped, the scheme and the host in lower case —HTTPS://Example.com/org/geo.git/andhttps://example.com/org/geoare one repository; the rest keeps its case, andhttps://andssh://to one host stay two. A revision the repository does not have, or a repository without a package at its root, is refused (LYR-PKG0006), and so is a tag that is a version over a manifest that gives another —v1.2.0where the manifest saysversion = "1.1.0": the build chooses among versions by the tag. A repository that cannot be reached is the environment's failure (LYR-PKG0007, exit 2, 14 §1.3). - What is read from git is kept in the user's cache, not in the project: each repository
once, each revision's package once, for every project that reads it (P9; 07 P10). A tag or a
commit the cache holds is not fetched again; a branch, or no revision, is read where the lock
holds it (§3), and at its head — fetched — where the lock holds nothing for it yet.
--offlinefetches nothing: what the cache does not hold is refused (LYR-PKG0007). - A package read from git is its package content (11 P8): its manifest,
src/,native/,build.lyr, and the filesREADME*andLICENSE*at its root — nottests/, notout/.[package] include = […]names the files instead of that default — the manifest belongs always —, andexclude = […]takes files out. A pattern is relative to the package's root,/between directories;*stands for any characters within a directory,?for one,**for any number of directories, and a pattern that names a directory holds what lies below it (LYR-PKG0002for another form). A module outside the content is not there (LYR-RES0003). A package read from git names its own dependencies by git: a directory is no part of it (LYR-PKG0004). - A module imports from its own package, from
std, and from the packages its package's manifest declares — not from what those depend on (LYR-RES0014) (07 P6). - A program holds one package of each name (07 P3). Versions of one repository are one
package: a tag that is a semantic version,
v1.2.0or1.2.0, asks for that version or a later one of its line — the same major version; below 1, the same minor; below 0.1, the version alone (07 P2) —, and of all the versions the graph asks for, directly or through a version read on the way, the build takes the greatest: the least that satisfies them all (minimal version selection, 07 P4). Any other two sources for one name — two directories, two repositories, two revisions of one, versions of two lines — are refused (LYR-PKG0005), unless the root manifest's[override] units = { path = "…" }picks the one — read wherever the graph asks forunits, and what it replaces is not read at all, not fetched either (07 P7). An override reads a directory (LYR-PKG0003for the git form); an override in another package's manifest is not read. No package depends on itself, at once or through others: a cycle is refused with its path,app -> geo -> app(LYR-PKG0010; the review's M7-6) — a package's dependencies are built before it, and a cycle has no first one. - A library — a package without
src/main.lyr— builds as a check: every module of it through the compiler, nothing built (07 B6);lyric runhas no program there (LYR-CLI0005).
3. The lock file
What a build read from git, kept so that the next build reads the same (07 P5): minimal version selection makes the choice, the lock makes the content reproducible.
Conformance. conformance/cases/15-project/, package cases that hold their lyric.lock;
the toolchain's own tests (tests/Lyric5.Tests, LockTests).
lyric.lock, beside the root manifest, holds every revision of a git repository the graph read — the versions chosen and the ones read on the way —, each with its package's name and version, its repository and revision, the commit it was, and the hash of its package content (§2): SHA-256 over one line per file — the file's SHA-256 in hexadecimal, two spaces, its path with/between directories —, the lines sorted by path; writtenh1:and base64 — and the source trees from git a build read (§5 rule 15). The toolchain writes the lock — only when what it holds changes, and none for a program that reads nothing from git —, and it is checked in with the manifest. A dependency's lock is not read.- A build reads a revision the lock holds at the commit the lock holds: a branch stays where
it was locked, and a tag moved in the repository too. Content that is not what the lock holds
is refused, as is a locked commit the repository does not have (
LYR-PKG0008). What the lock does not hold yet is resolved and added; what the graph no longer reads is dropped. A lock that is not one is refused (LYR-PKG0001,LYR-PKG0002). lyric update [<package>…]reads every package from git anew — or those it names, the others staying at their commits —, fetching their repositories first, and writes the lock: a branch moves to its head, a moved tag to its commit. A tag of the root manifest that is a version is first raised to the newest tag of its line the repository has (the review's M7-8) — never another major version; below 1, never another minor; a pre-release only for a pre-release — and written on its line oflyric.toml, the rest of the file as it was; a dependency's own manifest is its own, and a branch, a commit or a tag that is no version stays. A name that no package read from git has is refused (LYR-CLI0003).- Under
--locked(the review's M7-9),build,runandtesttake the lock as it is and write nothing: a revision the graph reads that the lock does not hold is refused before anything is fetched, and so is a lock that holds what the graph does not read, or no lock where the program reads from git (LYR-PKG0011, exit 1). A program that reads nothing from git needs none. Without the flag a build writes the lock on (rule 1).
4. Profiles
How a program is built — the compiler's settings, not the program (11 P3).
Conformance. conformance/cases/15-project/, package cases whose manifest changes the
built-in profiles the suite builds with; the toolchain's own tests (tests/Lyric5.Tests,
ProfileTests, LtoTests).
debug,release,asanandtsanare built in.[profile.<name>]changes a built-in profile, or names one of the manifest's own — a lowercase letter, then letters, digits,_and-—, which inherits from another,inherits = "release", the chain ending in a built-in one. A built-in profile inherits from nothing, a manifest's own profile always does, and none inherits from itself (LYR-PKG0002). Only the root manifest's profiles count: the program is built one way.out/<profile>/is named after the profile (14 §1.2).- A profile sets fields:
opt, the C optimization level from 0 to 3;debugInfo,lto,denyWarnings,overflowChecks,fastMath, eachtrueorfalse; andgc,"immix"or"boehm"(LYR-PKG0002for another type or value,LYR-PKG0003for another key). A field a profile does not set is the one it inherits — as the manifest has that profile. The built-in ones:debugopt = 0,releaseopt = 2, the sanitizers'opt = 1; all four withdebugInfoandoverflowChecks, none withlto,denyWarningsorfastMath, all withgc = "immix". overflowChecks = falsemakes integer overflow wrap instead of panicking, for the whole program (03 §1.6). Nothing is without the checks unless a profile says so.denyWarnings = truefails a compilation that warns: it is-D warnings(16 §5 rule 8) — each warning is an error, its note naming the profile.fastMath = truelets the C compiler treat the program's floating point as not IEEE-exact (03 §1.6); the runtime's stays exact.lto = truelets the C compiler optimize across the program, the native parts (§5) and the runtime as they are linked — ThinLTO. A target whose linker takes none — macOS, with the toolchain's C compiler — is built without it, not refused. What a program does is the same either way.gcchooses the runtime's collector (01 L1):"immix", its own, or"boehm", the Boehm–Demers–Weiser collector it began with, kept to compare against. What a program does is the same under either; what it costs in time and memory is not.
5. The native part
C a package brings with it, compiled with the program and linked into it (07 B5; 11 W2).
Conformance. conformance/cases/13-abi/ and conformance/cases/15-project/, package cases
that call their native part or whose manifest a rule refuses; the toolchain's own tests
(tests/Lyric5.Tests, NativeTests, VendorTests, BindingsTests, LinkDiagnosticsTests, LinkerTextTests).
5.1 Sources
[native]namessources, patterns of the package's files as §2'sincludehas them — the C sources compiled with the program under its profile —,include, directories of the package the sources find their includes in, andlibs, libraries linked by name (-lz). Another key than this section's is refused (LYR-PKG0003), as is another form of an entry (LYR-PKG0002).[native.linux],[native.windows]and[native.macos]take the same keys: what a build for that operating system gets on top of[native].- Every package of the program brings its native part — a dependency's too —, and each library is
linked once. The C functions of a native part are called through
extern "C"(13 §2). [native.<triple>]— a Tier 1 or Tier 2 target's triple,[native.x86_64-windows-gnu]— takes the same keys, and what a build for that target gets comes on top of[native]and of its operating system's table: the three tables are layered, each list the one before with its own entries after. A triple no tier holds is refused (LYR-PKG0003).defines = ["RAYLIB_STATIC", "LEVEL=2"]are the package's sources' preprocessor definitions,NAMEorNAME=value,NAMEa C identifier (LYR-PKG0002). The manifest takes no other flag for the C compiler: one that names the machine or a path outside the package would break §6 and the builds for other targets.- A native source finds, besides its package's
include, the toolchain's<lyric.h>(13 §4) and theincludeof each package its package declares as a dependency — not of the packages those depend on (§2 rule 5). Of the toolchain's headers onlylyric.his promised.
5.2 Linking
archives = ["native/lib/libz.a"]are static libraries the package brings, prebuilt — files of the package's content (§2) or of a source tree (§5.3): each is linked by its path, not searched for. A file outside the content, or one that is not there, is refused when the build needs it (LYR-PKG0002). An archive is built for one target, so it stands in the table of its triple (rule 4) as a rule. On Windows an archive is promised to link where it was built for the GNU ABI — by MinGW or zig cc —, not by MSVC.dylibsare shared libraries the package brings, prebuilt — files of the package's content or of a source tree, linked by their path. A shared library is built for one target, sodylibsis a key of the operating systems' and the triples' tables only (LYR-PKG0003in[native]): on Linux and macOS each entry is the path of a.soor a.dylib("native/linux/libfoo.so"); on Windows{ dll = "native/win/foo.dll", lib = "native/win/libfoo.dll.a" }, the DLL and its import library, for the GNU ABI as rule 7 has it. Another form, a file outside the content, or a shared library named inarchivesis refused (LYR-PKG0002). The build puts each beside every binary it makes of the program, as §8 rule 3.2 puts a file there, and with the same rules: the binary searches its own directory first, no directory of the machine is written into it, and two files of one name stop the build. A Mach-O library whose install name does not begin with@rpath/would not be found there, and an ELF library without asonamewould be recorded by the path it was linked from — the machine's; each is refused (LYR-BLD0006, exit 1), the message saying how to name it. A shared library of the system is linked by name (libs); one the program finds while it runs isstd.ffi'sLibrary(13 §5). (Rule 8 replaces, the same day, a rule that refused every shared library of a package — 11, E3′.)frameworks = ["Cocoa"]are macOS frameworks, linked as-framework Cocoa: a key of[native.macos]and of the macOS triples' tables only (LYR-PKG0003elsewhere).pkgConfig = ["sdl2"]names libraries of the system aspkg-configknows them: a build for the host askspkg-config --cflags --libs— or the program the environment'sPKG_CONFIGnames — and gives what it says about include directories and definitions to the package's sources and to its bindings (§5.4), its directories and libraries to the link aslibsare linked, its frameworks as rule 9's, and every other flag to the link as it is.pkg-configmissing, or a name it does not know, stops the build (LYR-BLD0004, exit 2).What only the host has: a framework comes from the macOS SDK and a name of
pkgConfigfrom the host's system, so a build for another target that needs one is refused before it compiles (LYR-BLD0004, exit 2, naming the package and the key). (Informative: with the toolchain's C compiler a build for Windows links Windows' system libraries from any host; a build for Linux links a library of the system beside libc only on a Linux host, and one for macOS a framework only on the Mac it is for: zig finds the SDK's frameworks for the Mac it runs on, and for no target named — another Mac's included.)The link takes, in this order: the program's objects and the native parts' — the packages before the packages they depend on, the root's first —, their
archivesanddylibsin that order, the libraries by name and frompkgConfig, then the frameworks; each archive, library and framework once, where it first stands. A link that fails is read for what failed it, and each such finding is said, exit 2 (14 §1.3):- a symbol nothing the link takes defines —
LYR-LNK0001, at theexterndeclaration of the program that names it, else with what references it; - a library or a framework the linker does not find —
LYR-LNK0002, at the line of the manifest whoselibsorframeworksnames it, else naming the build script or thepkgConfigthat gave it; - a symbol two inputs define —
LYR-LNK0003, naming who defines it: a package, the program, the runtime.
What the linker says that none of them is said as it is (
LYR-BLD0001) — the reading never guesses. (Informative: the toolchain reads lld, zig's Mach-O linker, ld64 and GNU ld.) A C source that includes a header no directory holds fails its compile (LYR-BLD0001) with the directories it was searched in. A binary is linked anew where an archive's or a shared library's bytes changed, not only its time.- a symbol nothing the link takes defines —
5.3 Source trees
[native.vendor]names source trees: C that the package does not hold and that is no package — no manifest, no modules.raylib = { git = "https://…", tag = "5.5" }is a revision of a repository, read as §2 rule 2 reads one (branch,rev, or none), cached and locked as §2 rule 3 and §3 have it, its content every file of the commit;sqlite = { url = "https://…/sqlite.zip", hash = "sha256:…" }is a file loaded fromhttps://,http://orfile://— itshashis its SHA-256, 64 hexadecimal digits, and makes the way it came irrelevant —, a tar compressed with gzip or a zip, told by its bytes, not its name, and unpacked with a single top directory left out. A name is a lowercase letter, then letters, digits,_and-; another key or form is refused (LYR-PKG0002). (A tar compressed with xz is no tree in 5.0; such a tree comes from git.)A path of the native part — in
sources,include,archives,dylibsandbindings— that begins with@name/lies in the treename; a name[native.vendor]does not hold is refused (LYR-PKG0002). A tree's file is no part of the package's content (§2 rule 4) and is not refused for it; one that is not there is refused when the build needs it (LYR-PKG0002). A tree is the package's own: another package's@nameis another tree, and two packages that compile one tree define its symbols twice (rule 12).A tree is read only where a build needs it: where a table that holds for the build's target names it.
lyric checkreads only those its bindings need (§5.4);lyric metadataand the editor read none. What a build reads is fetched into the user's cache — a URL's file once by its hash, unpacked once —, under--offlinenot at all (LYR-PKG0007). A URL withouthashis refused, the message giving the hash of what it loaded (LYR-PKG0002); a file whose hash is another is refused, the message giving both (LYR-PKG0008), as is a revision whose content is not what the lock holds; a revision the repository does not have (LYR-PKG0006); a repository or a URL that cannot be reached is the environment's (LYR-PKG0007, exit 2).The lock (§3) holds a git tree a build read as it holds a package read from git — its repository, revision, commit and the hash of its content —, written
kind = "native", withof, the name of the package whose tree it is, and noversion; a URL's tree is held by itshashin the manifest, not in the lock. A build adds the trees it resolved; reading the graph keeps the trees a manifest of the graph still names so and drops the rest — a tree no build has needed is not held. Under--lockeda build that needs a tree the lock does not hold is refused (LYR-PKG0011), as §3 rule 4 refuses a revision.lyric updatereads the trees the lock holds anew — those it names, or every one —, a branch at its head and a moved tag at its commit; a tree's tag is not raised, as a tree has no version.A tree runs nothing: it is compiled, as the package's sources are, and no trust is asked for it (§8 rule 6). What an archive does, its bytes say; the lock holds them.
5.4 Bindings
bindings = [{ header = "@raylib/src/raylib.h", module = "rl" }]makes a module of the package from a C header:rlingameis the modulegame.rl, a path of segments as §2's modules have, each a lowercase letter, then letters, digits and_(LYR-PKG0002). Its declarations arepub, its names C's. A module of that path undersrc/,gen/ortests/is refused (LYR-RES0016). The packages that declare the package as a dependency import it as any of its modules.bindingsis a key of every table of rule 4, layered as the others.The module is made for the build's target, from what the C compiler reads of the header with the package's
includeanddefines— C's types differ between targets. It holds the declarations of the header and of the headers beside and below it, in the order they come, not the system's:- a function as
extern "C" fn(13 §2), with...where it is variadic; - a struct as a
@Layout(C)struct of the same fields (13 §3 rule 4), eachvar— C writes any of them —; a struct C declares without its fields asPtr<void>where a pointer names it; - an enum's constants as module-level constants of its integer type, and the enum's name as an alias of that type;
- a
typedefas an alias (03 §10), a pointer to a C function as its typeextern "C" fn(…) -> R; - a
#definewhose body is one integer literal, or one string literal, as a constant.
The C types as 13 §2–§3 cross them: the integers by their width on the target —
charas the target'sint8oruint8,size_tasuint,ptrdiff_tasint—,floatanddouble,bool;const char *as?CStr; any otherT *as?Ptr<T>,void *as?Ptr<void>; an array parameter as the pointer it is. In a field a pointer is?Ptr<T>or?CStras well; a C function's pointer is its type, not optional — 13 §3 rule 4 takes none —, so a null there is the program's to look for; and an array of arrays is one array of all their elements,float m[4][4]asfloat32[16], laid out alike. A constant is apub let: an enum's of its integer type; a#define's integer of the type C gives the literal — the first ofint32andintit fits, unsigned with ausuffix or where a hexadecimal or octal one needs it,intoruintwith anl—, so that it goes where C'sintgoes; its string asstring. A name that is a word of Lyric or a builtin type's name gets a_after it:stringasstring_.- a function as
What it cannot write — a union, a bit field, a struct with one, a function-like macro, a
static inlinefunction, a variable, a declaration that needs one of them — is left out, and the module's last lines list each by its name, its file and line, and why; a#definewith an empty body — an include guard — is passed over. No lint looks at the module (16 §5): it is written by the toolchain, as a dependency's modules are written by others.A header that does not compile, or a module the toolchain cannot write — a C compiler that writes no syntax tree, which only zig cc and clang do —, stops the build (
LYR-BLD0005, exit 1) with what the C compiler said. The module is made anew where the header, a header it reads, thedefines, the target or the toolchain changed.lyric bindgenwrites the module one entry makes to standard output, to keep it undersrc/instead (14 §2 rule 6).
6. Reproducibility
(11 P6)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, ReproducibilityTests): one
package built in two directories a second apart — for the host in both built-in profiles, and for
each operating system from any host — compared byte for byte.
- The same sources, options, toolchain and C compiler give the same bytes — wherever the
package lies, wherever the build runs from, and whenever it is built. A binary carries no time
stamp, and no path of the machine that built it: a path the build would write into it — a
source's, the emitted C's, the runtime's — is written as the name of the package it lies in, or
lyricfor the toolchain's own, and the directory the C compiler works in as.. A library the C compiler brings of its own — zig'slibunwindon Linux — comes as the C compiler built it. - Debug information that names the machine's paths lies beside the binary, not in it: a
Windows binary's PDB, a macOS binary's
.dSYM— gathered on a macOS host, wheredsymutilis. The binary names it by a hash of its own bytes — a PE image's PDB GUID, a Mach-O image's UUID —, so the two still pair. - A package's archives, shared libraries and source trees (§5.2, §5.3) are inputs as
its sources are: the lock holds their bytes, and an archive comes into the binary as it was
built — what it carries of the machine that built it is its own. A library linked by name,
through
pkgConfigor from a directory a build script names (§8 rule 3.1) is the machine's: the same bytes need the same system libraries.
7. Tests
(07 V4)
Conformance. The toolchain's own tests (tests/Lyric5.Tests, TestCommandTests).
- A package's
tests/, besidesrc/, holds modules of the package:tests/math.lyrinappisapp.tests.math. A test there sees what the package does not makeprivate; a test beside the code, in the module it tests, sees that module'sprivatetoo. A module that would lie both undersrc/tests/and undertests/is refused (LYR-RES0015). - Only
lyric testcompilestests/(14 §3): no program's build reaches it, and a package's content (§2) leaves it out.
8. The build script
(11 W3 BS1–BS6; M8b S13.)
- A package's
build.lyr, at its root, is a program that runs before the package compiles. It does things — writes modules intogen/, names C to compile, libraries to link and where to find them, and files to put beside the program — and defines nothing: what the package is, the manifest says (§1). - It is a program of its own: its module is
build, a filebuild/x.lyrbeside it the modulebuild.x, and it imports fromstdand from the packages of the manifest's[build-dependencies], a graph of its own (§2), read at the commits the same lock holds and held in it beside the program's (§3). Nothing of it is compiled into the package, and the package's program sees none of its dependencies;buildnames no package of that graph. It runs on the host, with the package's root as its working directory, whatever the build's target. std.buildis its view of the build:target()andprofile(), the build's;outDir(), the package'sout/;genDir();rerunIfChanged(paths…),rerunIfEnvChanged(names…),linkLib(name),linkSearch(dir),besideBinary(paths…)— paths from the package's root, or absolute —, andwarn(message), which the build shows (LYR-BLD0003); and those of rules 3.3–3.6. Outside a build script they panic.linkSearch(dir)names a directory the link searches for the libraries oflinkLiband of[native]'slibs(§5), before the linker's own and in the order named — the scripts of dependencies by their names, the root's last. For a Windows target a libraryXis found asX.dll,X.lib,libX.a, or as the import librarylibX.dll.aorX.dll.aa MinGW toolchain makes. No directory the link searched is written into the binary: a shared library is found when the program starts where the system looks, or beside it (rule 3.2). A directory that is not there is no error: the link that does not find a library says where it searched.besideBinary(paths…)names files the program needs beside it when it runs — a shared library above all. After each link the build copies them, under their own names, into the directory of every binary it makes of the program — ofbuildandrun, oftestandbench(14 §3), of a library--libmakes, not of a build script —, and such a binary searches its own directory for shared libraries first: an ELF binary by the run path$ORIGIN, a Mach-O binary by@executable_path; a Windows binary does so by itself. A file that is not there when the script has ended, and two files of one name — counting thedylibsof §5 rule 8 —, stop the build (LYR-BLD0006, exit 1).target()is aBuildTarget— itstriple, itsosandarchas the prelude'sPlatformandArchname them (.Linux,.Windows,.MacOS;.X86_64,.Aarch64), and whether itisHost, the machine the script runs on.cLibrary(name)is a C library the script compiles with the program — itssources(…), patterns as[native]'ssources,include(…),define(name)anddefine(name, value), andflags(…), the C compiler's own — andcompile()adds it. Its sources see its ownincludefirst, then what the package's sources see (§5 rule 6); its definitions and flags are its own, no other source's. Its paths are the package's or a tree's (@name/…); another is refused (LYR-BLD0002).linkLib(name),linkArchive(path),linkFramework(name)andpkgConfig(name)add to the package's native part whatlibs,archives,frameworksandpkgConfigadd (§5), with their rules; an archive the script names — underout/, where it made it, or absolute — is the script's, not of the package's content (§5 rule 7).vendorDir(name)is the directory of the package's source treename(§5.3), read when the script asks for it: the script stops, the build reads the tree, and the script runs again from its start with the tree there. A name[native.vendor]does not hold is refused (LYR-BLD0002).cEnv()is the environment —CC,AR,CFLAGS— under which another build system compiles C for the target with the toolchain's C compiler:CCandARrun the toolchain's compiler for the target, as the build's own C is compiled, andCFLAGSholds the profile's optimization.
gen/, which the toolchain makes before the script runs, is a module space of the package:gen/schema.lyrinappisapp.gen.schema, astests/is §7's. It is no part of the package's content (§2).- When it runs: before the compile, where the script changed —
build.lyr,build/, its dependencies, the toolchain, the target, the profile —, where a file it named withrerunIfChangedchanged, where an environment variable it named withrerunIfEnvChangedhas another value than in its last run — set where it was not, or not where it was —, or wheregen/is not as it left it; else what its last run asked stands. What the script's state holds of a variable is a hash of its value, not the value. A script that does not compile, that ends with an exit other than 0, or that does not end within 10 minutes, stops the build (LYR-BLD0002), with what it wrote — exit 1, as a program refused (14 §1.3): the package's code failed, not the environment. - Trust: the root package's script always runs; a dependency's only where the root
manifest's
[trust] build-scripts = ["geo"]names the package. Else the build stops before anything runs (LYR-PKG0012), at the line that declares the dependency.