Manual contents

Your First Project

This chapter expands the minimal program into an executable project with multiple files and modules.

Initialize the Project

mkdir greeting
cd greeting
feng init greeting

The initialized project has this core structure:

greeting/
├── feng.fm
└── src/
    └── main.ff

Add a Module

Create src/greeting.ff:

open module greeting.message;

open func make_greeting(name: string): string {
  return "Hello, " + name;
}

Update src/main.ff:

module greeting;

import greeting.message;
import std.collections;
import std.io;

func main(args: string[]) {
  let name = if args.length() > 1 {
    args[1];
  } else {
    "Feng";
  };
  println(make_greeting(name));
}

Module names and file paths are independent. A module can span multiple .ff files, but each file can declare only one module. Both the module and a top-level declaration must be public before another module can import that declaration.

Run with Arguments

feng run
feng run -- Alice

args[0] is the program path, so the first user argument is stored in args[1].

Project Manifest

The default feng.fm for an executable project looks like this:

[package]
name: "greeting"
version: "0.1.0"
target: "bin"
src: "src/"
out: "build/"

If the distribution includes packages such as the standard library, feng init also writes them to [dependencies] with exact versions. Do not edit generated build artifacts. Project inputs consist of feng.fm and the source files under src/.

Common Development Loop

feng check
feng run -- Alice
feng clean

Use check for quick feedback while editing. run builds the project before running it, and clean removes every build artifact for the current project. See Build and Run for details.