diff --git a/README.md b/README.md index 975b4e2..114dfcb 100644 --- a/README.md +++ b/README.md @@ -15,252 +15,37 @@ ## Table of contents - [Table of contents](#table-of-contents) -- [Macros](#macros) - - [`@latest`](#latest) - - [`@uname`](#uname) - - [`@include`](#include) - - [`@join`](#join) - - [`@concat`](#concat) - - [`@exec`](#exec) -- [Manifest file format](#manifest-file-format) - - [`id`](#id) - - [`type`](#type) - - [`description`](#description) - - [`enabledIf`](#enabledif) - - [`requires`](#requires) - - [`provides`](#provides) -- [Target file format](#target-file-format) - - [`id`](#id-1) - - [`type`](#type-1) - - [`props`](#props) - - [`tools`](#tools) +- [Introduction](#introduction) +- [Quick-start](#quick-start) +- [Example](#example) -## Macros +## Introduction +**CuteKit** is a simple - yet - powerful build system and package manager for C and C++. It: -### `@latest` +- ✨ It uses **JSON**: Cutekit uses JSON instead of introducing a whole new programming language for describing the project. And also has macros to help the user experience (see [Jexpr](doc/spec/jexpr.md)). +- ✨ It's a **package manager**: Cutekit package manager is based on **Git**, nothing is centralized. +- ✨ It's **extendible**: Cutekit can be [extended](./doc/extends.md) by writing custom Python plugins. +- ✨ It's **easy**: the [**templates**](./doc/templates.md) help the user quick-start a project. +- ✨ It's **portable**: Cutekit can run on MacOS Gnu/Linux and Windows. -Find the latest version of a command in the path. +## Quick-start -```json -"cc": { - "cmd": ["@latest", "clang"], // clang-14 -/* ... */ -``` +-> If you directly want to start using Cutekit for a new project, you can just run `$ ck I host` and it will create a new project in the host directory (you can rename it later). -### `@uname` +-> If you want to use Cutekit for writing operating systems, you can create a new [limine](https://github.com/limine-bootloader/limine/)-based project by running `$ ck I limine-barebone`. -Query the system for information about the current operating system. +## Example +If you want to see how it works you can read the [doc/cutekit.md](doc/cutekit.md) file. -```json -"cc": { - "cmd": ["@uname", "machine"], // "x86_64" -/* ... */ -``` +# License -### `@include` + + MIT License + -Include a file +Cutekit is licensed under the **MIT License**. -### `@join` - -Join two objects - -Example: - -```json -["@join", {"a": 1}, {"b": 2}] // {"a": 1, "b": 2} -``` - -### `@concat` - -Concatenate strings - -Example: - -```json -["@concat", "a", "b", "c"] // "abc" -``` - -### `@exec` - -Execute a command and return the output - -Example: - -```json -["@exec", "uname", "-m"] // "x86_64" -``` - -## Manifest file format - -### `id` - -The id of the package. This is used to identify the package in the manifest file. - -Exemple: - -```json -{ - "id": "hello" -} -``` - -### `type` - -The type of the package. This is used to identify the package in the manifest file. - -Exemple: - -```json -{ - "type": "exe" -} -``` - -### `description` - -The description of the package for the user. - -Exemple: - -```json -{ - "description": "Hello world" -} -``` - -### `enabledIf` - -A list of requirements for the package check agaisnt the build props. If the requirement is not met, the package will be disabled. - -```json -{ - "enabledIf": { - "freestanding": [ - false - ] - } -} -``` - -### `requires` - -Dependencies of the package. The name listed here must be the same as the id of the package or member of a provide list. - -Exemple: - -```json -{ - "requires": [ - "libc", - "libm" - ] -} -``` - -### `provides` - -Alias for the package. - -Exemple: - -```json -{ - "provides": [ - "hello" - ] -} -``` - - -## Target file format - -### `id` - -The id of the target. This is used to identify the target in the target file. - -### `type` - -Should be `target`. - -### `props` - -A list of properties for the target. - -Exemple: - -```json -{ - "props": { - "arch": "x86_64", - "vendor": "pc", - "os": "linux", - "env": "gnu", - "abi": "elf", - "cpu": "x86_64", - "features": "fxsr,sse,sse2" - } -} -``` - -Theses values are exposed the translation unit as `__ck_{prop}__`. - -### `tools` - -A list of tools for the target. - -```json -{ - "tools": { - "cc": { - "cmd": ["@latest", "clang"], - "args": [ - "-target", - "x86_64-unknown-windows", - "-ffreestanding", - "-fno-stack-protector", - "-fshort-wchar", - "-mno-red-zone" - ] - }, - "cxx": { - "cmd": ["@latest", "clang++"], - "args": [ - "-target", - "x86_64-unknown-windows", - "-ffreestanding", - "-fno-stack-protector", - "-fshort-wchar", - "-mno-red-zone" - ] - }, - "ld": { - "cmd": ["@latest", "clang++"], - "args": [ - "-target", - "x86_64-unknown-windows", - "-nostdlib", - "-Wl,-entry:efi_main", - "-Wl,-subsystem:efi_application", - "-fuse-ld=lld-link" - ] - }, - "ar": { - "cmd": ["@latest", "llvm-ar"], - "args": [ - "rcs" - ] - }, - "as": { - "cmd": "nasm", - "args": [ - "-f", - "win64" - ] - } - } -} -``` +The full text of the license can be accessed via [this link](https://opensource.org/licenses/MIT) and is also included in the [license.md](license.md) file of this software package. diff --git a/doc/cutekit.md b/doc/cutekit.md new file mode 100644 index 0000000..65d7b50 --- /dev/null +++ b/doc/cutekit.md @@ -0,0 +1,114 @@ +# Cutekit + +Cutekit is a build system that aims to be simple, fast and easy to use. +A project is described using json files. + +## Project file + +The project file is used to describe the project and its dependencies. + +See: [doc/spec/project.md](doc/spec/project.md) for the full specification. + +Example: + +> project.json +```json +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.project.v1", + "id": "skift-org/skift", + "type": "project", + "description": "The Skift Operating System", + "extern": { + "cute-engineering/libheap": { + "git": "https://github.com/cute-engineering/libheap.git", + "tag": "v1.1.0" + } + } +} +``` + +Here we describe a project with the id `skift-org/skift` and a dependency to `cute-engineering/libheap` at version `v1.1.0`. + +## An executable package manifest + + +When you want to create an executable package, you need to create a `manifest.json` file in any directory under `src/`. +This is the file that describe an executable with its dependencies. + +> src/nyan-cat-app/manifest.json +```json +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "id": "nyan-cat-app", + "type": "exe", + "description": "rainbows everywhere", + "requires": [ + "easy-lib" + ] +} +``` + +Here we describe an executable with the id `nyan-cat-app` and a dependency to `easy-lib` (which is a library built by the project). + +You can run the executable by running `$ ck run nyan-cat-app`. + +## A library package manifest + +When you want to create a library package, you need to create a `manifest.json` file in any directory under `src/`, like an executable package. + +> src/easy-lib/manifest.json +```json +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "id": "easy-lib", + "type": "lib", + "description": "easy to use library", + "requires": [ + "cute-engineering/libheap" + ] +} +``` + +Here we describe a library with the id `easy-lib` and a dependency to `cute-engineering/libheap` (which is an external dependency described above in the `project.json`). + +## Using installed libraries + +You can create a specific installed library through the use of `pkg-config` files. +For example here is how you add `SDL2` to your project: + + +> src/extern/sdl2/manifest.json +```json +{ + "$schema": "https://schemas.cute.engineering/stable/cutekit.manifest.component.v1", + "id": "sdl2", + "type": "lib", + "description": "A cross-platform development library designed to provide low level access to hardware", + "tools": { + "cc": { + "args": [ + "@exec", + "pkg-config", + "--cflags", + "sdl2" + ] + }, + "cxx": { + "args": [ + "@exec", + "pkg-config", + "--cflags", + "sdl2" + ] + }, + "ld": { + "args": [ + "@exec", + "pkg-config", + "--libs", + "sdl2" + ] + } + } +} +``` diff --git a/doc/extends.md b/doc/extends.md new file mode 100644 index 0000000..dcea14a --- /dev/null +++ b/doc/extends.md @@ -0,0 +1,32 @@ + +# Extending cutekit + +By writing custom Python plugins, you can extend Cutekit to do whatever you want. + +First the file need to be located in `meta/plugins` and have the `.py` extension. +Then you can import cutekit and change/add whatever you want. + +For example you can add a new command to the CLI: + +```python +import os +import json +import magic +import logging +from pathlib import Path + + +from cutekit import shell, builder, const, project +from cutekit.cmds import Cmd, append +from cutekit.args import Args +from typing import Callable + + +def bootCmd(args: Args) -> None: + project.chdir() + print("Hello world!") + +append(Cmd("h", "hello", "Print hello world", bootCmd)) +``` + +This feature is used - for example - by [SkiftOS](https://github.com/skift-org/skift/blob/main/meta/plugins/start-cmd.py) to add the `start` command, that build packages and run a virtual machine. diff --git a/doc/spec/jexpr.md b/doc/spec/jexpr.md new file mode 100644 index 0000000..c3ea3a0 --- /dev/null +++ b/doc/spec/jexpr.md @@ -0,0 +1,92 @@ + +## Macros + +To avoid headache, Cutekit extends JSON through simple macros, this is what we call **Jexpr**. + + +### `@latest` + +Find the latest version of a command in the path. + +```json +"cc": { + "cmd": ["@latest", "clang"], // clang-14 +/* ... */ +``` + + +### `@uname` + +Query the system for information about the current operating system. + + +```json +"cc": { + "cmd": ["@uname", "machine"], // "x86_64" +/* ... */ +``` + +The `@uname` commands has 1 argument that may be: +- `node`: to get the current machine hostname. +- `machine`: to get the current machine running architecture + - `aarch64` is renamed to `arm64` + - `AMD64` is renamed to `x86_64` +- `system`: to get the current machine running operating system: + - `Linux` + - `Windows` +- `release`: to get the current machine operating system's version +- `version`: to get more information about the host operating system. + +### `@include` + +Include a manifest file. + +### `@read` + +Read a Json file and output its value. + +### `@join` + +Join two objects + +Example: + +```json +["@join", {"a": 1}, {"b": 2}] // {"a": 1, "b": 2} +``` + +### `@concat` + +Concatenate strings + +Example: + +```json +["@concat", "a", "b", "c"] // "abc" +``` + +### `@exec` + +Execute a command and return the output + +Example: + +```json +["@exec", "uname", "-m"] // "x86_64" +``` + +### `@eval` + +Execute python code and return the output + +Example: + +```json +"32limit": ["@eval", "2**32"] +``` + +### `@abspath` + +Returns the absolute path of a path. + + diff --git a/doc/spec/manifest.md b/doc/spec/manifest.md new file mode 100644 index 0000000..db971aa --- /dev/null +++ b/doc/spec/manifest.md @@ -0,0 +1,102 @@ + + +## Manifest file format + +### `id` + +The `id` of the package. This is used to identify the package in the manifest file. + +Example: + +```json +{ + "id": "hello" +} +``` + +### `type` + +The type of the package. This is used to identify the package in the manifest file. + +Example: + +```json +{ + "type": "exe" +} +``` + + +**Values:** +- `"exe"` +- `"lib"` + +### `description` + +The description of the package for the user. + +Example: + +```json +{ + "description": "Hello world" +} +``` + +### `enabledIf` + +A list of requirements for the package check against the build props. If the requirement is not met, the package will be disabled. + +```json +{ + "enabledIf": { + "freestanding": [ + false + ] + } +} +``` + +**Values:** + +`enableIf` is a map of variable and values: +``` +"variable-name": [array of expected value] +``` +If `variable-name` is equal to one of the value in the table, then the package will be enabled. + + +### `requires` + +Dependencies of the package. The name listed here must be the same as the `id` of the package or member of a provide list. + +Example: + +```json +{ + "requires": [ + "libc", + "libm" + ] +} +``` + +### `provides` + +An alias for the package. + +Example: + +```json +{ + "provides": [ + "hello" + ] +} +``` + +This alias may be used by other package when using `requires`. +This is used when you have multiple package implementing the same features, but only one is enabled through `enableIf`. + +**Value**: +- An array of `id`. \ No newline at end of file diff --git a/doc/spec/project.md b/doc/spec/project.md new file mode 100644 index 0000000..21bb786 --- /dev/null +++ b/doc/spec/project.md @@ -0,0 +1,33 @@ +## project.json + +The project file is the main file of the project. +It describes the project and its dependencies. + +### `id` + +The `id` of the project. This is used to identify the project. + +### `type` + +Should be `project`. + +### `description` + +The description of the project for the user. + +### `extern` + +A list of external dependencies for the project, for example: + +```json + +"externs": { + "cute-engineering/libheap": { + "git": "https://github.com/cute-engineering/libheap.git", + "tag": "v1.1.0" + } +} +``` + +You describe the project `id`, the `git` repository and the `tag` to use. + diff --git a/doc/spec/target.md b/doc/spec/target.md new file mode 100644 index 0000000..27a97a9 --- /dev/null +++ b/doc/spec/target.md @@ -0,0 +1,119 @@ + +## Target file format + +A target file is used for describing a new cross-compiler to use. +Generally, a target file is named like this: `{target}-{arch}.json`. For example, you could have: +- `host-x86-64` +- `windows-arm` +- ... + +### `id` + +The `id` of the target. This is used to identify the target in the target file. + +### `type` + +Should be `target`. + +### `props` + +A list of properties for the target. + +Example: + +```json +{ + "props": { + "arch": "x86_64", + "vendor": "pc", + "os": "linux", + "env": "gnu", + "abi": "elf", + "cpu": "x86_64", + "features": "fxsr,sse,sse2" + } +} +``` + +Theses may be accessed during compilation as C-Macros: `__ck_{prop}__`. + +### `tools` + +A list of tools for the target. + +Each tool is described like this: + +```json +"name": { + "cmd": "", + "args": [ + ... + ] +} +``` + +Where: +- `cmd` describe the command to run +- `arg` describes each argument to use (note: each entry of the table correspond to ONE argument). + +You have different tools names that you can use: +- "cc" +- "cxx" +- "ld" +- "ar" +- "as" + +**Example**: + +```json +{ + "tools": { + "cc": { + "cmd": ["@latest", "clang"], + "args": [ + "-target", + "x86_64-unknown-windows", + "-ffreestanding", + "-fno-stack-protector", + "-fshort-wchar", + "-mno-red-zone" + ] + }, + "cxx": { + "cmd": ["@latest", "clang++"], + "args": [ + "-target", + "x86_64-unknown-windows", + "-ffreestanding", + "-fno-stack-protector", + "-fshort-wchar", + "-mno-red-zone" + ] + }, + "ld": { + "cmd": ["@latest", "clang++"], + "args": [ + "-target", + "x86_64-unknown-windows", + "-nostdlib", + "-Wl,-entry:efi_main", + "-Wl,-subsystem:efi_application", + "-fuse-ld=lld-link" + ] + }, + "ar": { + "cmd": ["@latest", "llvm-ar"], + "args": [ + "rcs" + ] + }, + "as": { + "cmd": "nasm", + "args": [ + "-f", + "win64" + ] + } + } +} +``` diff --git a/doc/templates.md b/doc/templates.md new file mode 100644 index 0000000..774107d --- /dev/null +++ b/doc/templates.md @@ -0,0 +1,40 @@ + +# Templates + +Templates are based on this [repository (cute-engineering/cutekit-templates)](https://github.com/cute-engineering/cutekit-templates). +Each directory correspond to a template. + +You can create a new Cutekit project with the `ck I {template-name}` command. + +If you want to use another repository as a template, you can use the `ck I --repo="github-link" name` command. For example: + +```bash +ck I --repo="cute-engineering/cutekit-templates.git" host +``` + +## Writing a template + +When writing a template, you do it through a github repository (only github for now). +Then add a `registry.json` file at the root of the repository contaning a table of entry directories. + +For example, if you have a UI library called `cute-ui`, you can add a `registry.json` file like this: + +```json +[ + { + "id": "cute-ui-simple", + "description": "A simple template" + }, + { + "id": "cute-ui-advanced", + "description": "A more advanced template" + } +] +``` + +And each "id" will correspond to a directory in the repository: + +- `cute-ui-simple` will be in `cute-ui-simple/` +- `cute-ui-advanced` will be in `cute-ui-advanced/` + +