Projects and the build
The language design document (§34) defines what the build does (compiling, monomorphization, optimizing, linking, FFI, libraries), but not how a project is described. This document fills that gap.
Basic model
Section titled “Basic model”- A program consists of all
.cshiftfiles passed to it; there are no headers and no translation units in the C sense. The compiler analyzes the whole program at once (symbols are resolved globally, generics are instantiated per type combination) and writes one object file, which it then links. - Because of that, a project only needs, at its core: a name, the source files, the target (a program or an object file), the optimization level, and any extra libraries.
- There is no incremental build or inter-project dependencies (yet). At the program’s current size, a full rebuild is fast (on the order of 0.2 s).
Stage 1 (implemented): the declarative project file cshift.json
Section titled “Stage 1 (implemented): the declarative project file cshift.json”{ "name": "demo", "version": "0.1.0", "type": "executable", "sources": ["src"], "output": "bin/demo", "optimize": 2, "links": ["sqlite3"], "target": "x86_64-w64-windows-gnu"}| Key | Meaning | Default |
|---|---|---|
name |
the project name (letters, digits, _ - .); required |
– |
version |
version (informational only) | – |
type |
"executable" (link a program), "object" (object file only) or "library" (source code for other projects, see dependencies; build only checks it) |
"executable" |
sources |
a list of files and folders; folders are searched recursively for *.cshift (and *.csh, the extension until 0.31), paths are relative to cshift.json |
["src"] |
output |
the output path without an extension (.exe/.obj/.o is added depending on the platform) |
"bin/<name>" |
optimize |
0–3 (like -O0 … -O3) |
2 |
links |
libraries for the linker: a name (-l<name>) or a file (libs/libminifb.a, x.o, x.lib; has a path or extension); in addition to link "name" in source code |
[] |
includePaths |
search paths for C headers (using X from "h.h"), relative to cshift.json |
[] |
dependencies |
libraries the project uses: folders (or cshift.json files) of projects with "type": "library", relative to cshift.json. Their sources, links, includePaths, libraryPaths, defines and ffiApi (with their platforms entries for the platform that is built) become a part of the project; libraries may have dependencies themselves, one that is reached twice is used once, a cycle is an error (projects) |
[] |
defines |
macros used when parsing C headers (NAME, NAME=value) |
[] |
libraryPaths |
linker search paths (-L) |
[] |
ffiApi |
path fragments of C headers that belong to the imported API even when they live in system paths (--ffi-api=, see ffi.md) |
[] |
target |
the target triple; a 32-bit triple (i686-linux-gnu, m68k-…, arm…) makes pointers, nint/nuint and sizes 32 bits; m68k-amigaos builds an Amiga program (amiga.md) |
host |
backend |
the code generator: "llvm" (LLVM IR, clang), "m68k" (CShift’s own 68000 backend) or "wasm" (CShift’s own WebAssembly backend, wasm.md); like --backend |
m68k for AmigaOS, else llvm |
ndk |
the AmigaOS NDK folder, relative to cshift.json (like --ndk; CSHIFT_NDK is used if it is not set): SFD files for using X from "lib.sfd";, Include_H for C headers |
– |
debug |
true: debug information for gdb and lldb (like -g, see debugging.md) |
false |
unchecked |
true: integer overflow wraps around instead of a panic in the whole project (like --unchecked; division by zero and index checks stay; --checked on the command line overrides it) |
false |
assets |
files and folders that the program reads at run time, relative to cshift.json and inside of the project: cshiftc publish puts them into the page, where the program finds them at the same paths (wasm.md) |
[] |
platforms |
additions per platform: { "windows": {...}, "linux": {...}, "macos": {...} }, each with links, includePaths, libraryPaths and/or defines, appended to the common lists when building for that platform (e.g. "windows": { "links": ["opengl32"] }, "linux": { "links": ["GL"] }) |
none |
Unknown keys produce a warning, invalid values an error naming the file. $schema is allowed; the VS Code extension
ships a schema that validates and auto-completes cshift.json.
Commands
Section titled “Commands”cshiftc new <folder> a new project (cshift.json, src/main.cshift, .gitignore)cshiftc build [project] build itcshiftc run [project] build and run it; the arguments after -- go to the program: cshiftc run -- input.txt --verbosecshiftc publish [project] the program for the browser: bin/<name>.html with everything in it (wasm.md)cshiftc serve [project] the page on http://localhost:8080/, built again when a file changescshiftc [options] a.cshift b.cshift single files without a project (as before)Source files end in .cshift. .csh, the extension until 0.31, is still read (in projects, folders and on the command
line), so older projects build unchanged; the compiler’s own sources still use it (see compiler.md).
project is a folder containing cshift.json, or the path to the file. Without it, cshift.json is looked up in
the current folder and its parent folders. Command-line options (-O2, --target, -o, --cc, -l…, -v)
override the file (as do --backend and --ndk).
Why JSON?
Section titled “Why JSON?”- No code needed to read the project: the compiler understands it directly (LLVM already brings a JSON parser along, so this adds no new dependency). YAML would need to bring its own parser; Makefiles are platform-dependent and too powerful for a single-program model.
- Editor support via a JSON schema (completion, errors while typing).
- As a plain data model, it also becomes the intermediate format for stage 2 later.
Stage 2 (idea): a build written in the language itself, like Zig
Section titled “Stage 2 (idea): a build written in the language itself, like Zig”For cases a single file can’t express (sources conditional on the platform, code generation before the build,
multiple targets, dependencies, tests), a build.cshift sits next to, or instead of, cshift.json:
using System.Build;
Error<void> Build(ref Builder b){ var exe = b.AddExecutable("demo"); exe.AddSources("src"); exe.Link("sqlite3"); exe.SetOptimize(2);
if (b.Target().IsWindows()) exe.AddSources("platform/windows");
var tests = b.AddExecutable("demo-tests"); tests.AddSources("src", "tests"); b.AddRunStep("test", tests); return;}This is how it would work:
cshiftc buildfinds abuild.cshiftand compiles it together with the standard library and a smallSystem.Buildmodule into a temporary program.- That program is run;
Build(...)describes the targets. The result is exactly the data model from stage 1 (one or more project descriptions with the same fields), which the compiler then builds. - The language itself is the scripting language; there’s no second format to learn.
The standard library already has what this needs at the language level — Process.Run/RunCapture/GetEnv/IsWindows,
Directory/Path, and Main(string[] args) for command-line arguments — plus a JSON parser (used to read
cshift.json itself). What’s still missing is the System.Build module described above (a thin, typed layer over
that data model) and named steps (cshiftc build test). Until then, cshift.json stays the standard way; stage 2
doesn’t replace it, it complements it for special cases.
Open items
Section titled “Open items”- Multiple targets in one
cshift.json(e.g. a program plus tests),cshiftc test. - Packages beyond local folders (
dependenciesnames folders): versions, a place to publish and fetch them, a lock file. A package stays source code (with prebuilt C libraries per platform where it needs them): the whole program is compiled at once and generics are instantiated per use, so there is no binary CShift library format. - An intermediate
obj/directory, incremental builds (only useful once translation units are separated). - Variables/conditions in the project file (
"sources"per platform) — or handle that directly viabuild.cshift.