Cella Documentation 0.1.0-dev Home Source

Project settings

A project file, the .celp file in a project's folder, is written in TOML. This page lists every setting it can hold, the values each takes and what it does when it's left out. Projects and building introduces project files and the commands that read them.

Summary

SettingValuesDefaultIn [When] tables
OutputType"Executable", "WindowedExecutable", "SharedLibrary", "StaticLibrary"requiredno
CellaVersiona version such as "0.1.0"noneno
StandardLibrary"Full", "Core", "None""Full"no
SystemLinkPreference"Dynamic", "Static""Dynamic"yes
AssemblyNamea file namethe project file's nameyes
BoundsCheckstrue, falsetrueyes
OverflowCheckstrue, falsetrue in debug builds, false in release buildsyes
DebugInfotrue, falsetrueyes
Referenceabletrue, falsefalseyes
Importsa list of import pathsnoneno
Preludea list of import pathsnoneno
[Flags]flag names set to true or falsenoneno
[Lints]lint names set to "Off", "Hint", "Warning" or "Error"each lint's own levelyes
[Naming]kinds of names set to patternsthe usual styleno
[[ProjectReferences]]Path and Aliasnoneyes
[When."..."]a condition and the settings it changesnone

Setting names are case-sensitive, and any other name is an error such as "Unknown setting 'Optimize'". A setting given twice is an error too.

OutputType

What the project builds. It's the one setting every project file needs; without it the build stops with "Missing 'OutputType'".

ValueBuildsWindows fileLinux file
"Executable"a programname.exename
"WindowedExecutable"a program that opens no console window on Windowsname.exename
"SharedLibrary"a library loaded when a program startsname.dlllibname.so
"StaticLibrary"a library linked into each program that uses itname.liblibname.a

name is the AssemblyName. Executables need a main function, as Functions explains.

CellaVersion

The version of Cella the project is written for. cella new writes the version that created the project. When you run cella, the launcher reads this setting and runs that version of the compiler, which must be installed; without it, the launcher runs the newest version installed. Projects and building covers the launcher.

The compiler compares the setting with its own version. A project pinned to a newer version is an error ("Pinned to Cella 99.0.0, newer than this compiler"), and one pinned to an older version gets a warning. The value must be a full version with three numbers, such as "0.1.0" or "0.2.0-dev".

StandardLibrary

How much of the standard library the project references.

ValueReferences
"Full"all of the standard library
"Core"only the parts that don't depend on the operating system
"None"nothing

With "None", a project has no panic unless it declares one, as Checks and panics shows.

SystemLinkPreference

How a program links the C runtime when it's built for Windows with Visual Studio's C++ build tools. "Dynamic" uses the runtime's DLLs, and "Static" copies the runtime into the program. Other builds link the C runtime the same way with either value.

All projects in one program must agree, in every build. A program that links the C runtime statically can't use a shared library project, and a library used by two programs that link differently is an error. Calling C covers linking.

AssemblyName

The name of the output file, without its extension or lib prefix. It defaults to the project file's name, so game.celp builds game.exe. It must be a valid file name, so it can't be empty or contain a path, and the name of a shared library must be ASCII.

BoundsChecks

Whether indexing an array or a string checks that the index is in range, stopping the program with a panic when it isn't. On by default in every build. The built-in flag boundsChecks says whether the checks are on. Checks and panics covers the checks.

OverflowChecks

Whether arithmetic checks for overflow, stopping the program with a panic when a result doesn't fit its type. On by default in debug builds and off in release builds. The built-in flag overflowChecks says whether the checks are on. Numbers and Checks and panics cover overflow.

DebugInfo

Whether the build includes debug information for debuggers. On by default.

Referenceable

Whether other projects can reference this executable and use its pub declarations, as they would a library's. A referenceable executable is built as a shared library that holds its code, and a small program that runs it. The setting applies only to executables, and a referenceable executable can't link the C runtime statically. Referencing an executable without it is an error that names the executable's project file: "... is an executable without 'Referenceable = true'".

Imports and Prelude

Imports lists imports that apply to every source file in the project, written as they would be after use. Prelude lists imports that apply to every project that references this one. Modules and visibility covers both.

Flags

[Flags] declares the project's own flags, each set to true or false. Code tests them with when:

OutputType = "Executable" [Flags]verbose = true
main: fun{	when verbose	{		printf("starting\n")	} 	printf("done\n")}
Output
starting
done

A flag's name must be an identifier, and it can't be the name of a built-in flag. cella build --flag verbose=false changes a flag's value for one build, as Projects and building shows. Conditional compilation covers when.

The built-in flags are always defined:

FlagTrue when
windows, linux, macosbuilding for that operating system
x64, x86, arm64, wasm64building for that processor
debugbuilding without --release
releasebuilding with --release
boundsChecksbounds checks are on
overflowChecksoverflow checks are on

Lints

Some of the compiler's hints and warnings come from lints, checks for code that works but is likely a mistake or could be simpler. [Lints] sets how each is reported: "Off" drops it, and "Hint", "Warning" and "Error" report it at that level. An error from a lint stops the build like any other:

OutputType = "Executable" [Lints]UnusedLocal = "Error"NeverChanged = "Off"
main: fun -> i32{	var count = 3	val spare = count * 2'spare' is never used	ret count}

count is a var that never changes, which would get a hint, but NeverChanged is off. The lints and their usual levels:

