Appearance
[中文版本](/posts/c教程/zh-CN/10-真实项目/099-Packaging, Versioning, and Documentation)
You’ve written real C programs—now it’s time to package, version, and document them like a professional. This is what makes your code usable by others and maintainable by your future self.
Step 1. The goal of packaging
Packaging is about making your project easy to:
- build (
make,cmake, ormeson) - install (
make install) - link (
pkg-config) - use (
#include "yourlib.h")
You’ll create a structure that helps others build and use your code without guessing.
Step 2. Standard project layout
A simple, conventional layout for a C project:
myproject/
├── include/
│ └── myproject.h
├── src/
│ ├── main.c
│ └── util.c
├── tests/
│ └── test_basic.c
├── Makefile
├── README.md
└── LICENSEinclude/holds headers that others can includesrc/holds your implementation filestests/holds unit testsMakefiledefines how to build and install
Step 3. Tiny Code: a simple reusable library
// include/myproject.h
#ifndef MYPROJECT_H
#define MYPROJECT_H
int add(int a, int b);
int sub(int a, int b);
#endif// src/myproject.c
#include "myproject.h"
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }Step 4. Minimal Makefile
CC = gcc
CFLAGS = -std=c23 -O2 -Wall -Iinclude
LDFLAGS =
SRC = $(wildcard src/*.c)
OBJ = $(SRC:.c=.o)
LIB = libmyproject.a
.PHONY: all clean install uninstall
all: $(LIB)
$(LIB): $(OBJ)
ar rcs $@ $^
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
install:
mkdir -p /usr/local/include/myproject
cp include/*.h /usr/local/include/myproject/
cp $(LIB) /usr/local/lib/
uninstall:
rm -f /usr/local/lib/$(LIB)
rm -rf /usr/local/include/myproject
clean:
rm -f $(OBJ) $(LIB)Build the library:
make
sudo make installThen another project can link against it:
gcc main.c -lmyproject -L/usr/local/lib -I/usr/local/include/myprojectStep 5. Versioning your releases
Follow semantic versioning:
vMAJOR.MINOR.PATCHExamples:
v1.0.0– stable releasev1.1.0– new feature, backward compatiblev1.1.1– bug fix, no API changev2.0.0– breaking API change
Tag your releases in git:
git tag -a v1.0.0 -m "First stable release"
git push origin v1.0.0Step 6. Create a pkg-config file
pkg-config lets others compile your library easily.
Createmyproject.pc:
prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/myproject
Name: myproject
Description: Tiny math helper library
Version: 1.0.0
Libs: -L${libdir} -lmyproject
Cflags: -I${includedir}Install it in/usr/local/lib/pkgconfig/ and test:
pkg-config --cflags --libs myprojectStep 7. Documentation with Markdown and Doxygen
Keep a clear README.md at the root:
# myproject
A tiny example C library for arithmetic functions.
## Buildmake sudo make install
## Usage
```c
#include <myproject.h>
int main() {
printf("%d\n", add(3, 4));
}
For API documentation, use **Doxygen**:
```bash
sudo apt install doxygen
doxygen -gEditDoxyfile to include your source paths, then run:
doxygen DoxyfileDocs will appear inhtml/ orlatex/.
Step 8. Licensing
Add aLICENSE file so others know how they can use your code. Common ones:
- MIT License: simple, permissive
- Apache 2.0: adds patent protection
- GPLv3: ensures derivatives remain open
Example MIT License header for your source files:
/*
* Copyright (c) 2025 Your Name
* Licensed under the MIT License.
*/Step 9. Continuous Integration (optional)
Add GitHub Actions or another CI service:
# .github/workflows/build.yml
name: Build and Test
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- run: make
- run: make test || echo "No tests yet"Now every push builds automatically.
Step 10. Why this matters
Professional packaging is part of being a systems engineer:
- Your projects build reproducibly.
- Others can install, link, and use them easily.
- Documentation and version tags create confidence.
- Licensing clarifies ownership.
You have now moved from C programmer to C maintainer, the person others trust to deliver solid, reusable, and well-documented software.
Next is 100. Practice: Build Your Own Mini Project, where you will bring everything together, writing, building, debugging, and packaging a complete small system in pure C.
