Files
makemake/README.md
2026-08-29 04:17:12 +02:00

6.1 KiB

makemake

This repository contains a makefile for C projects. It is configured out-of-the-box for C17 using GCC, enforces extremely strict compilation standards (treating all warnings as errors), manages out-of-source builds, and includes automatic dependency tracking and versioning.

Setup Tutorial

Follow these steps to bootstrap your project from scratch using this Makefile:

1. Initialize the Project

Place the Makefile in the root of your new (and empty) project directory. Note that the output executable will be named after your root directory. Run the following command to scaffold the required directory structure:

make init

What this does: Creates the config/, includes/, output/, and source_code/ directories. It also generates a starter main.c and initializes the versioning and file list configuration files.

2. Write Your Code

  • Place all your .c files inside the source_code/ directory (or subdirectories within it).
  • Place all your .h files inside the includes/ directory.

3. Synchronize the Build System

Whenever you add, rename, or delete a .c or .h file, you must tell the Makefile to update its tracking lists:

make synch

What this does: Scans your directories and updates config/source_code_list and config/header_list.

4. Build the Project

Compile your code for the first time in debug mode:

make debug

Your compiled executable will be located in the output/ directory, named <your_folder_name>_00.000.00.0000 (or whatever the current version string is).


Make Targets Overview

Here is a detailed breakdown of every command available in this Makefile, what it does, and when to use it.

Target Description & Use Case
make / make help Behavior: Prints a help message with available commands.


When to use: When you need a quick reminder of the available targets. | | make init | Behavior: Scaffolds the project directories (source_code, includes, config, output) and creates base tracker files.


When to use: Only once, at the very beginning of a new project. | | make synch | Behavior: Searches the project for .c and .h files and writes their paths to config/source_code_list and config/header_list.


When to use: Every time you create a new file, delete a file, or rename a file. (You do not need to run this if you only edited the contents of an existing file). | | make debug | Behavior: Compiles the project incrementally using DEBUG_FLAGS (-g3, -O0, Undefined Behavior Sanitizer).


When to use: During active development. This build includes debug symbols for gdb, disables optimization for accurate stepping, and catches undefined behavior at runtime. | | make fast | Behavior: Compiles the project incrementally using RELEASE_FLAGS (-O2, NDEBUG) without bumping the project version.


When to use: When you want to test the performance of the optimized build locally, but you aren't ready to officially "release" a new version yet. | | make release | Behavior: Bumps the project version using a date/time stamp (Format: _YY.DAY.HH.MMSS), saves it to config/version, and compiles the project using RELEASE_FLAGS.


When to use: When your code is tested, stable, and ready to be packaged or deployed. | | make clean | Behavior: Deletes the output/ directory, removing all compiled object files (.o), dependency files (.d), and executables.


When to use: When you want a completely fresh build, or if you change compiler flags in the Makefile and need to force a full recompilation. |


Project Structure

After running make init and building, your project will look like this:

my_project/                 # Root folder (dictates the executable name)
├── Makefile                # The build script
├── config/                 # Build tracking files (auto-generated)
│   ├── header_list
│   ├── source_code_list
│   └── version
├── includes/               # Place all your .h files here
├── source_code/            # Place all your .c files here
│   └── main.c
└── output/                 # Build artifacts (ignored by git ideally)
    ├── obj_debug/          # .o and .d files for debug builds
    ├── obj_release/        # .o and .d files for release builds
    └── my_project_version  # The final compiled executables


Configuration & Defaults

This Makefile is heavily configured for safety and strictness. Here is how to modify the defaults to suit your needs:

1. Changing the C Standard

The project defaults to C17. To change this to C11, C99, or C2x:

  • Open the Makefile.
  • Locate the CFLAGS = -std=c17 \ line.
  • Change -std=c17 to -std=c11 (or your preferred standard).

2. Changing the Compiler

The default compiler is GCC. To use Clang (which is highly recommended for macOS users or for its excellent static analyzer):

  • Locate CC = gcc at the top of the file.
  • Change it to CC = clang.

3. Modifying Warning Strictness (Fixing Compilation Blocks)

By default, this Makefile includes -Werror, which treats all warnings as errors and halts compilation. It also includes an extensive list of strict warnings (like -Wconversion, -Wshadow, -Wpadded, etc.).

  • To allow warnings to pass without failing the build: Remove the -Werror \ line from the CFLAGS block.
  • To remove specific strict checks: Simply delete or comment out the specific flag (e.g., -Wmissing-prototypes \) from the CFLAGS list.

4. Modifying Debug and Release Flags

You can tweak optimization levels and sanitizers at the top of the file:

  • Debug (DEBUG_FLAGS): Defaults to -g3 -O0 -fsanitize=undefined -fno-omit-frame-pointer. You can add Address Sanitizer by appending -fsanitize=address.
  • Release (RELEASE_FLAGS): Defaults to -O2 -D NDEBUG. (NDEBUG strips out assert() calls). If you want maximum optimization, you can change -O2 to -O3 or -Ofast (use -Ofast with caution as it breaks strict IEEE compliance for math).