{"id":13423440,"url":"https://github.com/SanderMertens/bake","last_synced_at":"2025-03-15T17:31:46.481Z","repository":{"id":33916502,"uuid":"160625897","full_name":"SanderMertens/bake","owner":"SanderMertens","description":"Bake, A build system for building, testing and running C \u0026 C++ projects","archived":false,"fork":false,"pushed_at":"2025-03-06T04:17:11.000Z","size":2578,"stargazers_count":698,"open_issues_count":37,"forks_count":56,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-03-09T21:40:55.371Z","etag":null,"topics":["build-system","build-tool","c","cpp","developer-tools","environment-configuration","gamedev","gamedev-tool","git","github","indie","indiedev","package-manager"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"cortoproject/bake","license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SanderMertens.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-12-06T05:54:02.000Z","updated_at":"2025-03-06T04:17:15.000Z","dependencies_parsed_at":"2024-08-02T19:41:33.024Z","dependency_job_id":"fa25eafc-b993-4f82-b384-8175ae64f7e2","html_url":"https://github.com/SanderMertens/bake","commit_stats":{"total_commits":868,"total_committers":12,"mean_commits":72.33333333333333,"dds":0.09447004608294929,"last_synced_commit":"fe458884483b95618a8522fef7a527385829c631"},"previous_names":[],"tags_count":20,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMertens%2Fbake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMertens%2Fbake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMertens%2Fbake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SanderMertens%2Fbake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SanderMertens","download_url":"https://codeload.github.com/SanderMertens/bake/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243766862,"owners_count":20344828,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["build-system","build-tool","c","cpp","developer-tools","environment-configuration","gamedev","gamedev-tool","git","github","indie","indiedev","package-manager"],"created_at":"2024-07-31T00:00:34.624Z","updated_at":"2025-03-15T17:31:46.457Z","avatar_url":"https://github.com/SanderMertens.png","language":"C","readme":"[![.github/workflows/main.yml](https://github.com/SanderMertens/bake/actions/workflows/main.yml/badge.svg)](https://github.com/SanderMertens/bake/actions/workflows/main.yml)\n\n# bake\nThe Dutch IRS has a catchy slogan, which goes like this: \"Leuker kunnen we 't niet maken, wel makkelijker\". Roughly translated this means: \"We can't make it more fun, but we can make it easier\". Bake adopts a similar philosophy. Building C/C++ code will never be fun, but with bake you'll probably spend a little less time worrying about it.\n\nHere's how bake tries to alleviate some of the pain:\n- Minimal, platform independent project configuration (as in 2 lines of JSON minimal)\n- Create new projects with a single command\n- Builtin emscripten (webasm) support\n- Zero-dependencies, calls msvc, gcc, clang and emcc compilers directly\n- Refer to dependencies by logical names, no OS/environment dependent paths\n- Automatically include headers from dependencies\n- Out of the box macro's for exporting symbols\n- Automatically discover, order and build projects in directories without additional config\n- Recursively build projects \u0026 their dependencies for the right config with a single command\n- Generate single source/header files from any project\n- A test framework\n- Clone, build and run projects with their dependencies with a single command\n- Make projects warning free on all compilers/compiler versions with strict compilation mode\n- Out of the box support for running projects with address sanitizers\n- Manage projects \u0026 their git repositories with bake bundles\n\nBake is verified on the following platforms:\n\n- Linux\n- MacOS\n- Windows\n\nBake is verified on the following compilers\n- gcc (7, 8, 9, 10)\n- clang (8, 9, 10)\n- msvc\n\nBake is used as the primary build system for [Flecs](https://github.com/SanderMertens/flecs).\n\n## Contents\n* [Installation](#installation)\n* [Getting Started](#getting-started)\n* [FAQ](#faq)\n* [Manual](#manual)\n  * [Introduction](#introduction)\n  * [Building projects](#building-projects)\n  * [Running projects](#running-projects)\n  * [Project kinds](#project-kinds)\n  * [Project layout](#project-layout)\n  * [Project configuration](#project-configuration)\n  * [Project bundles](#project-bundles)\n  * [Template functions](#template-functions)\n  * [Templates](#templates)\n  * [Configuring Bake](#configuring-bake)\n  * [Installing Miscellaneous Files](#installing-miscellaneous-files)\n  * [Integrating Non-bake Projects](#integrating-non-bake-projects)\n  * [The Bake Environment](#the-bake-environment)\n  * [Environment Variables](#environment-variables)\n  * [Command line interface](#command-line-interface)\n  * [Writing drivers](#writing-drivers)\n* [Authors](#authors)\n* [Legal stuff](#legal-stuff)\n\n## Installation\n\nInstall bake using the following commands:\n\nOn Linux/MacOS:\n```demo\ngit clone https://github.com/SanderMertens/bake\nbake/setup.sh\n```\n\nOn Windows:\n\nRequires [Visual Studio Build Tools](https://visualstudio.microsoft.com/downloads/#build-tools-for-visual-studio-2022) or the full Visual Studio Community IDE installed with the `C++ CMake tools for Windows` and `Windows SDK` individual components included in the `Desktop development with C++` workload:\n```\ngit clone https://github.com/SanderMertens/bake\ncd bake\nsetup\n```\n\nOn MacOS/Linux bake will install a single script in `/usr/local/bin` which calls the bake binary in `~/bake`, which may prompt for your password during installation. This script allows you to call bake from any location without having to make changes to your environment.\n\nIf you'd rather not install this script, you can install bake in local mode:\n\n```c\ngit clone https://github.com/SanderMertens/bake\ncd bake\nmake -C build-$(uname) clean all\n./bake setup --local\n```\nAfter the setup has finished, the bake executable will be stored in `~/bake`. Make sure to add this directory to your `PATH` variable before using bake.\n \n## Upgrade bake\nYou can upgrade bake to the latest version by running this command:\n\n```demo\nbake upgrade\n```\n\n## Getting started\n\nThe following commands are useful for getting started with bake. Also, check out the `bake --help` command, which lists all the options and commands available in the bake tool.\n\n### Create and run new project\nTo create and run a new bake application project called `my_app`, run the following commands:\n\n```demo\nbake new my_app\nbake run my_app\n```\n\nYou can also run projects in interactive mode. This will automatically rebuild and restart an application when a project file changes. To run in interactive mode, simply add `--interactive` to the bake command:\n\n```demo\nbake run my_app --interactive\n```\n\n### Basic configuration with dependency and configuration for C driver\nThis example shows a simple configuration with a dependency on the `foo.bar` package and links with `pthread`.\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"foo.bar\"]\n    },\n    \"lang.c\": {\n        \"lib\": [\"pthread\"]\n    }\n}\n```\n\n### Build, rebuild and clean a project\n\n```demo\nbake\nbake rebuild\nbake clean\n```\n\nSpecify a build configuration:\n\n```demo\nbake --cfg release\n```\n\n### Clone \u0026 build a project from git\nBuild a project and its dependencies directly from a git repository using this command:\n\n```demo\nbake clone https://github.com/SanderMertens/example\n```\n\n### Export an environment variable to the bake environment\nBake can manage environment variables that must be set during the build. To export an environment variable to the bake environment, use this command:\n\n```demo\nbake export VAR=value\n```\nAlternatively, if you want to add a path to an environment variable like `PATH` or `LD_LIBRARY_PATH`, use this:\n\n```demo\nbake export PATH+=/my/path\n```\n\nThese variables are stored in a configuration file called `bake.json` in the root of the bake environment, which by default is `$HOME/bake`.\n\nTo export the bake environment to a terminal, use:\n```\nexport `bake env`\n```\n\n## FAQ\n\n### Bake is built under the GPL3.0 license. Does this mean I cannot use it for commercial projects?\nNo. As long as you do not distribute bake (either as source or binary) as part of your (closed source) deliverable, you can use bake for building your projects. This is no different than when you would use make for your projects, which is also GPL licensed.\n\n### I want my customers to use bake. Does the license allow for this?\nYes. As long as your customers use the open source version of bake, and you do not distribute bake binaries or source files with your product, your customers can use bake.\n\n### I noticed a premake file in the bake repository. Does bake need premake to be installed?\nNo. Bake uses premake to generate its makefiles (we would've used bake to build bake- but chicken \u0026 egg etc). The generated makefiles are included in the bake repository, so you won't need premake to use bake.\n\n### Why yet another build tool?\nTo put it bluntly, existing tools for C/C++ aren't great.\n\n### Is bake a package manager?\nNo. Bake has package-management like features, like resolving projects by logical name, automatic project discovery \u0026 associate projects with git repositories, but it does not pretend to be a full-fledged package manager. The only reason bake has these features is because it makes the build process easier.\n\n### Why are bake project configurations so simple?\nAll C/C++ project build configurations basically boil down to the same set of rules to translate source files into objects, and objects into shared objects or application binaries. Yet with most build systems you'll find yourself copy-pasting the same rules every time you create a new project.\n\nBake doesn't need to be told how to build C/C++ code. It just needs three pieces of information:\n- The project name\n- Whether it's an application or a package\n- A `src` and `include` directory\n\n### Why doesn't bake generate makefiles or visual studio files?\nMakefiles and Visual Studio files are just elaborate front-ends for how to call compilers. Bake calls the compiler directly. It has builtin drivers for gcc, clang, msvc and emcc, and it automatically detects for which compiler it's building.\n\n### How does bake compare to make?\nGNU make is a low-level tool that requires you to explicitly list all the rules required to translate code to binaries. Bake is a high-level tool that already knows how to build the code, and can do this with minimal configuration.\n\n### How does bake compare to CMake?\nCMake is a tool that generates other build configurations. When you use CMake you still need to use another tool like Make or Visual Studio to actually build your project. Bake builds your code directly.\n\nAnother big difference is that CMake requires you to specify project configuration in a custom language, whereas Bake configuration is specified in JSON. Here is a CMake configuration and a Bake configuration for the same project:\n\nCMake:\n```cmake\ncmake_minimum_required (VERSION 2.6)\n\ninclude_directories (\"bar\")\nadd_subdirectory (bar)\nset (EXTRA_LIBS ${EXTRA_LIBS} bar)\n\nproject (foo)\nadd_executable(foo foo.c)\n\ntarget_link_libraries (foo ${EXTRA_LIBS})\n```\n\nBake:\n```json\n{\n    \"id\": \"foo\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"bar\"]\n    }\n}\n```\n\nA difference that jumps out from the examples is that the bake configuration is agnostic to its environment. It knows where to find project `bar`, whereas in CMake this needs to be explicitly specified.\n\n### How does bake compare to premake?\nPremake is a lot like CMake, but with a Lua-based project configuration that's slightly less verbose. Premake also generates build configurations, and requires additional tools to actually build your code.\n\n### How does bake compare to Bazel?\nOut of all build systems, bake and bazel come closest in the way they approach building code. The biggest differences are:\n\n- Bake is a much, much smaller project\n- Bake is less controlling when it comes to your environment. If you want absolute control over which version of Python, make, gcc etc. you're using while building, Bazel can do a better job.\n- Bake only builds C/C++ code.\n- Bazel project identifiers are relative to a workspace. Bake project identifiers are universal.\n- Bazel has a custom language for project configuration\n\n### Can I link with non-bake libraries?\nYes. This example shows how to link with `libm`:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"lang.c\": {\n        \"lib\": [\"m\"]\n    }\n}\n```\n\nThis can be improved by ensuring that `libm` is only added on Linux (MacOS/Windows don't have `libm`):\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"${os linux}\": {\n        \"lang.c\": {\n            \"lib\": [\"m\"]\n        }\n    }\n}\n```\n\n### I want to wrap a C library so I can use it as a bake dependency. How do I do this?\nIt would be nice if we could wrap `libm.so` from the previous example in a bake `math` package, so we don't have to repeat this configuration for every project. Bake lets us do this with the `\"dependee\"` attribute:\n\n```json\n{\n    \"id\": \"math\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"dependee\": {\n        \"${os linux}\": {\n            \"lang.c\": {\n                \"lib\": [\"m\"]\n            }\n        }\n    }\n}\n```\n\nThis creates a new \"math\" package that you can now specify as regular bake dependency. The `\"language\": \"none\"` attribute lets bake know that there is no code to build, and this is a configuration-only project. The `dependee` attribute tells bake to not apply the settings inside the JSON object to the `math` project, but to the projects that depend on `math`.\n\nWe can now use the math package like this:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"math\"]\n    }\n}\n```\n\n### Where can I find the configuration options for C and C++ projects?\nYou can find language-specific configuration options in the README of the language driver projects:\n\nFor C: https://github.com/SanderMertens/bake/tree/master/drivers/lang/c\n\nFor C++: https://github.com/SanderMertens/bake/tree/master/drivers/lang/cpp\n\n### What is a driver?\nAll of the rules and instructions in bake that actually builds code is organized in bake \"drivers\". Drivers are shared libraries that bake loads when a project needs them. The most common used drivers are \"language drivers\", which contain all the build instructions for a specific language, like C or C++. Bake automatically loads the language drivers based on the `\"language\"` attribute in your `project.json`, as is specified here:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"language\": \"c\"\n    }\n}\n```\nBy default the language is set to \"c\", so if you do not specify a language, your project will build as a C project.\n\n### What does \"lang.c\" mean? When do I need to specify it? \nIn some cases you will want to provide configuration options that are specific to a language, like linking with C libraries on your system, or provide additional compiler flags. In that case, you have to tell bake that the configuration you are about to specify is for a specific driver. This is where \"lang.c\" comes in:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"language\": \"c\"\n    },\n    \"lang.c\": {\n        \"lib\": [\"m\"]\n    }\n}\n```\n\nThe `\"lang.c\"` member uniquely identifies the bake driver responsible for building C code, and bake will make all of the attributes inside the object (`\"lib\"`) available to the driver.\n\nIf you want to build a C++ project, instead of using the `\"lang.c\"` attribute, you have to use the `\"lang.cpp\"` attribute, which identifies the C++ driver:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"language\": \"c++\"\n    },\n    \"lang.cpp\": {\n        \"lib\": [\"m\"]\n    }\n}\n```\n\n### For C++ projects, should I specify cpp or c++ for the language attribute?\nYou can use either, but for specifying driver-specific configuration you always have to use `lang.cpp`.\n\n### How can I see a list of the available drivers?\nThe following command will show you a list of the available drivers:\n\n```\nbake list bake.*\n```\n\nEverything except for `bake.util` is a driver. If you just built bake for the first time, this will only show the `\"lang.c\"` and `\"lang.cpp\"` drivers.\n\n### Can I load more than one driver?\nYes! You can load as many drivers as you want. If you want to add a driver, simply add it to your configuration like this:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"my_custom_driver\": { }\n}\n```\n\n### Are there any example drivers I can use as a template?\nDriver documentation is a bit lacking at the moment, but we will eventually address that. In the meantime, you can take a look at the C driver to see what a fully fledged driver looks like:\n\nhttps://github.com/SanderMertens/bake/tree/master/drivers/lang/c\n\n### How do I install bake packages?\nBake relies on git to store packages. To install a package, use the `bake clone` command with a GitHub repository identifier:\n\n```\nbake clone SanderMertens/example\n```\n\nIf your git repository is not hosted on GitHub, simply provide the full git URL:\n\n```\nbake clone https://my_git_server.com/example\n```\n\nAny URL that is accepted by git is accepted by bake.\n\n### How does bake find dependencies of cloned projects?\nWhen bake clones a package with dependencies, it will try to also install those dependencies. It does this by taking the git URL specified to `bake clone`, and replacing the package name with the dependency name. For example, if the https://github.com/SanderMertens/example git repository depends on project `foobar`, bake would also look for https://github.com/SanderMertens/foobar.\n\nFuture versions of bake may provide more intelligent ways to locate packages.\n\n### Why use JSON for project configuration?\nA number of people have asked me why I used JSON for project configuration. There are two reasons: \n- It is a ubiquitous language that everyone understands, \n- It has a C parser that can be easily embedded into bake without adding dependencies\n\nA disadvantage of JSON is that while it is fine for trivial configurations, it can get a bit unwieldy once project configurations get more complex. In bake however, you can encapsulate complexity into a configuration-only project, and then include that project as a dependency in your project configuration ([example](https://github.com/SanderMertens/bake/tree/master/examples/c/pkg_w_dependee)).\n\nAdditionally, bake is not like traditional build tools where you specify rules with inputs and outputs in your project configuration. If you want to, for example, add a code generation step to your build, you write a driver for it, and then include the driver in your project configuration.\n\n### How can I specify a custom compiler?\nThe drivers for C \u0026 C++ projects by default use gcc/g++ (on Linux) and clang/clang++ (on MacOS). If you want to change the default compiler, you can set the `CC` (for C) and `CXX` (for C++) environment variables, as long as the command line options are compatible with gcc. Instead of setting the environment variables manually, you can make them part of a bake environment like this:\n\n```demo\nbake export CC=clang --env clang_env\n```\n\nTo use the environment, and build with clang, you can then invoke bake like this:\n```demo\nbake --env clang_env\n```\n\nTo export `CC` or `CXX` to the default environment, simply leave out the `--env` argument.\n\n### Where does bake store my binaries?\nBake always stores binaries in the `bin/arch-os-config` directory of your project. When your project is a public project (this is the default) binaries are also copied to the target bake environment, which by default is `$BAKE_HOME/arch-os/config/bin` or `$BAKE_HOME/bake/arch-os/config/lib`. By default, `$BAKE_HOME` is set to `~/bake`.\n\nTo prevent a project from being stored in the bake environment, add this to the `project.json`:\n\n```json\n\"value\": {\n    \"public\": false\n}\n```\n\nUsually you do not need to know where binaries are stored, as you can run applications with `bake run`, and specify dependencies by using their logical name.\n\n### How do I do a release build?\nBy default, binaries are built with the default debug configuration. To build a release configuration, add `--cfg release` to your bake command. You can add/change configurations in the bake configuration file. See \"Configuring Bake\" for more details.\n\n### How to use different versions of the same package?\nBake does not support having different versions of a package in the same environment. If you want to use different versions of the same package on a machine, you have to use different bake environments. You can do this by setting the `BAKE_HOME` environment variable. By default, this variable is set to `$HOME/bake`, but you can override it to any path you want. You can set `BAKE_HOME` in a new environment called `my_env` (for example) with this command:\n\n```\nbake export BAKE_HOME=/home/user/my_path --env my_env\n```\n\nTo set the variables in this environment, add `--env my_env` to any bake command, like this:\n\n```demo\nbake --env my_env\n```\n\n## Manual\n\n### Introduction\nThe goal of bake is to bring a level of abstraction to building software that is comparable with `npm`. Tools like `make`, `cmake` and `premake` abstract away from writing your own compiler commands by hand, but still require users to create their own build system, with proprietary mechanisms for specifying dependencies, build configurations etc.\n\nThis makes it difficult to share code between different people and organizations, and is arguably one of the reasons why ecosystems like `npm` are thriving, while ecosystems for native code are fragmented.\n\nBake is therefore not just a build tool like `make` that can automatically generate compiler commands. It is also a build system that specifies how projects are organized and configured. When a project relies on bake, a user does, for example, not need to worry about how to link with it, where to find its include files or whether binaries have been built with incompatible compiler flags.\n\nA secondary goal is to create a zero-dependency build tool that can be easily ported to other platforms. Whereas other build tools exist, like `make`, `premake`, `rake` and `gradle`, they all rely on their respective ecosystems (`unix`, `lua`, `ruby`, `java`) which complicates writing platform-independent build configurations. Bake's only dependency is the C runtime.\n\n### Creating a new Project\nYou can create a new bake project with the `bake new` command. This command has a few options, which lets you create different kinds of projects (see \"Project Kinds\"). By default, bake creates an \"application\" project, which is a standard executable. To create a new application project called `my_app`, run the following command:\n\n```\nbake new my_app\n```\n\nThis will create a new directory called `my_app` with the contents of a basic bake application project. If you want to create a bake package (a shared library), you can simply add `--package` to the command:\n\n```\nbake new my_pkg --package\n```\n\nWhen a new project is created, its metadata is also stored in the bake environment. That means that the project is now discoverable by bake, and can be used as dependency of other projects. You can inspect the bake environment with this command:\n\n```\nbake list\n```\n\nYour new project should show up in the list of projects.\n\nBake lets you create projects with nested identifiers, like `foo.bar`. This lets you create hierarchies of projects. The `.` notation is used to denote different elements in the project identifier. To use nested identifiers, simply specify their name with bake new:\n\n```\nbake new foo.bar\n```\n\nThis will create a new directory `foo-bar`. The project will appear as `foo.bar` when you do `bake list`.\n\n### Building Projects\nBake's primary task is to build the code in your projects, and generate binaries in a reliable and reproducible way. You can simply build a bake project by invoking the `bake` command:\n\n```\nbake\n```\n\nThis will recursively discover and build all bake projects in the current directory. The command is synonymous for running bake with the `build` action:\n\n```\nbake build\n```\n\nAlternatively you can also specify a directory to build, like so:\n\n```\nbake my_directory\nbake build my_directory\n```\n\nBake has a number of actions, of which the following are related to building your project:\n\n```\nbake build\nbake rebuild\nbake clean\n```\n\nThe `build` action incrementally builds your project, and will reuse artefacts from previous builds, like object files and binaries. The `rebuild` action cleans artefacts from previous builds, and is then followed by a regular build. The `clean` action cleans all build artefacts for the project.\n\nBake allows you to build for multiple platforms and build configurations from the same source tree, as it stores build artefacts in locations that are platform/configuration specific. When you do a `bake rebuild`, only the artefacts for the current platform / configuration are cleaned, whereas `bake clean` cleans artefacts for all platforms / configurations.\n\n#### Discovery\nBake automatically discovers projects in the provided path, or current directory if no path was specified. It will then order the discovered projects based on their dependencies, so that they are built in the correct order. This removes the need for building makefiles in which you explicitly have to maintain the build order for your projects. Bake uses the information in the `use` attribute of your project configuration (see [Project Configuration](#project-configuration)).\n\nBake will not attempt to discover projects in subdirectories of projects if those subdirectories have special meaning. The following directories are skipped, _only_ if they are found inside a bake project directory:\n\n- src\n- include\n- config\n- data\n- test\n- etc\n- lib\n- bin\n- install\n- examples\n- .bake_cache\n\nAdditionally, bake will skip any directories that start with a `.`.\n\n#### Build configurations\nBake lets you build projects with different build configurations, like `debug` and `release`. By default, bake has built-in settings for `debug` and `release` configurations. You can specify a build configuration with the `--cfg` flag:\n\n```\nbake my_project --cfg release\n```\n\nThe default configuration is `debug`. The difference between `debug` and `release` is that `debug` disables optimizations and enables debugging code (release adds the `-DNDEBUG` flag). Furthermore, `debug` builds add compiler debugging information (like `-g` in gcc).\n\nBake never mixes binaries between build configurations. Therefore, if you build a project in `release` mode, but its dependencies haven't been built in `release` mode yet, the build will fail. \n\n#### Recursive builds\nTo make working across configurations easier, bake lets you do so called \"recursive builds\". These builds don't just build the current project, but also all dependencies for a project (and dependencies of dependencies, hence recursive builds). When building a project in `release` mode, but all dependencies have been built in `debug` mode, you can simply do:\n\n```\nbake my_project --cfg release -r\n```\n\nThe `-r` flag enables recursive building, which will, in addition to the current project, rebuild all dependencies in release mode as well. Recursive builds work for any dependency that is available in the bake environment. Bake keeps track of where the source files of your projects are located on disk, which is how it can start a build for a dependency, even when it is not discoverable from the location where bake was invoked from.\n\n### Running Projects\nYou can run bake projects by using `bake run`, followed by either a folder or a project id:\n\n```\nbake run foo.bar\nbake run my_directory\n```\n\nThis only works for application projects (see [Project Kinds](#project-kinds)). Bake will automatically start the executable and monitor its status. Before running the project, bake will first attempt to do a recursive build (see [Recursive builds](#recursive-builds)) so that the project and all its dependencies are built and are available for the right configuration. You can specify a configuration just like you would when building:\n\n```\nbake run foo.bar --cfg release\n```\n\nAdditionally, bake lets you do interactive builds, which monitor changes from your project, and rebuild the project when a change occurs. To start an interactive build, add the `--interactive` flag:\n\n```\nbake run foo.bar --interactive\n```\n\nCurrently bake does not monitor changes in the source code of dependencies, though it may do so in the future.\n\n### Project Kinds\nBake supports different project kinds which are configured in the `type` property of a `project.json` file. The project kind determines whether a project is a library or executable, whether a project is installed to a bake environment and whether a project is managed or not. The following table shows an overview of the different project kinds:\n\nProject Kind | Description\n-------------|----------\napplication  | Executable\npackage      | Shared object\ntemplate     | Template for new bake projects\n\n#### Public vs private projects\nA public project is a project that is installed to the bake environment. In this environment, bake knows where to find include files, binaries and other project resources. This allows other projects to refer to these resources by the logical project name, and makes specifying dependencies between projects a lot easier.\n\nPrivate projects are projects that are not installed to a bake environment. Because of this, these projects cannot be located by other projects. Private projects may depend on public projects, but public projects cannot depend on private projects. Binaries of private objects are only stored in the bin folder in the project root.\n\n### Project Layout\nEach bake project uses the same layout. This makes it very easy to build bake projects, as bake always knows where to find project configuration, include files, source files and so on. A bake project has at least three files:\n\nDirectory / File | Description\n-----------------|------------\nproject.json | Contains build configuration for the project\nsrc | Contains the project source files\ninclude | Contains the project header files\n\nIn addition, a bake project can contain the following optional directories:\n\nDirectory / File | Description\n-----------------|------------\netc | Miscellaneous project-specific files\ninstall | Miscellaneous files that can be used by all projects in bake environment\ntemplates | Template projects that are automatically installed when building the project\n\nBake will by default build any source file that is in the `src` directory. If the project is public, files in the `include`, `etc` and `install` folders will be soft-linked to the bake environment on Linux/MacOS, and copied when using Windows.\n\nWhen bake builds a project, build artefacts are stored in these directories:\n\nDirectory / File | Description\n-----------------|------------\nbin | Contains project binaries\n.bake_cache | Contains temporary files, like object files and precompiled headers\n\nBake stores temporary files in platform- and configuration specific directories, so that you can safely do debug/release builds, and builds for different operating systems from the same source directory.\n\n### Project Configuration\nA bake project file is located in the root of a project, and must be called `project.json`. This file contains of an `id` describing the logical project name, a `type` describing the kind of project, and a `value` property which contains properties that customize how the project should be built.\n\nThis is a minimal example of a bake project file that builds an shared object. With this configuration, the project will be built with all values set to their defaults.\n\n```json\n{\n    \"id\": \"my_library\",\n    \"type\": \"package\"\n}\n```\n\nThis example shows how to specify dependencies and specify additional flags:\n\n```json\n{\n    \"id\": \"my_application\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"my_library\"]\n    },\n    \"lang.c\": {\n        \"cflags\": [\"-DHELLO_WORLD\"]\n    }\n}\n```\n\nIn this example, if `my_library` is a project that is discovered by bake, it will be built *before* `my_application`.\n\nThe following properties are available from the bake configuration and are specified inside the `value` property:\n\nProperty | Type | Description\n---------|------|------------\nlanguage | string | Language of the project. Is used to load a bake language driver. May be `null`.\nversion | string | Version of the project (use semantic versioning)\npublic | bool | If `true`, project is installed to `$BAKE_TARGET`\nuse | list(string) | List of dependencies using logical project ids. Dependencies must be located in either `$BAKE_HOME` or `$BAKE_TARGET`.\nuse_private | list(string) | Same as \"use\", but dependencies are private, which means that header files will not be exposed to dependees of this project.\nuse_runtime | list(string) | Specify dependencies that a project needs at runtime, but that are not used/linked with during build time.\nuse-bundle | list(string) | Bundles to be used by project. If the bundles are also specified as a repository, bake will be able to automatically download \u0026 find dependencies in the specified bundles.\namalgamate | bool | Experimental. Generate amalgamated header and source file for the project.\nsources | list(string) | List of paths that contain source files. Default is `src`. The `$SOURCES` rule is substituted with this value.\nincludes | list(string) | List of paths that contain include files.\nkeep_binary | bool | Do not clean binary files when doing bake clean. When a binary for the target platform is present, bake will skip the project. To force a rebuild, a user has to explicitly use the `bake rebuild` command.\n\nThe `cflags` attribute is specified inside the `lang.c` property. This is because `cflags` is a property specific to the C driver. For documentation on which properties are valid for which drivers, see the driver documentation.\n\n#### Private dependencies\nWhen projects depend on other projects that require additional library paths or include paths, it may not be desirable to require having these properties propagate to dependees. For example, `bar` depends on `foo`, and `foo` requires adding an `include` path to the build configuration. Now, `helloworld` depends on `bar`, but it does not need to know about `foo`.\n\nTo prevent the `foo` build settings from propagating to `helloworld`, `bar` will need to configure `foo` as a \"private dependency\". The following configuration shows how to do this:\n\n```json\n{\n    \"id\": \"bar\",\n    \"type\": \"package\",\n    \"value\": {\n        \"use_private\": [\"foo\"]\n    }\n}\n```\n\nThis way, `foo` is still added as a dependency to `bar`, but `helloworld` will not be exposed to `foo`, nor inherit any of its build settings.\n\n### Template Functions\nBake property values may contain calls to template functions, which in many cases allows project configuration files to be more generic or less complex. Additionally, template functions can be used to parameterize bake template projects. Template functions take the following form:\n\n```\n${function_name argument}\n```\n\nThey are used like this:\n\n```json\n{\n    \"id\": \"my_project\",\n    \"type\": \"package\",\n    \"value\": {\n        \"include\": [\"${locate include}\"]\n    }\n}\n```\n\nThe following functions are currently supported:\n\nFunction | Description\n---------|-------------\nlocate | Locate project paths in the bake environment\nos | Match or return operating system\nlanguage | Match or return target language\nid | Return project identifier\n\nThe next sections are detailed description of the supported functions:\n\n#### locate\nThe locate function allows a project configuration to use any of the project paths in the bake environment. This functionality can also be used programmatically, through the `ut_locate` function in the `bake.util` package.\n\nParameter | Description\n----------|-------------\npackage | The package directory (lib)\ninclude | The package include directory\netc | The package etc directory\nlib | The package library (empty if an executable)\napp | The package executable (empty if a library)\nbin | The package binary\nenv | The package environment\n\n#### os\nThe `os` function can be used to specify platform-specific settings, or use the platform string in a path. The following example demonstrates how it can be used:\n\n```json\n{\n    \"${os linux}\": {\n        \"include\": [\"includes/linux\"]\n    }\n}\n```\n\nThe `os` function can match both operating system and architecture. The following expressions are all valid:\n\n- x86-linux\n- darwin\n- x86_64\n- x86_64-darwin\n- i386\n\nFor a full description of the expressions that are supported, see the documentation of `ut_os_match`.\n\nThe `os` function may be nested:\n\n```json\n{\n    \"${os linux}\": {\n        \"include\": [\"includes/linux\"],\n        \"${os x86_64}\": {\n            \"lib\": [\"mylib64\"]\n        },\n        \"${os x86}\": {\n            \"lib\": [\"mylib32\"]\n        }\n    }\n}\n```\n\nIf no argument is provided to `os`, it will return the current architecture in the following format:\n\n```\narch-os\n```\n\nThis format is consistent with the platform-specific bin path under which bake stores project binaries (like `bin/x86-linux`).\n\n#### language\nThe `language` function matches or returns the language of the project. \n\nWhen an argument is provided, it is matched against the current language:\n```json\n{\n    \"${language c}\": { \n        \"lib\": [\"my_c_lib\"]\n    },\n    \"${language cpp}\": {\n        \"lib\": [\"my_cpp_lib\"]\n    }\n}\n```\nThe function accepts both `cpp` and `c++` for C++ projects.\n\nWhen the argument is omitted, the current language is returned. This is particularly effective in combination with the `dependee` attribute, when dependees can be implemented in different languages:\n\n```json\n{\n    \"dependee\": {\n        \"lang.${language}\": {\n\n        }\n    }\n}\n```\n\n#### id\nThe `id` function returns the current project id in various formats. When the function is used without arguments, it returns the project id as it appears in the `project.json` file:\n\n```\n${id}\n```\n\nTo obtain the id in other formats, the following arguments can be passed to the `id` functions:\n\nParameter | Description | Example\n----------|-------------|---------\nno parameter | | foo.bar\nbase | Last element of an id | bar\nupper | Upper case, replace '.' with '\\_'. Used for macro's | FOO_BAR\ndash | Replace '.' with '-'. Used for repository names | foo-bar\nunderscore | Replace '.' with '\\_'. Used for variable names | foo_bar\n\n### Project bundles\nBake bundles let projects specify in which repositories their dependencies are located, and which revision of those dependencies they require. All repositories and their revisions in a bundle are expected to be compatible with each other. This makes it easier to work with projects that have many (open source) dependencies, where the dependencies have their own release cycles and rules for versioning.\n\nIf bundles are setup correctly, the following commands can all automatically download and build the correct set of dependencies:\n\nRun directly from a repository:\n```\nbake run https://github.com/SanderMertens/example\n```\n\nClone a bake project and its dependencies:\n```\nbake clone https://github.com/SanderMertens/example\n```\n\nRecursively build a project:\n```\nbake -r example\n```\n\nThis is a simple example of a bundle configuration:\n\n```json\n{\n    \"id\": \"example\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"example_library\"]\n    },\n    \"bundle\": {\n        \"repositories\": {\n            \"example_library\": \"https://github.com/SanderMertens/example_library\"\n        }\n    }\n}\n```\n\nThis example only contains information about where the `example_library` project can be found. When a user clones, runs or recursively builds the project, bake will automatically clone the `example_library` project if it is not locally available. Alternatively, this information can be stored in a separate project:\n\n```json\n{\n    \"id\": \"example_bundle\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"bundle\": {\n        \"default-host\": \"https://github.com/SanderMertens\",\n        \"repositories\": {\n            \"example_library\": \"SanderMertens/example_library\",\n            \"foo.bar\": \"SanderMertens/foo-bar\",\n            \"hello.world\": \"SanderMertens/hello-world\"\n        }\n    }\n}\n```\n\nThis is a configuration for a project that only contains bundle information. Note how it uses the `default-host` attribute to shorten the URLs. A bake project can automatically load this bundle when it is built by specifying the bundle in the `use-bundle` attribute:\n\n```json\n{\n    \"id\": \"example\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use-bundle\": [\"example_bundle\"]\n    },\n    \"bundle\": {\n        \"repositories\": {\n            \"example_bundle\": \"https://github.com/SanderMertens/example_bundle\"\n        }\n    }    \n}\n```\n\nNote how the project also adds the bundle project to the `repositories` list in its `bundle` section. This is not required, but is recommended so that bake will be able to clone the bundle if `example` is built in an environment that does not contain `example_bundle`. If the repository configuration is omitted and `example_bundle` cannot be found by bake the project will fail to build.\n\nIf a project wants to use a specific branch, commit and/or tag of a repository, it can do so by adding a `refs` property to the `bundle` section:\n\n```json\n{\n    \"id\": \"example_bundle\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"bundle\": {\n        \"default-host\": \"https://github.com/SanderMertens\",\n        \"repositories\": {\n            \"example_library\": \"SanderMertens/example_library\",\n            \"foo.bar\": \"SanderMertens/foo-bar\",\n            \"hello.world\": \"SanderMertens/hello-world\"\n        },\n        \"refs\": {\n            \"v1.0\": {\n                \"example_library\": {\n                    \"branch\": \"master\",\n                    \"tag\": \"v1.0\"\n                },\n                \"foo.bar\": {\n                    \"branch\": \"master\",\n                    \"tag\": \"v1.0\"\n                },\n                \"hello.world\": {\n                    \"branch\": \"master\",\n                    \"commit\": \"52ba2e129a6359f06f3437e7f46b9f466464b495\"\n                }\n            }\n        }\n    }\n}\n```\n\nTo use this specific set of revisions, a project should specify its id in the `use-bundle` property, like so: \n\n```json\n{\n    \"use-bundle\": [\"example_bundle:v1.0\"]\n}\n```\n\nThe above bundle configuration can be shortened with the `default-branch` and `default-tag` properties:\n\n```json\n{\n    \"id\": \"example_bundle\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"bundle\": {\n        \"default-host\": \"https://github.com/SanderMertens\",\n        \"repositories\": {\n            \"example_library\": \"SanderMertens/example_library\",\n            \"foo.bar\": \"SanderMertens/foo-bar\",\n            \"hello.world\": \"SanderMertens/hello-world\"\n        },\n        \"refs\": {\n            \"v1.0\": {\n                \"default-branch\": \"master\",\n                \"default-tag\": \"v1.0\",\n                \"hello.world\": {\n                    \"commit\": \"52ba2e129a6359f06f3437e7f46b9f466464b495\"\n                }\n            }\n        }\n    }\n}\n```\n\nIn cases where the revision id is the same as the tag, the `tag` and `default-tag` properties can be omitted, as bake will automatically use this id as the tag when a project has no tag and no commit specified. Additionally, if no branch is specified, master is assumed. Therefore the above configuration is equivalent to this:\n\n```json\n{\n    \"id\": \"example_bundle\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"bundle\": {\n        \"default-host\": \"https://github.com\",\n        \"repositories\": {\n            \"example_library\": \"SanderMertens/example_library\",\n            \"foo.bar\": \"SanderMertens/foo-bar\",\n            \"hello.world\": \"SanderMertens/hello-world\"\n        },\n        \"refs\": {\n            \"v1.0\": {\n                \"hello.world\": {\n                    \"commit\": \"52ba2e129a6359f06f3437e7f46b9f466464b495\"\n                }\n            }\n        }\n    }\n}\n```\n\nThis allows for shorter bundle configurations, where the bundle only needs to capture deviations from what is considered good practice. The exception to this rule is if a set of revisions has the `default` id. `default` specifies the set of revisions that are loaded when no bundle id, or `default`, is specified. \n\nIt is possible to add bundles to the bake configuration. This ensures that repositories in the environment are guaranteed to be of the revisions in the configured bundle. If a bundle is configured with bake, and a project is loaded that has a different configuration (repository, branch, tag, commit) for a project, it will fail to build. To add a bundle to bake's configuration, use the `bake use` command:\n\n```\nbake use example_bundle:v1.0\n```\n\nAttempting to load a project with different settings for any of the projects in the `example_bundle` bundle will result in an error. For example, if a project specifies project `hello.world` with tag `v1.0`, bake will reject it. Additionally, if a project specifies project `foo.bar` with tag `v2.0` bake will also reject the configuration. Even though `foo.bar` is not explicitly added to `v1.0`, bake adds it automatically when it loads the bundle configuration.\n\nIf a project specifies its repository URL in the `repository` property, it must match with bundle configurations, or bake will reject the project. For example, trying to load the following project configuration against the previous bundle will fail because the URL does not match:\n\n```json\n{\n    \"id\": \"foo.bar\",\n    \"type\": \"library\",\n    \"value\": {\n        \"repository\": \"https://gitlab.com/foo-bar\"\n    }\n}\n```\n\nBake will not automatically download dependencies during a build. Dependencies are only automatically downloaded for recursive builds, which are enabled with the `-r` argument:\n\n```\nbake -r\n```\n\n### Templates\nBake lets you create template projects which contain boilerplate code for common types of applications. Template projects look like regular projects, with two exceptions:\n\n- The project type is set to `template`\n- Files may contain template functions that are resolved when instantiating a template\n\nYou can create a new template project by specifying the `--template` flag when using the `bake new` command:\n\n```\nbake new my_template --template\n```\n\nThis creates a new template project which can be instantiated like this:\n\n```\nbake new my_app -t my_template\n```\n\nA template project can be parameterized using bake template functions (see previous chapter), like so:\n\n#### Using template functions \n```c\nint main(int argc, char *argv[]) {\n\n    printf(\"Hello ${id}!\");\n\n    return 0;\n}\n```\n\nTemplate functions may occur at any point in your files. Not all files in a project are parsed. Only files with the following extensions are considered by the template parser:\n\n- c, cpp, h, hpp, html, js, css, json, md, sh, bat, lua, python, java, cs, make\n\nAdditionally, files with the following filename will be considered:\n\n- Makefile\n\nThese lists may be extended with additional extensions and filenames.\n\nAdditionally, filenames may also be parameterized with bake template functions. The syntax for doing so is (`xxx` is a placeholder for parts of the filename):\n\n```\nxxx__\u003ctemplate function\u003e.\u003cfile extension\u003e\nxxx__\u003ctemplate function\u003e_\u003ctemplate argument\u003e.\u003cfile extension\u003e\nxxx__\u003ctemplate function\u003e__xxx.\u003cfile extension\u003e\nxxx__\u003ctemplate function\u003e_\u003ctemplate argument\u003e__xxx.\u003cfile extension\u003e\n```\n\nFor example, if you want a source file in your template project to have the base name of the instantiated project, you can name it like this:\n\n```\n__id_base.c\n```\n\nThis is equivalent to the template function:\n```\n${id base}.c\n```\n\n#### Running templates\nIf you are developing a new template, you'll often find yourself wanting to instantiate it to test modifications to the template. To make this process easier, bake lets you instantiate templates directly. Simply do:\n\n```\nbake run my_template --template\n```\n\nwhere `my_template` is the template name. This will cause bake to automatically instantiate a new temporary project with the template.\n\n### Configuring Bake\nBake can be optionally configured with configuration files that specify the environment in which bake should run and the build configuration that should be used. Bake locates a bake configuration file by traveling upwards from the current working directory, and looking for a `bake.json` file. If multiple files are found, they are applied in reverse order, so that the file that is \"closest\" to the project takes precedence.\n\nA bake configuration file consists out of an `environment` and a `configuration` section. The `configuration` section contains parameters that are not specific to a project, but influence how code is built. The `environment` section contains a list of environment variables and their values which are loaded when bake is started.\n\nThe `bake env` command prints the bake environment to the command line in a format that can be used with the `export` bash command, so that the bake environment can be easily exported to the current shell, like so:\n\n```\nexport `bake env`\n```\n\n```note\nBake automatically adds `$BAKE_HOME/bin` to the `PATH` environment variable. This ensures that even when applications (tools) are not installed to a global location, such as `/usr/local/bin`, they can still be directly accessed from a shell when the bake environment is exported.\n```\n\nThe following table is a list of the configuration parameters:\n\nParameter | Type | Description\n----------|------|------------\nsymbols | bool | Enable or disable symbols in binaries\ndebug | bool | Enable or disable debugging (defines NDEBUG if `false`)\noptimizations | bool | Enable or disable optimizations\ncoverage | bool | Enable or disable coverage\nstrict | bool | Enable or disable strict building\n\n```note\nIt is up to plugins to provide implementations for the above parameters. Not all parameters may be implemented. Refer to the plugin documentation for specifics.\n```\n\nThis is an example configuration file:\n\n```json\n{\n    \"configuration\":{\n        \"debug\":{\n            \"symbols\":true,\n            \"debug\":true,\n            \"optimizations\":false,\n            \"coverage\":false,\n            \"strict\":false\n        },\n        \"release\":{\n            \"symbols\":false,\n            \"debug\":false,\n            \"optimizations\":true,\n            \"coverage\":false,\n            \"strict\":false\n        }\n    },\n    \"environment\":{\n        \"default\":{\n            \"PATH\": [\"/my/path\"],\n            \"FOO\": \"Some value\"\n        }\n    }\n}\n```\n\nNote that environment variables configured as a JSON array (as shown with the `PATH` variable), are appended to their current value. Elements in the array are separated by a `:` or `;`, depending on the platform.\n\nWith the `--cfg` and `--env` flags the respective configuration or environment can be selected.\n\n### Installing Miscellaneous Files\nFiles in the `install` and `etc` directories are automatically copied to the project-specific locations in the bake environment, so they can be accessed from anywhere (see below). The `install` folder installs files directly to a location where other projects can also access it, whereas files in `etc` install to the project-specific location in the bake environment. For example, the following files:\n\n```\nmy_app\n |\n |-- etc\n |    | index.html\n |    + style.css\n |\n +-- install/etc\n      | image.jpg\n      + manual.pdf\n```\n\nwould be installed to the following locations:\n\n```\n$BAKE_HOME/platform/config/etc/my_app/index.html\n$BAKE_HOME/platform/config/etc/my_app/style.html\n$BAKE_HOME/platform/config/etc/image.jpg\n$BAKE_HOME/platform/config/etc/manual.pdf\n```\n\nBake allows projects to differentiate between different platforms when installing files from the `etc` and `install` directories. This can be useful when for example distributing binaries for different architectures and operating systems. By default, all files from these directories installed. However, bake will look for subdirectories that match the platform string. Files in those directories will only be installed to that platform. For example, consider the following tree:\n\n```\nmy_app\n |\n +-- etc\n      |-- Linux/linux_manual.html\n      |\n      |-- Darwin/darwin_manual.html\n      |\n      |-- Linux-i686/libmy_binary.so\n      |\n      |-- Linux-x86_64/libmy_binary.so\n      |\n      |-- Linux-armv7l/libmy_binary.so\n      |\n      +-- Darwin-x86_64/libmy_binary.so\n```\n\nHere, only the `libmy_binary.so` that is in the directory that matches the platform string will be installed.\n\nThe platform string is case independent. It allows for a number of different notations. For example, both `x86-linux` and `linux-x86` are allowed. In addition, projects can also just specify the operating system name, in which case the file will be installed to all architectures, as long as the operating system matches the directory name.\n\nTo see the exact matching of the platform string, see the implementation of `ut_os_match` in `bake.util`.\n\n### Integrating Non-Bake Projects\nIt is not uncommon that a project needs to include or link with a project that itself was not built with bake. Often such projects require that you specify custom include paths, library paths, and link with specific libraries. When you have many projects that depend on such an external project, it can become tedious having to repeat these properties in every `project.json`.\n\n#### Wrapping external projects\nBake allows you to create a project that \"wraps around\" the external project, in which you describe this build configuration once. Once done, projects can simply add this project as a dependency, and the properties will be automatically added.\n\nConsider a project that requires dependees to add `/usr/local/include/foobar` to their include path, that need to link with `libfoobar.so`, which is a library located in `/usr/local/lib/foobar`. For such a project, this is what the `project.json` could look like:\n\n```json\n{\n    \"id\": \"foobar\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\",\n    },\n    \"dependee\": {\n        \"lang.c\": {\n            \"include\": [\"/usr/local/include/foobar\"],\n            \"libpath\": [\"/usr/local/lib/foobar\"],\n            \"lib\": [\"foobar\"]\n        }\n    }\n}\n```\n\nLets go over each property. The first two specify that the project is a bake package with the id `foobar`. Because bake packages are public by default, we do not have to explicitly add `\"public\": true` to the `project.json` file to ensure that other packages can find this dependency.\n\nThe next property is `\"language\": \"none\"`. This ensures that when ran, bake does not try to build anything for the package. It also ensures that when specifying this package as a dependency, bake will not try to link with any binaries.\n\nThe `dependee` property is where the properties are specified for projects that depend on `foobar`. For every dependee project, bake will add the include, libpath and lib properties to those of the dependee configuration. Therefore, a project that depends on `foobar`, simply can do:\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"foobar\"]\n    }\n}\n```\n\n... and bake will take care of the rest.\n\n#### Include external files from bake environment\nWhen include files or libraries are not installed to a common system location, you can use bake to make these files available to dependee projects as well. Suppose we have a project called `helloworld`, which is shipped as a library `libhelloworld.so`, and two header files called `helloworld.h` and `helloworld_types.h`. We could include these files in a bake project, like this:\n\n```\nhelloworld\n |\n +-- include\n      |-- helloworld.h\n      +-- helloworld_types.h\n```\n\nThat way, when running bake, they are installed to the bake environment and are available to other projects. However, there is a potential problem with this approach. The `helloworld.h` file might for example depend on `helloworld_types.h`, simply by doing:\n\n```c\n#include \u003chelloworld_types.h\u003e\n```\n\nBecause bake does not automatically add project-specific include paths to the include path when compiling (to prevent name-clashes), that include file will not be found by the compiler. Therefore, an additional property is required that includes the correct path from the bake environment. Instead of hard-coding that path, bake provides a convenient way to do this:\n\n```json\n{\n    \"id\": \"helloworld\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"dependee\": {\n        \"include\": [\"${locate include}\"],\n    }\n}\n```\n\nThe `${locate include}` part of the include path will be substituted by the project-specific include folder when the `project.json` is parsed.\n\n#### Link external files from global environment\nWhen a project needs to link with an external binary, one option is to install it to a global location. The bake equivalent is to install it to the `lib` directory in the bake environment. That way, the library will be installed to `$BAKE_TARGET/lib`.\n\nTo install the library to this location, it needs to be added to the project folder. Add the library to this location:\n\n```\nhelloworld\n |\n +-- install/lib/libhelloworld.so\n```\n\nThe project configuration now needs to be configured so that dependee projects link with the library:\n\n```json\n{\n    \"id\": \"helloworld\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"dependee\": {\n        \"lib\": [\"helloworld\"]\n    }\n}\n```\n\n#### Link external files from bake environment\nIn some cases it may be desirable to link with a library without copying it to a public location, like `/usr/local/lib`. In that case, the library can also be copied to the bake environment, in the same way we did for the include file. First, the library needs to be installed to a project specific location. This can be accomplished by storing it in the `lib` directory in the project:\n\n```\nhelloworld\n |\n +-- lib/libhelloworld.so\n```\n\nNow the `dependee` section in the `project.json` file needs to be adjusted so that projects depending on `helloworld` will link with the correct library. To avoid having to rely on `LD_LIBRARY_PATH`, or having to specify a full path in the project configuration, we can use the `link` property in combination with a bake template function. The full configuration now looks like this:\n\n```json\n{\n    \"id\": \"helloworld\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"dependee\": {\n        \"link\": [\"${locate lib}/helloworld\"]\n    }\n}\n```\n\nBake will automatically expand the expression in the `link` path so that it contains the `lib` and `.so` prefixes. The `link` property will cause bake to link with the library using a hard-coded path, just like other project dependencies.\n\n```warning\nSome prebuilt libraries cannot be linked with using a hard-coded path. Typically libraries that have been compiled with \"--soname\" may cause problems, as the hardcoded path will be overwritten at link-time with the name provided to \"--soname\", which will cause the runtime linker to fail.\n```\n\n#### Deploying to multiple operating systems\nWhen deploying binaries, a project likely needs to include versions for multiple operating systems. This can be done by storing the binaries in a directory that matches the target operating system. The following tree shows the `helloworld` project with two binaries, for Linux and MacOS:\n\n```\nhelloworld\n |\n +-- lib\n      |-- Linux-i686/libhelloworld.so\n      |-- Linux-x86_64/libhelloworld.so\n      +-- Darwin-x86_64/libhelloworld.dylib\n```\n\nBake will automatically install and link with the binary that corresponds with the target platform. Note that bake also automatically tries to find libraries that end in `dylib` on MacOS.\n\n#### Putting it all together\nThe following tree and project file show a non-bake project where the include files and binary file are installed to the bake environment, and the project supports multiple operating systems.\n\nFiles:\n```\nhelloworld\n |-- project.json\n |\n |-- include\n |    |-- helloworld.h\n |    +-- helloworld_types.h\n |    \n +-- lib\n      |-- Linux-i686/libhelloworld.so\n      |-- Linux-x86_64/libhelloworld.so\n      +-- Darwin-x86_64/libhelloworld.dylib\n```\n\nproject.json:\n\n```json\n{\n    \"id\": \"helloworld\",\n    \"type\": \"package\",\n    \"value\": {\n        \"language\": \"none\"\n    },\n    \"dependee\": {\n        \"include\": [\"${locate include}\"],\n        \"link\": [\"${locate lib}/helloworld\"]\n    }\n}\n```\n\n### The Bake Environment\nBake installs projects to the \"bake environment\". The bake environment is located in a location specified by the `BAKE_HOME` environment variable, and contains all the metadata and binaries for public projects, miscellaneous files and templates. By default, the bake environment is located in `~/bake`. A different location can be specified by changing the value of the `BAKE_HOME` environment variable.\n\nProjects in the bake environment can be automatically discovered and linked with by using their logical name. Here is an example of two public projects, one `application` and one `package`, where the `application` depends on the `package`:\n\n```json\n{\n    \"id\": \"my_lib\",\n    \"type\": \"package\"\n}\n```\n\n```json\n{\n    \"id\": \"my_app\",\n    \"type\": \"application\",\n    \"value\": {\n        \"use\": [\"my_lib\"]\n    }\n}\n```\n\nNote that neither project configuration specifies where they are built to, or where to find the `my_lib` project. This is automatically managed by the bake environment.\n\nTo get an overview of the projects stored in the bake environment, you can do:\n\n```\nbake list\n```\n\nThe bake environment stores platform-specific data (such as binaries) in a location that is specific to a platform and build configuration. For example, if you are doing a debug build on Windows, you will find a directory in `$BAKE_HOME` called:\n\n```\nx64-Windows/debug\n```\n\nDuring a build, this directory is accessible through the `BAKE_TARGET` environment variable. This will contain all binaries (in `bin` and `lib` directories) for projects built for this platform and build configuration. The `bake list` command shows which projects have been built for which build configuration.\n\n### Environment Variables\nBake uses the following environment variables:\n\nVariable | Description\n---------|------------\nBAKE_HOME | Location of the bake environment\nBAKE_CONFIG | The current build configuration used by bake (`debug` by default)\nBAKE_ENVIRONMENT | The current build environment used by bake (`default` by default)\nBAKE_VERBOSITY | Specify the bake logging level (`INFO` by default)\nBAKE_ARCHITECTURE | Specify the processor architecture (default is the host architecture)\nBAKE_OS | Specify the operating system (default is the host operating system)\n\n### Command line usage\nThe following is the output of `bake --help`\n\n```\nUsage: bake [options] \u003ccommand\u003e \u003cpath\u003e\n\nOptions:\n  -h,--help                    Display this usage information\n  -v,--version                 Display version information\n\n  --cfg \u003cconfiguration\u003e        Specify configuration id\n  --env \u003cenvironment\u003e          Specify environment id\n  --strict                     Manually enable strict compiler options\n  --optimize                   Manually enable compiler optimizations\n\n  --package                    Set the project type to package\n  --template                   Set the project type to template\n  --test                       Create a test project\n  --to-env                     Clone projects to the bake environment source path (use with clone)\n  --always-clone               Clone dependencies even if found in the bake environment (use with clone)\n\n  --id \u003cproject id\u003e            Specify a project id\n  --type \u003cpackage|template\u003e    Specify a project type (default = \"application\")\n  --language \u003clanguage\u003e        Specify a language for project (default = \"c\")\n  --artefact \u003cbinary\u003e          Specify a binary file for project\n  -i,--includes \u003cinclude path\u003e Specify an include path for project\n  --private                    Specify a project to be private (not discoverable)\n\n  -a,--args [arguments]        Pass arguments to application (use with run)\n  --interactive                Rebuild project when files change (use with run)\n  --run-prefix                 Specify prefix command for run\n  --test-prefix                Specify prefix command for tests run by test\n  -r,--recursive               Recursively build all dependencies of discovered projects\n  -t [id]                      Specify template for new project\n  -o [path]                    Specify output directory for new projects\n\n  --show-repositories          List loaded repositories (use with list)\n\n  -v,--verbosity \u003ckind\u003e        Set verbosity level (DEBUG, TRACE, OK, INFO, WARNING, ERROR, CRITICAL)\n  --trace                      Set verbosity to TRACE\n  --debug                      Set verbosity to DEBUG (highest verbosity)\n\nCommands:\n  new [path]                   Initialize new bake project\n  run [path|project id]        Build \u0026 run project\n  build [path]                 Build a project (default command)\n  rebuild [path]               Clean and build a project\n  clean [path]                 Clean a project\n  test [path]                  Run tests of project\n  coverage [path]              Run coverage analysis for project\n  cleanup                      Cleanup bake environment by removing dead or invalid projects\n  reset                        Resets bake environment to initial state, save for bake configuration\n  publish \u003cpatch|minor|major\u003e  Publish new project version\n  install \u003cproject id\u003e         Install project to bake environment (repository must be known)\n  uninstall [project id]       Remove project from bake environment\n  clone \u003cgit url\u003e              Clone and build git repository and dependencies\n  use \u003cproject:bundle\u003e         Configure the environment to use specified bundle\n  update [project id]          Update an installed package or application\n  foreach \u003ccmd\u003e                Run command for each discovered project\n\n  env                          Echo bake environment\n  upgrade                      Upgrade to new bake version\n  export \u003cNAME\u003e=|+=\u003cVALUE\u003e     Add variable to bake environment\n\n  info \u003cpackage id\u003e            Display info on a project in the bake environment\n  list [filter]                List packages in bake environment\n\nExamples:\n  bake                         Build all projects discovered in current directory\n  bake my_app                  Build all projects discovered in my_app directory\n  bake new                     Create new application project in current directory\n  bake new my_app              Create new application project in directory my_app\n  bake new my_lib --package    Create new package project in directory my_lib\n  bake new my_tmpl --template  Create new template project in directory my_tmpl\n  bake new game -t sdl2.basic  Create new project from the sdl2.basic template\n  bake run my_app -a hello     Run my_app project, pass 'hello' as argument\n  bake publish major           Increase major project version, create git tag\n  bake info foo.bar            Show information about package foo.bar\n  bake list foo.*              List all packages that start with foo.\n```\n\n### Writing Drivers\nBake has a plugin architecture, where a plugin describes how code should be built for a particular language. Bake plugins are essentially parameterized makefiles, with the only difference that they are written in C, and that they use the bake build engine. Plugins allow you to define how projects should be built once, and then reuse it for every project. Plugins can be created for any language.\n\nThe bake build engine has a design that is similar to other build engines in that it uses rules that depend on other rules. Rules have rule-actions, which get executed when a rule is outdated. Whether a rule is outdated or not is determined by comparing timestamps of the rule dependencies with the timestamps of the rule output.\n\nRules are written in their respective language plugins in C. A simple set of rules that builds a binary from a set of source files would look like this:\n\n```c\ndriver-\u003epattern(\"SOURCES\", \"//*.c|*.cpp|*.cxx\");\ndriver-\u003erule(\"objects\", \"$SOURCES\", driver-\u003etarget_map(src_to_obj), compile_src);\ndriver-\u003erule(\"ARTEFACT\", \"$objects\", driver-\u003etarget_pattern(NULL), link_binary);\n```\n\nPatterns create a label for a pattern (using the `ut_expr` syntax). Rules are patterns that have dependencies and actions. The syntax for a rule is:\n\n```c\ndriver-\u003erule(\u003cid\u003e, \u003cdependencies\u003e, \u003cfunction to map target to output\u003e, \u003caction\u003e);\n```\n\nEach plugin must have a `bakemain` entry point. This function is called when the\nplugin is loaded, and must specify the rules and patterns.\n\n## Authors\n\n- Sander Mertens - Initial work\n\n## Legal stuff\n\nBake is licensed under the GPL3.0 license. The bake runtime (all code under the `util` directory) is licensed under the MIT license.\n","funding_links":[],"categories":["C","c"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSanderMertens%2Fbake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSanderMertens%2Fbake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSanderMertens%2Fbake/lists"}