make building C as simple as pie

Mekpie is an opinionated build system for small scale C projects. The core premise of Mekpie is that you should not be spending time worrying about Make files, compiler arguments, or build times, when working on a small C project. By enforcing a simple directory structure and always providing a clean build, Mekpie saves you time and effort. For added convenience Mekpie takes notes from tools like Rust's cargo and Node's npm and provides options for building, running, cleaning, and testing your current project.

Mekpie is a small-scale project and is not supposed to replace tools like CMake or provide any sort of package management capabilities. Use Mekpie when the alternative is a shoddy Make file or manually compiling.

Currently Mekpie supports the gcc, clang, avr-gcc, and emscripten compilers, as well as allows users to write custom compiler configurations.


Mekpie is a python package. Use pip to install it!

$ pip install mekpie

Getting Started

Create a new project by running mekpie new. Mekpie will walk you through the configuration.

$ mekpie new "project-name"
┌ Configuring mekpie...
│ Please provide a name for your project (default project-name):
│ Selected project-name.
│ Mekpie supports the following c compilers, please select one (compilers must be installed separately):
│     - gcc_clang   for use with the gcc or clang compiler
│     - emscripten  for use with the emscripten c to js compiler
│     - avr_gcc     for use with avr-gcc and avrdude
│ Please select a cc (default gcc_clang):
│ Selected gcc_clang.
│ ┌ Configuring gcc_clang...
│ │ Please select a compiler command (default cc):
│ │ Selected cc.
│ │ Please select a debug command (default lldb):
│ │ Selected lldb.
│ └ gcc_clang configured!
└ mekpie configured!
project-name created successfully!

Then navigate to the project directory and run

$ mekpie run
Project successfully cleaned.
Project successfully built. (0.060s)
Hello, World!

That's it!


Mekpie is built for the IDE free lifestyle. These days I do most of my development in VSCode regardless of language. As a consequence, I am often writing small scripts to build my projects. Mekpie evolved from a python script I used in place of a Make file for my c projects. Rather than continuing to rewrite the script for every new project I decided to package this functionality together. Mekpie emphasizes simplicity and correctness over performance. Unlike most c build tools, which focus a great deal of effort on partial compilation, Mekpie recompiles the entire project from scratch every time you build, run, or test. This means that code is always fresh, and you will never have to run mekpie clean (though you still can if you want to remove the executables). For small programs the overhead of starting up python will be comparatively slower than the actual compilation times, so I believe this approach is a suitable one for many projects.

Creating a Project

