1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
# mkproj
just a dumb bullshit utility that generates build system boilerplate and gets the fuck out of your way.
like, imagine you want to start a new project. maybe it's something scalable, maybe it's just some stupid scratch program to test an idea. either way, before you've written a single line of the thing you actually want to make, you have to pick a build system, because project management in c is fucking cancer. then you have to go out of your way to write a `Makefile`, or a `CMakeLists.txt`, or whatever other configuration file your build system decided it needed, instead of just actually writing whatever the fuck it is you wanted to write.
`mkproj` fixes that. it makes a directory (or uses the one you're in, with `mkproj .`), generates the boilerplate for the build system you picked — currently `make`, `cmake`, `meson`, `premake`, and `xmake` — and that's it. you get a project you can immediately build, and you never use `mkproj` again.
by default you get a flat c project built with `make`: the source sits at the root, the binary builds to the root, the object files go under `bin/`, and it uses the newest language standard. there are a couple of things you can customize: whether it initializes a git repository, the language (`c`, `cpp`, `objc`, `nasm`, `swift`, or `crust` — rust through `rustc`, no cargo), the language standard, where your sources live, where your build output goes, and whether you want the object files in their own directory. but most of the time, you shouldn't have to think about any of that.
```sh
$ mkproj hello
```
that's a c project using `make`. `cd hello && make run` and you're off — the generated makefiles have a `run` target that builds and runs the thing.
## usage
```text
$ mkproj --help
mkproj 0.4.0 - dumb project generator
generates boilerplate for make, cmake, meson or premake so you can stop
writing the same fucking build files every time you start a project.
usage: mkproj [-l lang] [-s std] [-b system] [-k kind] [--cc cc] [--license name]
[--git] [--no-root] [--single] [--no-validation] [--docker]
[--style] [--ci] [--src dir] [--bin dir] [--bin-int dir] <name>
mkproj --completions bash|zsh|fish
mkproj [-v | -h]
<name> is the project directory to create, or . to generate into the
current directory (the project name is taken from its basename).
defaults: a flat C project built with make, binary at the project root,
the latest language standard, and objects under bin/.
options:
-l, --lang LANG language: c, cpp, objc, nasm, swift, crust (default c)
-s, --std STD language standard (default: latest for the language)
-b, --build SYSTEM build system: make, cmake, meson, premake, xmake (default make)
-k, --kind KIND exe, lib (static) or shared (default exe)
--cc CC compiler (default clang/clang++); make, premake, xmake
--license NAME add a LICENSE: mit, isc, bsd-2, bsd-3, unlicense
--git initialize a git repository and write a .gitignore
--src DIR put sources in DIR/ instead of at the project root
--no-root put the binary in the build dir, not the project root
--single single-file project: compile directly, no object dir (make, c family)
--no-validation drop the make check target and the sanitizer flags
--docker add a Dockerfile to build in a container (c, cpp, nasm)
--style add .clang-format + .editorconfig from the style guide
--ci add a GitHub Actions workflow that builds the project
--bin DIR build directory (default per build system)
--bin-int DIR put objects in a separate dir (make/premake)
-v, --version print version and bail
-h, --help print this and bail
by hachem <im@hachem.wtf>
```
```sh
$ mkproj hello # C + make, the default
$ mkproj . # generate into the current directory
$ mkproj -l cpp -s c++20 -b cmake app # C++20 + cmake
$ mkproj -l objc -b meson gui # Objective-C + meson
$ mkproj -l crust hello # Rust through rustc, no cargo
$ mkproj -k shared -b cmake libbar # a shared library
$ mkproj --src source tool # sources under source/
$ mkproj -b make --bin-int obj tool # objects in obj/, binary at the root
$ mkproj --git tool # also init a git repo + .gitignore
```
## build
needs a c compiler. nothing else.
```sh
$ sudo make install # -> /usr/local/bin + man page
$ make install PREFIX=~/.local # or somewhere without sudo
```
it really is one file, so if you don't want the makefile:
```sh
$ cc -O2 mkproj.c -o mkproj
```
## completions
`make install` already drops bash, zsh, and fish completions into the standard
directories under `$PREFIX/share`, so a normal `sudo make install` just works.
if you installed somewhere non-standard (e.g. `PREFIX=~/.local`), zsh may need that dir on its `fpath` — add `fpath=(~/.local/share/zsh/site-functions $fpath)` to your `.zshrc` before `compinit`. you can also generate a script by hand anytime:
```sh
$ mkproj --completions bash > /etc/bash_completion.d/mkproj
$ mkproj --completions zsh > ~/.zsh/completions/_mkproj
$ mkproj --completions fish > ~/.config/fish/completions/mkproj.fish
```
## license
`mkproj` is licensed under the mit license. see [license](LICENSE) for more.
|