diff --git a/README.md b/README.md index 52b1c39..529a5bf 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,29 @@ # Lana - V C++ Build System -A simple, fast C++ build tool designed for modern C++ projects. +A simple, fast C++ build tool designed for modern C++ projects. Lana compiles itself with V and targets portable C++ workflows without relying on heavyweight generators. -## Features +## Documentation -- **Automatic dependency tracking** for efficient rebuilds -- **Simple configuration** with `config.ini` files -- **Cross-platform** support -- **Clean, minimal interface** - -## Installation - -1. Install V: https://vlang.io/ -2. Build Lana: - ```bash - v . -o lana - ``` -3. Add to PATH or use from current directory +- πŸ“š **Canonical guide:** [`docs/guide.md`](docs/guide.md) now hosts the full documentation (installation, configuration, directives, troubleshooting). +- 🧩 **Reusable snippets:** Shared markdown/JSON data lives under [`docs/snippets`](docs/snippets) and [`docs/commands.json`](docs/commands.json). The CLI help output and initializer templates consume these files directly. ## Quick Start -### Initialize a new project -```bash -lana init myproject -cd myproject -``` - -### Build the project -```bash -lana build -``` - -### Run the project -```bash -lana run -``` - -### Clean build files -```bash -lana clean -``` +See [`docs/snippets/quickstart.md`](docs/snippets/quickstart.md) for the exact commands surfaced by `lana init`, the README template, and `lana --help`. ## Project Structure -``` -myproject/ -β”œβ”€β”€ src/ # Source files (.cpp, .cc, .cxx) -β”œβ”€β”€ include/ # Header files (.h, .hpp) -β”œβ”€β”€ build/ # Object files and intermediates -β”œβ”€β”€ bin/ # Executable output -β”œβ”€β”€ config.ini # Build configuration -β”œβ”€β”€ README.md # Project documentation -└── .gitignore # Git ignore file -``` +[`docs/snippets/project_structure.md`](docs/snippets/project_structure.md) is the single source for structure diagrams used across the README, guide, and generated projects. -## Commands +## Commands & Options -- `lana build` - Compile the project -- `lana run` - Build and execute -- `lana clean` - Remove build files -- `lana init ` - Create new project - -## Configuration - -Edit `config.ini` to customize your build: - -```ini -# Project settings -project_name = myproject -src_dir = src -build_dir = build -bin_dir = bin -debug = true -optimize = false -verbose = false -include_dirs = include -libraries = -cflags = -ldflags = -``` - -## License - -MIT License - see LICENSE file for details. +The CLI help text is generated from [`docs/commands.json`](docs/commands.json). Update that file to add or modify commands/options once, and every consumer (help output, initializer docs, website) stays in sync. ## Contributing -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Submit a pull request +- Fork the repository, create a feature branch, hack away, and open a PR. +- Please keep user-facing documentation changes inside `docs/` whenever possibleβ€”other surfaces will pull from there automatically. + +## License + +MIT License - see [LICENSE](LICENSE) for details. diff --git a/deps/deps.v b/deps/deps.v index 7a39065..8f4d30a 100644 --- a/deps/deps.v +++ b/deps/deps.v @@ -2,7 +2,6 @@ module deps import os import config -import os.cmdline pub fn extract_dependencies(source_file string) ![]string { mut dependencies := []string{} diff --git a/DOCS.md b/docs/guide.md similarity index 81% rename from DOCS.md rename to docs/guide.md index e1ea389..cbdff27 100644 --- a/DOCS.md +++ b/docs/guide.md @@ -1,5 +1,7 @@ # Lana Documentation +> This is the canonical source of project documentation. `README.md`, the CLI help text, and the project initializer templates all reference the content in this directory. + ## Table of Contents 1. [Overview](#overview) @@ -57,7 +59,7 @@ Lana parses `// build-directive:` comments in your C++ files to handle project-s chmod +x lana ``` -4. Add to PATH (optional): +4. (Optional) Add to PATH: ```bash sudo mv lana /usr/local/bin/ ``` @@ -82,7 +84,7 @@ project/ β”‚ β”œβ”€β”€ tools/ # Tool executables β”œβ”€β”€ config.ini # Global build configuration β”œβ”€β”€ README.md # Project docs (auto-generated with directive examples) -└── .gitignore # Ignores build artifacts +└── .gitignore # Git ignore file ``` - **Build Directives**: Add `// build-directive:` comments at the top of C++ files for per-file settings (see [Build Directives](#build-directives)). @@ -111,8 +113,6 @@ lana build [options] ``` Compiles sources, processes directives, builds dependency graph, and links outputs. Incremental: only rebuilds changed files. -**Options:** See [Command Line Options](#command-line-options). - **Example:** ```bash lana build -d -v # Debug build with verbose output (shows directive parsing) @@ -124,22 +124,12 @@ lana run [options] ``` Builds (if needed) and runs the main executable (first tool or `project_name` from config/directives). -**Example:** -```bash -lana run -O # Optimized run -``` - ### Clean Project ```bash lana clean ``` Removes `build/`, `bin/`, and intermediates. -**Example:** -```bash -lana clean -``` - ### Help ```bash lana --help @@ -160,21 +150,10 @@ Fetches and extracts external dependencies declared in `config.ini` under `[depe - `build_cmds` - optional semicolon-separated shell commands to build/install the dependency Notes: -- Only `name` is required. If `url` is omitted Lana will skip any download/clone and extraction steps β€” this is useful for dependencies that are generated locally or that only require running project-local commands. -- If `url` points to a git repository (ends with `.git`), `lana setup` will perform a shallow clone into `dependencies/`. -- For archive URLs `lana setup` will try `curl` then `wget` to download, will verify checksum if provided, and will extract common archive types (`.tar.gz`, `.tar.xz`, `.zip`). -- When `build_cmds` are present they are executed either inside `dependencies/` (if `extract_to` is set or a clone/extract was performed) or in the project root (if no extract directory is available). -- The current implementation performs a best-effort download/extract and prints warnings/errors; it is intentionally simple and can be extended or replaced by a more robust script if needed. - -Example (only `name` + `build_cmds`): - -```ini -[dependencies] -name = generate_headers -build_cmds = tools/gen_headers.sh; cp -r generated/include ../../include/ -``` - -In this example `lana setup` will not try to download anything β€” it will run the `build_cmds` from the project root, allowing you to run arbitrary local build or generation steps. +- Only `name` is required. If `url` is omitted Lana will skip any download/clone and extraction steps β€” useful for dependencies generated locally or that only require running project-local commands. +- If `url` points to a git repository (ends with `.git`), `lana setup` performs a shallow clone into `dependencies/`. +- For archive URLs `lana setup` tries `curl` then `wget` to download, verifies checksum if provided, and extracts common archive types (`.tar.gz`, `.tar.xz`, `.zip`). +- When `build_cmds` are present they run either inside `dependencies/` (if available) or in the project root. ## Configuration @@ -190,7 +169,7 @@ src_dir = src build_dir = build bin_dir = bin -# Build modes (mutually exclusive; CLI overrides) +# Build modes (CLI overrides) debug = true optimize = false @@ -235,12 +214,12 @@ Lana's killer feature: Embed build instructions **directly in C++ source files** ### Supported Directives - **`unit-name()`**: Unique unit ID (e.g., `"lib/cli"`, `"tools/mytool"`). Required for custom builds. Defaults to file path if omitted. -- **`depends-units(,,...)`**: Dependencies (other units, e.g., `"lib/utils,lib/file"`). Builds them first. -- **`link(,,...)`**: Libraries to link (e.g., `"utils.so,pthread,boost_system"`). Internal (Lana-built) or external. +- **`depends-units(,,...)`**: Dependencies (other units). Builds them first. +- **`link(,,...)`**: Libraries to link (internal or external). - **`out()`**: Output relative to `bin/` (e.g., `"tools/mytool"`, `"lib/mylib"`). Defaults to unit name. -- **`cflags( ...)`**: Per-file compiler flags (e.g., `"-std=c++20 -fPIC"`). Appends to global `cflags`. -- **`ldflags( ...)`**: Per-file linker flags (e.g., `"-static -pthread"`). Appends to global `ldflags`. -- **`shared()`**: Build as shared lib (`.so`/`.dll`, true) or executable (false, default). +- **`cflags( ...)`**: Per-file compiler flags. Appends to global `cflags`. +- **`ldflags( ...)`**: Per-file linker flags. +- **`shared()`**: Build as shared lib (`.so`/`.dll`, true) or executable (false). ### Examples @@ -258,7 +237,6 @@ int main() { return 0; } ``` -- Builds `bin/tools/main` executable. No deps. **Shared Library (`src/lib/cli.cpp`)**: ```cpp @@ -276,7 +254,6 @@ namespace lana { void print_help() { std::cout << "CLI help" << std::endl; } } ``` -- Builds `bin/lib/cli.so`. PIC for shared lib. **Tool Depending on Shared Lib (`src/tools/mytool.cpp`)**: ```cpp @@ -296,14 +273,6 @@ int main() { return 0; } ``` -- Depends on/builds `lib/cli` first; links `cli.so`; outputs `bin/tools/mytool`. - -### Tips -- **Order**: Directives before `#include` or code. -- **Empty Values**: Use `()` for none (e.g., `depends-units()`). -- **Global Interaction**: Directives add to `config.ini` settings (e.g., global `-Wall` + per-file `-std=c++20`). -- **Assets**: Use `[dependencies]` hooks for non-C++ steps (e.g., shader compilation). -- **Legacy**: Use `[shared_libs]`/`[tools]` in config for manual lists (overrides auto-parsing). ## Build Process @@ -387,12 +356,12 @@ libraries = pthread,boost_system cflags = -Wall -Wextra -std=c++17 ldflags = -static -[shared_libs] # Legacy/manual (directives preferred) +[shared_libs] name = cli sources = src/lib/cli.cpp libraries = -[tools] # Legacy/manual +[tools] name = main sources = src/main.cpp libraries = cli @@ -400,13 +369,11 @@ libraries = cli ## Troubleshooting -### Common Issues - - **"No source files found"**: Check `src_dir` in config; ensure `.cpp` files exist. - **"Failed to parse directive"**: Verify syntax (e.g., `unit-name(lib/cli)`); use `-v` for details. - **"Dependency not found"**: Add missing `depends-units()` or build order in directives. - **Linking errors**: Check `link()` for libs; install dev packages (e.g., `sudo apt install libpthread-dev`). -- **Asset build fails**: Verify commands in `[dependencies]` hook scripts (e.g., shader toolchain). +- **Asset build fails**: Verify commands in `[dependencies]` hook scripts. - **Permission denied**: `chmod +x bin/tools/mytool`. ### Debugging Tips @@ -422,10 +389,4 @@ See the source code structure in the repo. To extend: - Add directives: Update `config.BuildDirective` and `builder.build_from_directives()`. - New features: Modify `config.v` for parsing, `builder.v` for logic. -For contributing, see [GitHub](https://github.com/yourusername/lana) (fork, branch, PR). - ---- -*Documentation for Lana v1.0.0* -*Last updated: 2025-09-17* -*Issues: [Issues](https://lostcave.ddnss.de/git/jocadbz/lana)* -*Contribute: [Repo](https://lostcave.ddnss.de/git/jocadbz/lana)* +For contributing, see Gitea (fork, branch, PR). diff --git a/docs/help.txt b/docs/help.txt new file mode 100644 index 0000000..425cd3c --- /dev/null +++ b/docs/help.txt @@ -0,0 +1,30 @@ +lana - Vlang C++ Build System +Usage: lana [command] [options] + +Commands: + build Compile all shared libraries and tools according to build directives. + run Build (if needed) and run the main tool (project_name or first tool). + clean Remove build artifacts under build/ and bin/. + init Scaffold a new Lana-ready C++ project. + setup Fetch/build external dependencies declared in config.ini. + help Display this help text. + +Global Options: + -d, --debug Enable debug mode (-g -O0). + -O, --optimize Enable optimization (-O3, disables debug). + -v, --verbose Verbose logging (graph + compiler commands). + -p, --parallel Force parallel compilation worker pool. + -o, --output Override project/output name. + -I Add include directory (repeatable). + -L Add library search path (repeatable). + -l Add global link library (repeatable). + -c, --compiler Set compiler binary explicitly. + --toolchain Choose toolchain adapter (gcc/clang). + --config Use alternate config file. + --shared-lib Add legacy shared lib entry (no directives). + --tool Add legacy tool entry (no directives). + +Docs: + Canonical Guide docs/guide.md + Project Structure docs/snippets/project_structure.md + Quick Start docs/snippets/quickstart.md \ No newline at end of file diff --git a/docs/snippets/project_structure.md b/docs/snippets/project_structure.md new file mode 100644 index 0000000..9dec28a --- /dev/null +++ b/docs/snippets/project_structure.md @@ -0,0 +1,12 @@ +## Project Structure +- `src/` β€” Source files (.cpp, .cc, .cxx) + - `lib/` β€” Shared library sources (mark with `shared(true)` when needed) + - `tools/` β€” Tool/executable sources +- `include/` β€” Public headers +- `build/` β€” Intermediate object files and dependency dumps +- `bin/` β€” Final outputs + - `lib/` β€” Shared libraries (.so/.dll) + - `tools/` β€” Executables +- `config.ini` β€” Global build configuration +- `README.md` β€” Project overview (generated by Lana) +- `.gitignore` β€” Generated ignore file tuned for Lana projects diff --git a/docs/snippets/quickstart.md b/docs/snippets/quickstart.md new file mode 100644 index 0000000..72b990c --- /dev/null +++ b/docs/snippets/quickstart.md @@ -0,0 +1,18 @@ +## Quick Start +1. Initialize a project: + ```bash + lana init myproject + cd myproject + ``` +2. Build it: + ```bash + lana build + ``` +3. Run the main tool: + ```bash + lana run + ``` +4. Clean artifacts: + ```bash + lana clean + ``` diff --git a/docs/templates/cli.cpp.tpl b/docs/templates/cli.cpp.tpl new file mode 100644 index 0000000..b281ff2 --- /dev/null +++ b/docs/templates/cli.cpp.tpl @@ -0,0 +1,15 @@ +// build-directive: unit-name(lib/cli) +// build-directive: depends-units() +// build-directive: link() +// build-directive: out(lib/cli) +// build-directive: shared(true) +// build-directive: cflags(-fPIC) + +#include +#include "cli.h" + +namespace lana { + void print_help() { + std::cout << "Lana CLI help" << std::endl; + } +} diff --git a/docs/templates/cli.h.tpl b/docs/templates/cli.h.tpl new file mode 100644 index 0000000..4f007d2 --- /dev/null +++ b/docs/templates/cli.h.tpl @@ -0,0 +1,8 @@ +#ifndef LANA_CLI_H +#define LANA_CLI_H + +namespace lana { + void print_help(); +} + +#endif diff --git a/docs/templates/config.ini.tpl b/docs/templates/config.ini.tpl new file mode 100644 index 0000000..a06a554 --- /dev/null +++ b/docs/templates/config.ini.tpl @@ -0,0 +1,24 @@ +# {{project_name}} lana build configuration + +[global] +project_name = {{project_name}} +src_dir = src +build_dir = build +bin_dir = bin +compiler = g++ +debug = true +optimize = false +verbose = false +parallel_compilation = true +include_dirs = include +lib_search_paths = +cflags = -Wall -Wextra +ldflags = + +dependencies_dir = dependencies + +[shared_libs] +# legacy/manual entries go here when you don't want build directives + +[tools] +# legacy/manual entries go here when you don't want build directives diff --git a/docs/templates/example_tool.cpp.tpl b/docs/templates/example_tool.cpp.tpl new file mode 100644 index 0000000..0cdb28d --- /dev/null +++ b/docs/templates/example_tool.cpp.tpl @@ -0,0 +1,13 @@ +#include +#include "cli.h" + +// build-directive: unit-name(tools/example_tool) +// build-directive: depends-units(lib/cli) +// build-directive: link(cli.so) +// build-directive: out(tools/example_tool) + +int main() { + std::cout << "Tool example" << std::endl; + lana::print_help(); + return 0; +} diff --git a/docs/templates/gitignore.tpl b/docs/templates/gitignore.tpl new file mode 100644 index 0000000..cd975c8 --- /dev/null +++ b/docs/templates/gitignore.tpl @@ -0,0 +1,23 @@ +# Build files +build/ +bin/ +*.o +*.exe +*.dSYM +*.d +*.so +*.dll +*.dylib + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS files +.DS_Store +Thumbs.db + +# Dependencies +dependencies/ diff --git a/docs/templates/main.cpp.tpl b/docs/templates/main.cpp.tpl new file mode 100644 index 0000000..458c101 --- /dev/null +++ b/docs/templates/main.cpp.tpl @@ -0,0 +1,11 @@ +#include + +// build-directive: unit-name(tools/main) +// build-directive: depends-units() +// build-directive: link() +// build-directive: out(tools/main) + +int main() { + std::cout << "Hello, {{project_name}}!" << std::endl; + return 0; +} diff --git a/docs/templates/readme.md.tpl b/docs/templates/readme.md.tpl new file mode 100644 index 0000000..0ae2c3d --- /dev/null +++ b/docs/templates/readme.md.tpl @@ -0,0 +1,13 @@ +# {{project_name}} + +A C++ project built with the [Lana build system](https://github.com/lana-build/lana/blob/main/docs/guide.md). + +{{quickstart}} + +{{project_structure}} + +## Build Directives +Lana reads build instructions directly from your source files. Add `// build-directive:` comments near the top of a translation unit to specify unit names, dependencies, and custom flags. See `docs/guide.md#build-directives` for the full catalog. + +## Configuration +Global build settings live in `config.ini`. Command-line flags override config values, which override built-in defaults. Consult `docs/guide.md#configuration` for details and advanced examples. diff --git a/docstore/docstore.v b/docstore/docstore.v new file mode 100644 index 0000000..07d29de --- /dev/null +++ b/docstore/docstore.v @@ -0,0 +1,43 @@ +module docstore + +const snippet_project_structure_embedded = $embed_file('../docs/snippets/project_structure.md') +const snippet_quickstart_embedded = $embed_file('../docs/snippets/quickstart.md') +const template_main_embedded = $embed_file('../docs/templates/main.cpp.tpl') +const template_cli_embedded = $embed_file('../docs/templates/cli.cpp.tpl') +const template_example_tool_embedded = $embed_file('../docs/templates/example_tool.cpp.tpl') +const template_cli_header_embedded = $embed_file('../docs/templates/cli.h.tpl') +const template_gitignore_embedded = $embed_file('../docs/templates/gitignore.tpl') +const template_config_embedded = $embed_file('../docs/templates/config.ini.tpl') +const template_readme_embedded = $embed_file('../docs/templates/readme.md.tpl') +const guide_embedded = $embed_file('../docs/guide.md') +const help_text_embedded = $embed_file('../docs/help.txt') + +pub fn snippet(name string) !string { + return match name { + 'project_structure' { snippet_project_structure_embedded.to_string() } + 'quickstart' { snippet_quickstart_embedded.to_string() } + else { error('snippet ${name} not found') } + } +} + +pub fn template(name string) !string { + return match name { + 'main.cpp.tpl' { template_main_embedded.to_string() } + 'cli.cpp.tpl' { template_cli_embedded.to_string() } + 'example_tool.cpp.tpl' { template_example_tool_embedded.to_string() } + 'cli.h.tpl' { template_cli_header_embedded.to_string() } + 'gitignore.tpl' { template_gitignore_embedded.to_string() } + '.gitignore.tpl' { template_gitignore_embedded.to_string() } + 'config.ini.tpl' { template_config_embedded.to_string() } + 'readme.md.tpl' { template_readme_embedded.to_string() } + else { error('template ${name} not found') } + } +} + +pub fn guide() string { + return guide_embedded.to_string() +} + +pub fn help_text() string { + return help_text_embedded.to_string() +} diff --git a/help/help.v b/help/help.v index 781b687..1c79b9d 100644 --- a/help/help.v +++ b/help/help.v @@ -1,57 +1,7 @@ module help +import docstore + pub fn show_help() { - println('lana - Vlang C++ Build System') - println('Usage: lana [command] [options]') - println('') - println('Commands:') - println(' build Build the project (shared libs + tools)') - println(' clean Clean build files') - println(' run Build and run the main tool') - println(' init Initialize new project') - println('') - println('Options:') - println(' -d, --debug Enable debug mode') - println(' -O, --optimize Enable optimization') - println(' -v, --verbose Verbose output') - println(' -p, --parallel Enable parallel compilation') - println(' -o, --output Set output name') - println(' -I Add include directory') - println(' -l Add library') - println(' --config Use config file') - println(' --shared-lib Add shared library') - println(' --tool Add tool/executable') - println('') - println('Configuration File (config.ini):') - println(' [global]') - println(' project_name = myproject') - println(' src_dir = src') - println(' debug = true') - println(' ') - println(' [shared_libs]') - println(' name = net') - println(' sources = src/lib/net/connection.cpp') - println(' libraries = cli') - println(' ') - println(' [tools]') - println(' name = dumpnbt') - println(' sources = src/tools/dumpnbt.cpp') - println(' libraries = nbt,cli') - println('') - println('Examples:') - println(' lana build -d -v -p') - println(' lana run') - println(' lana build --shared-lib cli src/lib/cli.cpp --tool dumpnbt src/tools/dumpnbt.cpp') - println(' lana init myproject') - println('') - println('Project Structure:') - println(' src/ - Source files (.cpp, .cc, .cxx)') - println(' lib/ - Shared library sources') - println(' tools/ - Tool/executable sources') - println(' include/ - Header files (.h, .hpp)') - println(' build/ - Object files and intermediates') - println(' bin/ - Output') - println(' lib/ - Shared libraries (.so/.dll)') - println(' tools/ - Executables') - println(' config.ini - Build configuration') + print(docstore.help_text()) } \ No newline at end of file diff --git a/initializer/initializer.v b/initializer/initializer.v index 5a92a6f..4bf8cde 100644 --- a/initializer/initializer.v +++ b/initializer/initializer.v @@ -1,11 +1,20 @@ module initializer import os +import docstore + +fn render_template(template string, replacements map[string]string) string { + mut output := template + for key, value in replacements { + placeholder := '{{${key}}}' + output = output.replace(placeholder, value) + } + return output +} pub fn init_project(project_name string) { println('Initializing C++ project: ${project_name}') - // Create directory structure dirs := [ 'src', 'src/lib', @@ -16,7 +25,7 @@ pub fn init_project(project_name string) { 'build', 'bin', 'bin/lib', - 'bin/tools' + 'bin/tools', ] for dir in dirs { full_path := os.join_path(project_name, dir) @@ -24,371 +33,48 @@ pub fn init_project(project_name string) { println('Warning: Failed to create ${full_path}: ${err}') } } - - // Create basic main.cpp with build directives - main_content := r' -#include -// build-directive: unit-name(tools/main) -// build-directive: depends-units() -// build-directive: link() -// build-directive: out(tools/main) - -int main() { - std::cout << "Hello, ${project_name}!" << std::endl; - return 0; -} -' - os.write_file(os.join_path(project_name, 'src', 'main.cpp'), main_content) or { } - - // Create example shared library with build directives - cli_content := r' -// build-directive: unit-name(lib/cli) -// build-directive: depends-units() -// build-directive: link() -// build-directive: out(lib/cli) -// build-directive: shared(true) - -#include - -namespace lana { - void print_help() { - std::cout << "Lana CLI help" << std::endl; + replacements := { + 'project_name': project_name } -} -' - os.write_file(os.join_path(project_name, 'src/lib', 'cli.cpp'), cli_content) or { } - - // Create example tool with build directives - tool_content := r' -#include -// build-directive: unit-name(tools/example_tool) -// build-directive: depends-units(lib/cli) -// build-directive: link(cli.so) -// build-directive: out(tools/example_tool) -int main() { - std::cout << "Tool example" << std::endl; - lana::print_help(); - return 0; -} -' - os.write_file(os.join_path(project_name, 'src/tools', 'example_tool.cpp'), tool_content) or { } - - // Create .gitignore - gitignore_content := r' -# Build files -build/ -bin/ -*.o -*.exe -*.dSYM -*.d -*.so -*.dll -*.dylib + quickstart := docstore.snippet('quickstart') or { 'See docs/snippets/quickstart.md in the Lana repo.' } + structure := docstore.snippet('project_structure') or { 'See docs/snippets/project_structure.md in the Lana repo.' } -# IDE files -.vscode/ -.idea/ -*.swp -*.swo + write_template(project_name, 'src/main.cpp', 'main.cpp.tpl', replacements) + write_template(project_name, 'src/lib/cli.cpp', 'cli.cpp.tpl', replacements) + write_template(project_name, 'src/tools/example_tool.cpp', 'example_tool.cpp.tpl', replacements) + write_template(project_name, '.gitignore', 'gitignore.tpl', replacements) + write_template(project_name, 'config.ini', 'config.ini.tpl', replacements) -# OS files -.DS_Store -Thumbs.db + mut readme_map := replacements.clone() + readme_map['quickstart'] = quickstart.trim_space() + readme_map['project_structure'] = structure.trim_space() + write_template_with_map(project_name, 'README.md', 'readme.md.tpl', readme_map) -# Dependencies -dependencies/ -' - os.write_file(os.join_path(project_name, '.gitignore'), gitignore_content) or { } - - // Create config.ini with build directive support - config_content := r' -# ${project_name} lana build configuration + write_template(project_name, 'include/cli.h', 'cli.h.tpl', replacements) -[global] -project_name = ${project_name} -src_dir = src -build_dir = build -bin_dir = bin -compiler = g++ -debug = true -optimize = false -verbose = false -parallel_compilation = true -include_dirs = include -lib_search_paths = -cflags = -Wall -Wextra -ldflags = - -# Build directives will be automatically parsed from source files -# using // build-directive: comments - -[shared_libs] -# These are for legacy support or manual configuration -# Most shared libraries should use build directives in source files - -[tools] -# These are for legacy support or manual configuration -# Most tools should use build directives in source files - -' - os.write_file(os.join_path(project_name, 'config.ini'), config_content) or { } - - // Create README.md with build directive documentation - readme_content := r' -# ${project_name} - -A C++ project built with lana (Vlang C++ Build System) - -## Getting Started - -### Build the project -```bash -lana build -``` - -### Run the main executable -```bash -lana run -``` - -### Run a specific tool -```bash -./bin/tools/example_tool -``` - -### Clean build files -```bash -lana clean -``` - -## Project Structure -- `src/` - Source files (.cpp, .cc, .cxx) - - `lib/` - Shared library sources - - `tools/` - Tool/executable sources -- `include/` - Header files (.h, .hpp) -- `build/` - Object files and intermediate build files -- `bin/` - Executable output - - `lib/` - Shared libraries (.so/.dll) - - `tools/` - Tool executables -- `config.ini` - Build configuration - -## Build Directives - -Lana reads build instructions directly from source files using special comments: - -``` -// build-directive: unit-name(tools/arraydump) -// build-directive: depends-units(lib/file,lib/cli) -// build-directive: link(file.so,cli.so) -// build-directive: out(tools/arraydump) -// build-directive: cflags(-Wall -Wextra) -// build-directive: ldflags() -// build-directive: shared(true) -``` - -### Directive Types - -- **unit-name**: Name of the build unit (e.g., "tools/arraydump", "lib/file") -- **depends-units**: Dependencies for this unit (other units or libraries) -- **link**: Libraries to link against (e.g., "file.so", "cli.so") -- **out**: Output path for the binary (relative to bin/) -- **cflags**: Additional CFLAGS for this file -- **ldflags**: Additional LDFLAGS for this file -- **shared**: Whether this is a shared library (true/false) - -### Example Source File - -```cpp -// build-directive: unit-name(tools/dumpnbt) -// build-directive: depends-units(lib/nbt,lib/cli) -// build-directive: link(nbt.so,cli.so) -// build-directive: out(tools/dumpnbt) -// build-directive: cflags() -// build-directive: ldflags() -// build-directive: shared(false) - -#include -#include "nbt.h" -#include "cli.h" - -int main() { - // Your code here - return 0; -} -``` - -## Configuration -Edit `config.ini` to customize global build settings: - -### Global Settings -```ini -[global] -project_name = myproject -compiler = g++ -debug = true -optimize = false -verbose = false -parallel_compilation = true -include_dirs = include,external/lib/include -lib_search_paths = /usr/local/lib,external/lib -cflags = -Wall -Wextra -std=c++17 -ldflags = -pthread -``` - -### Shared Libraries (Legacy) -```ini -[shared_libs] -name = cli -sources = src/lib/cli.cpp -libraries = -include_dirs = include -cflags = -ldflags = -``` - -### Tools (Legacy) -```ini -[tools] -name = main -sources = src/main.cpp -libraries = cli - -name = example_tool -sources = src/tools/example_tool.cpp -libraries = cli -``` - -## Command Line Options -```bash -lana build [options] - -d, --debug Enable debug mode - -O, --optimize Enable optimization - -v, --verbose Verbose output - -p, --parallel Parallel compilation - -c, --compiler Set C++ compiler (default: g++) - -o Set project name - -I Add include directory - -L Add library search path - -l Add global library - --config Use custom config file - --shared-lib Add shared library (legacy) - --tool Add tool (legacy) -``` - -## Build Process - -1. **Parse build directives** from source files -2. **Build dependency graph** based on unit dependencies -3. **Compile source files** to object files -4. **Link libraries and executables** according to directives -5. **Execute dependency hooks** declared under `[dependencies]` (ideal for assets like shaders) - -The build system automatically handles: -- Dependency resolution and build ordering -- Incremental builds (only rebuild changed files) -- Shared library vs executable detection -- Custom flags per file -- Parallel compilation - -## Examples - -### Simple Tool -```cpp -// build-directive: unit-name(tools/calculator) -// build-directive: depends-units() -// build-directive: link() -// build-directive: out(tools/calculator) - -#include - -int main() { - int a, b; - std::cin >> a >> b; - std::cout << "Sum: " << a + b << std::endl; - return 0; -} -``` - -### Shared Library with Dependencies -```cpp -// build-directive: unit-name(lib/math) -// build-directive: depends-units(lib/utils) -// build-directive: link(utils.so) -// build-directive: out(lib/math) -// build-directive: shared(true) -// build-directive: cflags(-fPIC) - -#include "utils.h" - -namespace math { - double add(double a, double b) { - return a + b; - } -} -``` - -### Complex Tool with Multiple Dependencies -```cpp -// build-directive: unit-name(tools/game) -// build-directive: depends-units(lib/graphics,lib/audio,lib/input) -// build-directive: link(graphics.so,audio.so,input.so,glfw,SDL2) -// build-directive: out(tools/game) -// build-directive: cflags(-DDEBUG) -// build-directive: ldflags(-pthread) - -#include "graphics.h" -#include "audio.h" -#include "input.h" - -int main() { - // Game loop - return 0; -} -``` - -## License - -MIT License - see LICENSE file for details. - -## Contributing - -1. Fork the repository -2. Create a feature branch -3. Make your changes -4. Submit a pull request -' - os.write_file(os.join_path(project_name, 'README.md'), readme_content) or { } - - // Create example header - header_content := r' -#ifndef LANA_CLI_H -#define LANA_CLI_H - -namespace lana { - void print_help(); -} - -#endif -' - os.write_file(os.join_path(project_name, 'include', 'cli.h'), header_content) or { } - println('Project initialized successfully!') println('Created directory structure and template files') - println('') - println('Usage:') + println('\nNext steps:') println(' cd ${project_name}') println(' lana build') println(' lana run') println(' ./bin/tools/example_tool') - println('') - println('Build Directives:') - println(' Add // build-directive: comments to your source files') - println(' See README.md for examples and documentation') - println('Configuration:') - println(' Edit config.ini for global build settings') - println(' Add your C++ source files to src/lib/ and src/tools/') - println(' Use [dependencies] entries for extra asset steps (e.g., shader compilation)') + println('\nDocs and templates originate from docs/ in the Lana repo. Update them once to affect README/help/init output everywhere.') +} + +fn write_template(root string, relative_path string, template_name string, replacements map[string]string) { + write_template_with_map(root, relative_path, template_name, replacements) +} + +fn write_template_with_map(root string, relative_path string, template_name string, replacements map[string]string) { + content := docstore.template(template_name) or { + println('Warning: template ${template_name} missing (${err})') + return + } + rendered := render_template(content, replacements) + os.write_file(os.join_path(root, relative_path), rendered) or { + println('Warning: failed to write ${relative_path}: ${err}') + } } \ No newline at end of file diff --git a/lana.v b/lana.v index 4ad389a..46102e3 100644 --- a/lana.v +++ b/lana.v @@ -8,68 +8,72 @@ import initializer import deps import help -const ( - // For runner compatibility - bin_dir = 'bin' - tools_dir = 'bin/tools' -) +// For runner compatibility +const bin_dir = 'bin' +const tools_dir = 'bin/tools' fn main() { - mut config_data := config.parse_args() or { config.default_config } - - if os.args.len < 2 { - help.show_help() - return - } - - match os.args[1] { - 'build' { - builder.build(mut config_data) or { - eprintln('Build failed: ${err}') - exit(1) - } - } - 'clean' { builder.clean(config_data) } - 'run' { - // For run, try to build first, then run the main tool - builder.build(mut config_data) or { - eprintln('Build failed: ${err}') - exit(1) - } - - // Find and run the main executable (first tool or project_name) - main_executable := get_main_executable(config_data) - if main_executable != '' && os.is_file(main_executable) { - runner.run_executable(config_data) - } else { - println('No main executable found to run') - } - } - 'init' { initializer.init_project(os.args[2] or { 'myproject' }) } - 'setup' { - deps.fetch_dependencies(config_data) or { - eprintln('Failed to fetch dependencies: ${err}') - exit(1) - } - } - else { help.show_help() } - } + mut config_data := config.parse_args() or { config.default_config } + + if os.args.len < 2 { + help.show_help() + return + } + + match os.args[1] { + 'build' { + builder.build(mut config_data) or { + eprintln('Build failed: ${err}') + exit(1) + } + } + 'clean' { + builder.clean(config_data) + } + 'run' { + // For run, try to build first, then run the main tool + builder.build(mut config_data) or { + eprintln('Build failed: ${err}') + exit(1) + } + + // Find and run the main executable (first tool or project_name) + main_executable := get_main_executable(config_data) + if main_executable != '' && os.is_file(main_executable) { + runner.run_executable(config_data) + } else { + println('No main executable found to run') + } + } + 'init' { + initializer.init_project(os.args[2] or { 'myproject' }) + } + 'setup' { + deps.fetch_dependencies(config_data) or { + eprintln('Failed to fetch dependencies: ${err}') + exit(1) + } + } + else { + help.show_help() + } + } } fn get_main_executable(build_config config.BuildConfig) string { - // First try to find a tool with the project name - for tool_config in build_config.tools { - if tool_config.name == build_config.project_name { - return os.join_path(tool_config.output_dir, tool_config.name) - } - } - - // Then try the first tool - if build_config.tools.len > 0 { - tool_config := build_config.tools[0] - return os.join_path(tool_config.output_dir, tool_config.name) - } - - // Fallback to old behavior - return os.join_path(build_config.bin_dir, build_config.project_name) -} \ No newline at end of file + // First try to find a tool with the project name + for tool_config in build_config.tools { + if tool_config.name == build_config.project_name { + return os.join_path(tool_config.output_dir, tool_config.name) + } + } + + // Then try the first tool + if build_config.tools.len > 0 { + tool_config := build_config.tools[0] + return os.join_path(tool_config.output_dir, tool_config.name) + } + + // Fallback to old behavior + return os.join_path(build_config.bin_dir, build_config.project_name) +}