Mekpie provides two commands for creating a project. mekpie new will attempt to create a new project as a subdirectory of your current location. You will have to provide Mekpie a name for your project. This name will be used as the name for the directory as well as the main .c file (don't worry you can change that later).

Alternatively, you can use the mekpie init command to create a new project. In this case Mekpie will use the name of the current directory as the project name and setup the project in your current location.

Project Structure

When you create a project using either new or init the following directory structure will be generated.


The first folder generated by Mekpie, target/, is used to store the debug and release binaries generated for your program.

The includes/ folder is automatically included as an includes directory to your compiler, so you can place any header files you want included in this directory. You can also place subdirectories within includes/.

The src/ folder should contain all your .c files. Like includes/ you can use subdirectories within. By default, a main file will be generated by Mekpie with a simple Hello World program to help you ensure everything is working correctly.

The tests/ folder should contain all your test files. Jump here to find out more about tests.

Mekpie automatically generates a .gitignore, or appends to one that already exists. The final file created by Mekpie is mek.py which is a small python file that allows you to configure Mekpie.


Configuration of Mekpie is done through the python file mek.py in the root of your project directory. Mekpie will autogenerate a file like the following when you first create a project. Release and debug flags are also automatically generated based on the selected compiler configuration.

# This is a standard configuration file for mekpie

name = 'project-name' 
main = 'project-name.c'
cc = gcc_clang(cmd='cc', dbg='lldb')
libs = []
flags = []

if options.release:
    flags += ['-Wall', '-O']
    flags += ['-Wall', '-g']

As shown at the bottom of the configuration file, the command line options for the current build command will be provided to your configuration anytime it is read. This allows you to easily change your configuration depending on the build. In addition to release, the options object also provides options.quiet, options.developer, and options.mode which correspond to their respective command line flags.

The following table describes each mek.py variable in detail.

name<projectname>This is a default identifier for your project.
main<projectname>.cThis should be the entry point for your main program. By default, it will point at the c file auto-generated by Mekpie.
ccgcc_clang(...)The c compiler configuration. Currently supported compilers include gcc_clang, avr_gcc, and emscripten. See Compiler Configurations for more details.
libs[]Add any libraries you want linked with your project here. For instance, if you wanted to include the c math library you would change libs to ['m'].
flags[]These flags will be passed to the compiler whenever a file is compiled. For instance, to always produce verbose output from the compiler, flags could be changed to [-v].
compileflags[]These flags will only be passed to the compiler whenever an object is compiled.
linkflags[]These flags will only be passed to the compiler whenever a file is linked.

Compiler Configuration

Mekpie provides three compiler configurations by default, gcc_clang, gcc_avr, and emscripten. The easiest way to get started with these is to use the configuration helper when running mekpie new or mekpie init and then selecting your desired compiler configuration, however these can be changed at any point.


This compiler configuration is designed for use with the gcc compiler, clang compiler, and MinGW compiler. Insert the following code into mek.py to use this configuration

cc = gcc_clang(
    cmd = 'cc',  # This shell command for your compiler
    dbg = 'gdb', # This shell command for your debugger


This compiler configuration is designed for use with the AVR gcc compiler and avrdude. It will automatically compiler your code, convert it to hex format, and upload it via a serial port on your computer to a desired piece of hardware. This compiler configuration expects avr-gcc and avrdude to be available from the command line. Insert the following code into mek.py to use this configuration

cc = avr_gcc(
    hardware   = 'atmega2560', # Your AVR hardware
    programmer = 'wiring',     # The programmer to use with avrdude
    baud       = '115200',     # The upload baud rate (default 115200)


This compiler configuration is designed for use with the Emscripten c to js compiler. It expects emcc and node to be available from the command line. Insert the following code into mek.py to use this configuration

cc = emscripten()

Custom Configuration

There is currently limited support for providing your own compiler configuration. This is done by implementing the CompilerConfig interface. For example

cc = CompilerConfig(
    name    = 'my_compiler_config', # The name of the config
    compile = my_compiler_function, # Your compile function
    link    = my_link_function,     # Your linking function
    run     = my_run_function,      # Your running function
    debug   = my_debug_function,    # Your debug function
    once    = my_once_function,     # Your once function

Each function is passed the relevant variables to complete its expected task. As this feature is still in early development full documentation is not provided. See /mekpie/cc_gcc_clang.py for an example implementation.


Typically, you will skip running mekpie build when running your program, as building happens automatically for mekpie run, mekpie debug, and mekpie test. mekpie run will build and then execute the main file specified by your project configuration. You can specify a release build using --release or -r. You can provide program arguments to your main program by separating arguments to mekpie with --. Everything after this symbol will be passed to your program, rather than Mekpie. For example

$ mekpie --release run -- ./some-path --flag 42

Use mekpie debug if you want to start your program in your configured debugger. The usage of mekpie test is broken down in the next section.


Mekpie provides simple facilities for testing your code. Add a test by placing a .c file, with a main function, in tests/. For example, if you created a test file like the following and placed it in a file named project-tests.c

void main() {

void test_one() {
    assert ...

You could run those tests with either of the following commands

$ mekpie test
$ mekpie test project-tests

You can provide any number of test names to the test command. All of these tests will be run. Alternatively, providing no test names will simply run all of the tests. Test files are compiled just like your program's main file, meaning they have access to all of your project's header files.


Note that in usage examples flags are provided before the command, however flags are not required to appear before a command unless that command takes an arbitrary number of arguments, such as mekpie test which accepts any number of test names.


Creates a new project in a subdirectory of the provided name. The command will fail if the subdirectory already exists. If you want to initialize Mekpie in an already created directory us mekpie init instead.

This command will create all of the necessary files to use mekpie run to build and run a simple Hello World program in c.


$ mekpie [--changedir|--developer] new <project-name>


Behaves just like mekpie new accept initializes the project in the current directory. The current directory's name will be used as the project name.


$ mekpie [--changedir|--developer] init


When no test names are provided this command will run all files contained in tests/. If test names are provided only those test files whose names are included will be run. Any number of test names can be provided.


$ mekpie [--release|--quiet|--changedir|--developer] test [test-names...]


Removes all existing executables from target/.


$ mekpie [--changedir|--developer] clean


Attempts to create an executable in target/.


$ mekpie [--release|--quiet|--changedir|--developer|--mode] build


Cleans, builds, and then runs the main file of the project. The main file of a project is specified in the project configuration.


$ mekpie [--release|--quiet|--changedir|--developer|--mode] run


Cleans, builds, and then runs the debugger on the main file of the project.


$ mekpie [--quiet|--changedir|--developer|--mode] debug


Cleans, builds, and then copies an executable into the project root. The executable will be given the same name as the project.


$ mekpie [--release|--quite|--changdir|--developer|--mode] dist


The following table describes Mekpie's command line options.

help-hDisplays a command line usage help message.
version-VPrints version info and exits.
mode-mProvide a mode to the mekpie file.
quiet-qThis will suppress information from being printed to stdout.
release-rWhen applicable the build will be done with the release configuration. By default, builds are done with the debug configuration.
developer-dRuns Mekpie in developer mode. This produces additional logging and stack traces on errors.
changedir-cRuns Mekpie command as if it had been invoked from the provided directory. Provide a path immediately after this flag.


Feel free to send be bug reports or feature requests. If you are interested in my other work, checkout my website.

Email [email protected]