A fast, minimal C build tool inspired by Taskfile & Make. Designed for speed, clarity, and cross-platform simplicity.
- ⚡ Lightning-fast incremental builds with dependancy tracking
- 🧠 Smart recompilation detection with reasoning
- 🔨 C compiler integration with support for custom flags
- 📦 Static library archiving
- 🔗 Application linking
- ✅ Clear verbose output option
- 🧩 Simple CLI
- 🧰 Cross-platform: Linux, (macOS, Windows not tested yet)
Install with Go:
go install github.com/ameergituser/craftc@latestOr clone and build manually:
git clone https://github.com/ameergituser/craftc
cd craftc
go build .The examples below use the verbose flag to print output to the console.
Use the obj command:
craftc obj -cc cc -cfile ./libsrc1.c -cflags "-Wall -O2" -objdir ./build/obj -vOutput:
[build] 🧠 build/obj/libsrc1.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -O2 -MMD -MF build/obj/libsrc.libsrc1.c.d -c ./libsrc1.c -o build/obj/libsrc1.c.oRe-run:
✅ build/obj/libsrc1.c.o is up to date.Use the objs command:
craftc objs -cc cc -cfiles "./libsrc1.c ./libsrc2.c" -cflags "-Wall" -objdir ./build/obj -vOutput:
[build] 🧠 build/obj/libsrc2.c.o: object file does not exist.
[build] 🧠 build/obj/libsrc1.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -MMD -MF build/obj/libsrc2.c.d -c ./libsrc2.c -o build/obj/libsrc2.c.o
[compile] 🔨 /usr/bin/cc -Wall -MMD -MF build/obj/libsrc1.c.d -c ./libsrc1.c -o build/obj/libsrc1.c.oUse the static-lib command:
craftc static-lib -cc cc -cfiles "./libsrc1.c ./libsrc2.c" -cflags "-Wall -O2" -lib-path "./build/lib.a" -objdir ./build/obj -vOutput:
[build] 🧠 build/obj/libsrc2.c.o: object file does not exist.
[build] 🧠 build/obj/libsrc1.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -O2 -MMD -MF build/obj/libsrc2.c.d -c ./libsrc2.c -o build/obj/libsrc2.c.o
[compile] 🔨 /usr/bin/cc -Wall -O2 -MMD -MF build/obj/libsrc1.c.d -c ./libsrc1.c -o build/obj/libsrc1.c.o
[archive] 📦 /usr/bin/ar rcs ./build/lib.a build/obj/libsrc1.c.o build/obj/libsrc2.c.oRe-run:
✅ build/obj/libsrc2.c.o is up to date.
✅ build/obj/libsrc1.c.o is up to date.
✅ 📦 ./build/lib.a is up to date.We also statically link against a library.
Use the exe command:
craftc exe -cc cc -cfiles "main.c" -objdir ./build/obj -cflags "-Wall -O2 -I ./libsrc" -lib-paths "./build/lib.a" -exe-path ./appOutput:
[build] 🧠 build/obj/main.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -O2 -I ./libsrc -MMD -MF build/obj/main.c.d -c ./main.c -o build/obj/main.c.o
[linking] 🔗 /usr/bin/cc build/obj/main.c.o ./build/lib.a -o ./build/appRe-run:
✅ build/obj/main.c.o is up to date.
✅ 🚀 ./build/app is up to date.Craftc's commands are designed to be composable. This makes it simple and easy to understand and integrate into other tools such as Task.
The example below utlises Task to build an executable, and also build the dependancy library is required.
Example:
version: '3'
tasks:
lib:
desc: Build a static library with a few source files
vars:
BUILD_DIR: ./build/{{.TASK}}
OBJ_DIR: '{{.BUILD_DIR}}/obj'
SRC: ./libsrc/libsrc1.c ./libsrc/libsrc2.c
STATIC_LIB: '{{.BUILD_DIR}}/{{.TASK}}.a'
CFLAGS: -Wall -O2
cmds:
- ./craftc static-lib -cc cc -cfiles "{{.SRC}}" -objdir {{.OBJ_DIR}} -cflags "{{.CFLAGS}}" -lib-path "{{.STATIC_LIB}}" -i {{.CLI_ARGS}}
exe:
desc: Build an exe cmd with a few source files
vars:
BUILD_DIR: ./build/{{.TASK}}
OBJ_DIR: '{{.BUILD_DIR}}/obj'
SRC: ./appsrc/main.c
STATIC_LIB: ./build/lib/lib.a
CFLAGS: -Wall -O2 -I ./libsrc
# LDFLAGS: -Wl,--trace
APP_PATH: '{{.BUILD_DIR}}/{{.TASK}}-app'
deps:
- task: lib
cmds:
- >
./craftc exe
-cc cc
-cfiles "{{.SRC}}"
-objdir {{.OBJ_DIR}}
-cflags "{{.CFLAGS}}"
-ldflags "{{.LDFLAGS}}"
-exe-path {{.APP_PATH}}
-lib-paths "{{.STATIC_LIB}}"
-i {{.CLI_ARGS}}Output:
[build] 🧠 build/lib/obj/libsrc.libsrc2.c.o: object file does not exist.
[build] 🧠 build/lib/obj/libsrc.libsrc1.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -O2 -MMD -MF build/lib/obj/libsrc.libsrc1.c.d -c ./libsrc/libsrc1.c -o build/lib/obj/libsrc.libsrc1.c.o
[compile] 🔨 /usr/bin/cc -Wall -O2 -MMD -MF build/test4/obj/libsrc.libsrc2.c.d -c ./libsrc/libsrc2.c -o build/lib/obj/libsrc.libsrc2.c.o
[archive] 📦 /usr/bin/ar rcs ./build/lib/lib.a build/lib/obj/libsrc.libsrc1.c.o build/lib/obj/libsrc.libsrc2.c.o
[build] 🧠 build/exe/obj/appsrc.main.c.o: object file does not exist.
[compile] 🔨 /usr/bin/cc -Wall -O2 -I ./libsrc -MMD -MF build/exe/obj/appsrc.main.c.d -c ./appsrc/main.c -o build/exe/obj/appsrc.main.c.o
[linking] 🔗 /usr/bin/cc build/exe/obj/appsrc.main.c.o ./build/lib/lib.a -o ./build/exe/appRe-run:
✅ build/lib/obj/libsrc.libsrc2.c.o is up to date.
✅ build/lib/obj/libsrc.libsrc1.c.o is up to date.
✅ 📦 ./build/lib/lib.a is up to date.
✅ build/exe/obj/appsrc.main.c.o is up to date.
✅ 🚀 ./build/exe/app is up to date.