eskiuv0.9.2
Language · Building & tooling

Building Eskiu from Source

Requirements

Dependency Minimum Tested
LLVM 21 22.x
CMake 3.20 3.x
C++ compiler C++17 (clang++ recommended, g++ works) clang++ 17+
git any n/a

LLVM is the only non-trivial dependency. The compiler uses the support, core, and irreader component libraries.


macOS

Install dependencies

brew install llvm cmake

Homebrew installs LLVM into a versioned prefix (e.g. /opt/homebrew/opt/llvm) and does not add it to PATH by default. Export the necessary paths before building:

export PATH="$(brew --prefix llvm)/bin:$PATH"
export LLVM_DIR="$(brew --prefix llvm)/lib/cmake/llvm"

Add these to your shell profile (~/.zshrc or ~/.bash_profile) to make them permanent.

Homebrew's llvm formula tracks the newest release (LLVM 23 at the time of writing). Eskiu builds against it, but CI and the release binaries use LLVM 22. To match them exactly, install llvm@22 and use $(brew --prefix llvm@22) in the two lines above.

Build

git clone https://github.com/doranteseduardo/eskiu.git
cd eskiu
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j$(sysctl -n hw.logicalcpu)

Expected output (last few lines):

[ 85%] Building CXX object CMakeFiles/eskiuc.dir/codegen/codegen_expr.cpp.o
[100%] Linking CXX executable eskiuc
[100%] Built target eskiuc

The compiler binary is at build/eskiuc.


Linux (Ubuntu / Debian)

Install dependencies

sudo apt-get update
sudo apt-get install -y llvm-22-dev clang-22 cmake git

For Ubuntu 22.04 or older, the LLVM 22 packages are in the LLVM apt repository:

wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 22
sudo apt-get install -y llvm-22-dev

Build

git clone https://github.com/doranteseduardo/eskiu.git
cd eskiu
cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_DIR=/usr/lib/llvm-22/lib/cmake/llvm \
  -DCMAKE_CXX_COMPILER=clang++-22
cmake --build build -- -j$(nproc)

Linux (Alpine)

Install dependencies

apk add llvm22-dev cmake clang22 git make

Build

git clone https://github.com/doranteseduardo/eskiu.git
cd eskiu
cmake -S . -B build \
  -DCMAKE_BUILD_TYPE=Release \
  -DLLVM_DIR=/usr/lib/llvm22/lib/cmake/llvm \
  -DCMAKE_CXX_COMPILER=clang++
cmake --build build -- -j$(nproc)

Build Options

Debug vs Release

# Release: optimized binary, suitable for benchmarks
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release

# Debug: unoptimized, assertions enabled, better stack traces
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug

Incremental builds

After changing source files, just re-run the build step; CMake tracks dependencies:

cmake --build build -- -j$(nproc)

Clean rebuild

Delete the build directory and start over:

rm -rf build
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -- -j$(nproc)

Verify the Build

Version check

./build/eskiuc --version

Expected output:

Eskiu 0.9.2 (LLVM 22.x.x)

The LLVM version will reflect whichever version is installed on the host.

Smoke test

./build/eskiuc examples/hello.esk --test-codegen

Expected output (LLVM IR for hello.esk):

; ModuleID = 'eskiu_module'
source_filename = "eskiu_module"

@0 = private unnamed_addr constant [19 x i8] c"Hello from Eskiu!\0A\00"
@1 = private unnamed_addr constant [12 x i8] c"Result: %d\0A\00"

declare i32 @printf(ptr, ...)

define i32 @add(i32 %a, i32 %b) {
entry:
  ...
}

define i32 @main() {
entry:
  ...
}

The exact IR body will vary with LLVM version, but the module must contain @printf, @add, and @main.


Troubleshooting

LLVM not found

CMake Error: Could not find a package configuration file provided by "LLVM"

Point CMake at the correct LLVM cmake directory:

cmake -S . -B build -DLLVM_DIR=/path/to/llvm/lib/cmake/llvm

