Building
How pcpp turns a main module into an executable or a library: what each kind builds, what the output folder holds, what each optimize level changes, how a target is built and run, and how libraries and the runtime are linked.
What a build makes
module exe builds an executable, module dll a shared library and module lib a static library. A unit is not built on its own: given to pcpp as the main module it is PR0004.
pcpp writes a C++23 header and source for each module and builds them with the bundled Zig toolchain (clang, -std=gnu++23) through zig build, which caches compiles. The toolchain folder is read from build.toml beside pcpp.exe (toolchain_path); the default is $P:res, the res folder beside pcpp.exe.
A successful build prints Build succeeded. and then Output: <path of the artifact>.
The output folder
The output folder is the -o option, else the @outputpath directive, else output under the working folder. It holds:
| Path | What it is |
|---|---|
build.zig | the build script pcpp writes |
pcpp-output.json | pcpp's record of the build: format, source, output folder, project |
pcpp-installed.txt | the record of the files the build put in bin\ and lib\ |
generated\<Module>.pcpp.h, .pcpp.cpp | the C++ written for each module |
pcpp-diag\ | clang's diagnostics, one file per translation unit |
.zig-cache\ | zig's cache |
bin\ | an exe or a dll |
lib\ | a lib (and a Windows dll's import library) |
| Kind | x86_64-windows-gnu | x86_64-linux-gnu |
|---|---|---|
| exe | <name>.exe | <name> |
| dll | <name>.dll (import library <name>.lib in lib\) | lib<name>.so |
| lib | <name>.lib | lib<name>.a |
- A Windows debug build writes the program's
.pdbbeside the exe or dll; asafe,fastorsmallbuild writes none, and neither does a Linux build. - Every file a build puts in
bin\andlib\(the program or library, its.pdb, a dll's import library, the@copydllfiles) is recorded inpcpp-installed.txtin the output folder. Before the next build, a recorded file that build does not produce is removed, withRemoving bin/<file>: an earlier build put it there, this build does not produce it: a debug build's.pdbbefore afastbuild, a program or a copy the build no longer makes. A file the record does not name is never removed. - An output folder longer than 198 characters is ZB0021 and nothing is built: zig launches its configure program from a folder nested under the output folder.
Optimize levels
With no @optimize (and no -opt) the build is debug.
| Level | Defines | Heap report |
|---|---|---|
debug | PCPP_DEBUG | yes |
safe | __OPTIMIZE__ | no |
fast | __OPTIMIZE__, NDEBUG | no |
small | __OPTIMIZE__, __OPTIMIZE_SIZE__, NDEBUG | no |
A debug build prints the runtime's heap report, [Heap] Allocs: <n>, Frees: <n>, Leaked: <n>, when the program ends. The level names are zig's own: build.zig writes the level as zig's optimize mode of the same name (small is std.lang.Optimize = .small).
module exe build_debug;
// What the C++ compiler sees at this optimize level
static const char* build_debug_flag()
{
#ifdef PCPP_DEBUG
return "yes";
#else
return "no";
#endif
}
begin
println("PCPP_DEBUG: {}", build_debug_flag());
end.
PCPP_DEBUG: yes
[Heap] Allocs: 0, Frees: 0, Leaked: 0
module exe build_release;
@optimize fast;
// What the C++ compiler sees at this optimize level
static const char* build_release_debug()
{
#ifdef PCPP_DEBUG
return "yes";
#else
return "no";
#endif
}
static const char* build_release_ndebug()
{
#ifdef NDEBUG
return "yes";
#else
return "no";
#endif
}
begin
println("PCPP_DEBUG: {}", build_release_debug());
println("NDEBUG: {}", build_release_ndebug());
end.
PCPP_DEBUG: no
NDEBUG: yes
Targets and running
The same source builds for x86_64-windows-gnu and x86_64-linux-gnu, from Windows: @target in the source (see Target) or pcpp -t.
pcpp <file> -rbuilds the exe and runs it in its own folder; a Linux exe runs through WSL.- A program that exits with a code other than 0 under
-ris ZB0031 (Program exited with code <n>.), and pcpp exits with that code. -ron a dll or a lib is the warning CMP0002 (a dll cannot be run: auto-run skipped); the build itself succeeds.
Linking libraries
An exe links a PaskalCPP dll by name (@linklibrary) from the folder @addlibrarypath names (Windows: the import library in the dll's lib\; Linux: the .so in its bin\), declares the dll's routines external, and @copydll puts the library beside the exe so it is found at run time.
@copydllfiles are copied before the build; a file an earlier build copied beside the artifact that no@copydllnames any more is removed.- A routine no linked library defines fails at the link as ZB0016 in the linker's words, reported at the .pcpp line that calls it.
Static libraries and the runtime
- A lib whose code never calls into the PaskalCPP runtime ships alone, with no startup hook, and a C program links it with a plain C driver.
- A lib that calls into the runtime (div, mod, a guard, raise, sets, ...) gets a startup hook, and pcpp builds the runtime library and publishes it beside the lib (
pcpp_runtime.lib; on Linuxlibpcpp_runtime.a), printingPublishing ... to .... - A lib that no longer calls into the runtime removes the
pcpp_runtimean earlier build published beside it. - A PaskalCPP program that links such a lib brings its own runtime and never links
pcpp_runtime; a raise inside the lib reaches the program's guard. - A C program built by another toolchain links the lib, then
pcpp_runtime, through a C++ driver; withoutpcpp_runtimethe link fails onpcpp::init.
Resource stamps
@exeicon, and @addverinfo on with the @vi* fields, are stamped on the built Windows binary after the build; where a stamp does not apply it is the warning SM0103 (see Values). A requested stamp that fails is an error (icon ZB0008, version info ZB0009), and nothing is published.