LintReportsLevel
Redundantmarks that change nothing, such as an imm where a value is borrowed anywayhint
RedundantImportimports of names the file can already usehint
NeverChangedvar variables that are never changedhint
UnusedLocallocal variables that are never usedhint
UnusedDeclarationfunctions and globals that nothing useshint
UnusedImportimports that the file never useshint
Namingnames that don't follow the [[Naming]](#naming) ruleshint
UnreachableCodecode that can never runwarning
FloatPatternpatterns that compare floatswarning
SelfConversionconversions that call themselveswarning
EndlessRecursionfunctions that call themselves on every pathwarning

UnusedDeclaration leaves out pub declarations, main, operators and ext functions. Hints are shown only in builds given --hints (see Projects and building). [When."condition".Lints] tables change single lints in some builds, so [When.release.Lints] with UnusedLocal = "Warning" would keep release builds going.

Naming

The Naming lint checks every name a project declares against a pattern for its kind. [Naming] replaces the pattern for some kinds:

OutputType = "Executable" [Naming]Constants = "{SCREAMING_CASE}"Types = "{PascalCase}|C{PascalCase}"
MAX_PLAYERS: const i32 = 4 CPoint: rec{	x: i32} main: fun{	val point = CPoint(MAX_PLAYERS)	printf("%d\n", point.x)}
Output
4

A pattern is a style in braces, {PascalCase}, {camelCase}, {snake_case}, {SCREAMING_CASE} or {lowercase}, with any letters, digits or _ before and after it, as in C{PascalCase}. | separates patterns a name may match instead. PascalCase and camelCase names don't allow two capital letters in a row, so HttpServer matches and HTTPServer doesn't.

KindNamesUsual pattern
Typesrecords, enums and unions{PascalCase}
Traitstraits{PascalCase}
TypeParameterstype parameters{PascalCase}
Functionsfunctions and methods{camelCase}
Fieldsfields, including payload fields{camelCase}
Propertiesproperties{camelCase}
Localslocal variables{camelCase}
Parametersparameters, including value parameters{camelCase}
Constantsconstants{camelCase}
Globalsglobal variables{camelCase}
EnumCasesenum cases{camelCase}
Moduleseach part of a module path{camelCase}

Names declared in ext blocks and the members of trait implementations aren't checked, since their names come from C or from the trait. A name that doesn't match gets a hint such as "'max_players' doesn't match {camelCase}".

ProjectReferences

Each [[ProjectReferences]] table makes the project use another one, usually a library. It has two settings:

SettingMeaning
PathThe other project's .celp file, relative to this project's folder. Required.
AliasA name to reach the other project's modules through. Optional.

Without an alias, the other project's modules are reached by their own names. With one, they are reached only through the alias, which keeps modules of the same name in different projects apart:

OutputType = "Executable" [[ProjectReferences]]Path = 'geometry/geometry.celp'Alias = 'geo'
geometry/geometry.celp
OutputType = "StaticLibrary"
geometry/shapes.ce
mod shapes area: pub fun(width: f64, height: f64) -> f64 => width * height
main: fun{	printf("%.1f\n", geo.shapes.area(2.0, 3.0))}
Output
6.0

An alias must be an identifier, can't be the name of a built-in type, and can't name two references. Projects and building covers using library projects.

When tables

A [When."condition"] table changes settings in the builds where its condition holds. The condition uses flags, built-in or the project's own, with !, &&, || and parentheses, as in a when block. A condition that is a single flag can leave out the quotes: [When.debug].

OutputType = "Executable" [Flags]fast = false [When.debug]OverflowChecks = false [When."release || fast"]BoundsChecks = false
main: fun{	when overflowChecks	{		printf("overflow checks on\n")	}	else	{		printf("overflow checks off\n")	} 	when boundsChecks	{		printf("bounds checks on\n")	}}
Output
overflow checks off
bounds checks on

This is a debug build, so the first table applies and the second doesn't. A release build, or one with --flag fast, would also turn bounds checks off.

A setting in a When table replaces the one at the top level. Only SystemLinkPreference, AssemblyName, BoundsChecks, OverflowChecks, DebugInfo, Referenceable, [Lints] and project references can go in one; a Lints table replaces only the lints it names. [[When."condition".ProjectReferences]] tables add references in the builds where the condition holds, after the ones at the top level:

[[When.windows.ProjectReferences]]Path = 'win32/win32.celp'

Two tables whose conditions both hold can't set the same setting: that's an error such as "'BoundsChecks' is set more than once, by [When."debug"] and [When."windows || linux"]".

Problems in project files

The compiler checks the whole project file before building and reports every problem it finds. Besides unknown and repeated settings, it reports values of the wrong kind, each naming the setting and the table it's in:

  • "'Program' is not a valid 'OutputType'"
  • "'BoundsChecks' must be true or false"
  • "'logging' in [Flags] must be true or false"
  • "Unknown lint 'Unused' in [Lints]"
  • "'Loud' is not a valid 'Naming' in [Lints]"
  • "'Pascal' is not a valid 'Types' in [Naming]"
  • "'Imports' must be a list of strings"
  • "Missing 'Path' in [[ProjectReferences]]"
  • "Project 'lib/lib.celp' not found"
  • "Cannot set 'OutputType' in [When."debug"]"
  • "Flag 'unknown' not found in [When."debug && unknown"]"

A folder can hold only one project file; a second one is an error, "Cannot share a directory with 'other.celp'".