134 lines
6.1 KiB
Markdown
134 lines
6.1 KiB
Markdown
# 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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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:
|
|
|
|
```bash
|
|
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.<br>
|
|
|
|
<br>**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.<br>
|
|
|
|
<br>**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`.<br>
|
|
|
|
<br>**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).<br>
|
|
|
|
<br>**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.<br>
|
|
|
|
<br>**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`.<br>
|
|
|
|
<br>**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.<br>
|
|
|
|
<br>**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:
|
|
|
|
```text
|
|
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). |