Common paths:

Platform Path
macOS (Homebrew arm64) /opt/homebrew/opt/llvm/lib/cmake/llvm
macOS (Homebrew x86) /usr/local/opt/llvm/lib/cmake/llvm
Ubuntu apt llvm-22 /usr/lib/llvm-22/lib/cmake/llvm
Alpine apk llvm22 /usr/lib/llvm22/lib/cmake/llvm

You can also run llvm-config --cmakedir (substituting the versioned binary name if needed) to get the correct path:

llvm-config-22 --cmakedir

C++17 errors

If the system default compiler does not support C++17, specify the compiler explicitly:

cmake -S . -B build \
  -DCMAKE_CXX_COMPILER=clang++-22 \
  -DCMAKE_C_COMPILER=clang-22

Linker errors: undefined LLVM symbols

The build links support, core, and irreader. If you see undefined symbols from LLVM:

  1. Confirm the installed LLVM version matches the headers used at configure time (llvm-config --version).
  2. On Ubuntu, ensure you installed llvm-22-dev (not just llvm-22); the -dev package contains the static libraries.
  3. On Alpine, llvm22-dev is the correct package name; llvm22 alone does not ship the .a archives.

Running Tests

The automated suite is driven by tests/run.sh, which compiles, links, and runs every tests/*.esk case (matching stdout against *.expected, smoke-running the rest, and checking that tests/errors/*.esk are rejected). eskiuc links each test itself with no -l flags, so the libraries programs imply (#pragma link, the C++ exception runtime, pthread) are exercised too:

tests/run.sh                       # full suite against build/eskiuc
ESKIUC=/path/eskiuc tests/run.sh   # point at a specific compiler

CI runs the suite three ways: plain, then under UBSan and ASan (SANITIZE=ubsan / SANITIZE=asan) as hardening gates, plus a generative fuzzer (tests/fuzz/eskiu_fuzz.py) that mutates programs and fails on any compiler crash, IR-verifier failure, or O0-vs-O2 runtime divergence (a differential oracle); a golden-IR oracle guards against unintended codegen changes.

The four --test-* modes below expose individual compiler phases for manual inspection.

--test-lexer

Tokenizes the input and prints every token with its type, value, and source location.

./build/eskiuc examples/hello.esk --test-lexer

Expected output (truncated):

Tokenizing: examples/hello.esk
========================================================
  Line   1, Col   1           EXTERN  'extern'
  Line   1, Col   8              INT  'int'
  Line   1, Col  12            IDENT  'printf'
  Line   1, Col  18           LPAREN  '('
  Line   1, Col  19           STRING  'string'
  ...
========================================================
Total tokens: 57

--test-parser

Parses the token stream and prints the AST in indented form.

./build/eskiuc examples/hello.esk --test-parser

Expected output (truncated):

Parsing: examples/hello.esk
========================================================
Program
  ExternDecl: printf -> int
    Parameters:
      string fmt
      ... ...
  FunctionDecl: add -> int
    Parameters:
      int a
      int b
    Body:
      BlockStmt
        ReturnStmt
          BinaryExpr: +
            Left:
              IdentExpr: a
            Right:
              IdentExpr: b
  FunctionDecl: main -> int
    ...

--test-typechecker

Runs semantic analysis. Prints Type checking succeeded! on success, or typed errors on failure.

./build/eskiuc examples/hello.esk --test-typechecker

Expected output on a valid file:

Type checking: examples/hello.esk
========================================================
========================================================
Type checking succeeded!

Example error output for a type mismatch:

error: type mismatch in return: expected 'int', got 'float'

--test-codegen

Runs the full pipeline through LLVM IR emission and prints the IR to stdout.

./build/eskiuc examples/hello.esk --test-codegen

A non-empty IR module with no error: lines on stderr indicates a passing build.

To batch-test all .esk files in the examples directory:

for f in examples/*.esk; do
  echo "=== $f ==="
  ./build/eskiuc "$f" --test-typechecker
done