cgit — Building
Prerequisites
| Dependency | Required | Purpose |
|---|---|---|
| GCC or Clang | Yes | C compiler (C99) |
| GNU Make | Yes | Build system |
| OpenSSL (libcrypto) | Yes | SHA-1 hash implementation (SHA1_HEADER = <openssl/sha.h>) |
| zlib | Yes | Git object compression |
| libcurl | No | Not used — NO_CURL=1 is passed by cgit.mk |
| Lua or LuaJIT | No | Lua filter support; auto-detected via pkg-config |
| asciidoc / a2x | No | Man page / HTML / PDF documentation generation |
| Python | No | Git's test harness (for make test) |
Build System Overview
cgit uses a two-stage build that embeds itself within Git's build infrastructure:
cgit/Makefile
└── make -C git -f ../cgit.mk ../cgit
└── git/Makefile (included by cgit.mk)
└── Compile cgit objects + link against libgit.a
Stage 1: Top-Level Makefile
The top-level Makefile lives in cgit/ and defines all user-configurable
variables:
CGIT_VERSION = 0.0.5-1-Project-Tick
CGIT_SCRIPT_NAME = cgit.cgi
CGIT_SCRIPT_PATH = /var/www/htdocs/cgit
CGIT_DATA_PATH = $(CGIT_SCRIPT_PATH)
CGIT_CONFIG = /etc/cgitrc
CACHE_ROOT = /var/cache/cgit
prefix = /usr/local
libdir = $(prefix)/lib
filterdir = $(libdir)/cgit/filters
docdir = $(prefix)/share/doc/cgit
mandir = $(prefix)/share/man
SHA1_HEADER = <openssl/sha.h>
GIT_VER = 2.46.0
GIT_URL = https://www.kernel.org/pub/software/scm/git/git-$(GIT_VER).tar.xz
The main cgit target delegates to:
cgit:
$(QUIET_SUBDIR0)git $(QUIET_SUBDIR1) -f ../cgit.mk ../cgit NO_CURL=1
This enters the git/ subdirectory and runs cgit.mk from there, prefixing
all cgit source paths with ../.
Stage 2: cgit.mk
cgit.mk is run inside the git/ directory so it can include Makefile to
inherit Git's build variables (CC, CFLAGS, linker flags, OS detection via
config.mak.uname, etc.).
Key sections:
Version tracking
$(CGIT_PREFIX)VERSION: force-version
@cd $(CGIT_PREFIX) && '$(SHELL_PATH_SQ)' ./gen-version.sh "$(CGIT_VERSION)"
The gen-version.sh script writes a VERSION file that is included by the
build. Only cgit.o references CGIT_VERSION, so only that object is rebuilt
when the version changes.
CGIT_CFLAGS
CGIT_CFLAGS += -DCGIT_CONFIG='"$(CGIT_CONFIG)"'
CGIT_CFLAGS += -DCGIT_SCRIPT_NAME='"$(CGIT_SCRIPT_NAME)"'
CGIT_CFLAGS += -DCGIT_CACHE_ROOT='"$(CACHE_ROOT)"'
These compile-time constants are used in cgit.c as default values in
prepare_context().
Lua detection
LUA_PKGCONFIG := $(shell for pc in luajit lua lua5.2 lua5.1; do \
$(PKG_CONFIG) --exists $$pc 2>/dev/null && echo $$pc && break; \
done)
If Lua is found, its --cflags and --libs are appended to CGIT_CFLAGS and
CGIT_LIBS. If not found, NO_LUA=YesPlease is set and -DNO_LUA is added.
Linux sendfile
ifeq ($(uname_S),Linux)
HAVE_LINUX_SENDFILE = YesPlease
endif
ifdef HAVE_LINUX_SENDFILE
CGIT_CFLAGS += -DHAVE_LINUX_SENDFILE
endif
This enables the sendfile() syscall in cache.c for zero-copy writes from
cache files to stdout.
Object files
All cgit source files are listed explicitly:
CGIT_OBJ_NAMES += cgit.o cache.o cmd.o configfile.o filter.o html.o
CGIT_OBJ_NAMES += parsing.o scan-tree.o shared.o
CGIT_OBJ_NAMES += ui-atom.o ui-blame.o ui-blob.o ui-clone.o ui-commit.o
CGIT_OBJ_NAMES += ui-diff.o ui-log.o ui-patch.o ui-plain.o ui-refs.o
CGIT_OBJ_NAMES += ui-repolist.o ui-shared.o ui-snapshot.o ui-ssdiff.o
CGIT_OBJ_NAMES += ui-stats.o ui-summary.o ui-tag.o ui-tree.o
The prefixed paths (CGIT_OBJS := $(addprefix $(CGIT_PREFIX),$(CGIT_OBJ_NAMES)))
point back to the cgit/ directory from inside git/.
Quick Build
cd cgit
# Download the vendored Git source (required on first build)
make get-git
# Build cgit binary
make -j$(nproc)
The output is a single binary named cgit in the cgit/ directory.
Build Variables Reference
| Variable | Default | Description |
|---|---|---|
CGIT_VERSION |
0.0.5-1-Project-Tick |
Compiled-in version string |
CGIT_SCRIPT_NAME |
cgit.cgi |
Name of the installed CGI binary |
CGIT_SCRIPT_PATH |
/var/www/htdocs/cgit |
CGI binary install directory |
CGIT_DATA_PATH |
$(CGIT_SCRIPT_PATH) |
Static assets (CSS, JS, images) directory |
CGIT_CONFIG |
/etc/cgitrc |
Default config file path (compiled in) |
CACHE_ROOT |
/var/cache/cgit |
Default cache directory (compiled in) |
prefix |
/usr/local |
Install prefix |
libdir |
$(prefix)/lib |
Library directory |
filterdir |
$(libdir)/cgit/filters |
Filter scripts install directory |
docdir |
$(prefix)/share/doc/cgit |
Documentation directory |
mandir |
$(prefix)/share/man |
Man page directory |
SHA1_HEADER |
<openssl/sha.h> |
SHA-1 implementation header |
GIT_VER |
2.46.0 |
Git version to download and vendor |
GIT_URL |
https://...git-$(GIT_VER).tar.xz |
Git source download URL |
NO_LUA |
(unset) | Set to any value to disable Lua support |
LUA_PKGCONFIG |
(auto-detected) | Explicit pkg-config name for Lua |
NO_C99_FORMAT |
(unset) | Define if your printf lacks %zu, %lld etc. |
HAVE_LINUX_SENDFILE |
(auto on Linux) | Enable sendfile() in cache |
V |
(unset) | Set to 1 for verbose build output |
Overrides can be placed in a cgit.conf file (included by both Makefile and
cgit.mk via -include cgit.conf).
Installation
make install # Install binary and static assets
make install-doc # Install man pages, HTML docs, PDF docs
make install-man # Man pages only
make install-html # HTML docs only
make install-pdf # PDF docs only
Installed files
| Path | Mode | Source |
|---|---|---|
$(CGIT_SCRIPT_PATH)/$(CGIT_SCRIPT_NAME) |
0755 | cgit binary |
$(CGIT_DATA_PATH)/cgit.css |
0644 | Default stylesheet |
$(CGIT_DATA_PATH)/cgit.js |
0644 | Client-side JavaScript |
$(CGIT_DATA_PATH)/cgit.png |
0644 | Default logo |
$(CGIT_DATA_PATH)/favicon.ico |
0644 | Default favicon |
$(CGIT_DATA_PATH)/robots.txt |
0644 | Robots exclusion file |
$(filterdir)/* |
(varies) | Filter scripts from filters/ |
$(mandir)/man5/cgitrc.5 |
0644 | Man page (if install-man) |
Make Targets
| Target | Description |
|---|---|
all |
Build the cgit binary (default) |
cgit |
Explicit build target |
test |
Build everything (all target on git) then run tests/ |
install |
Install binary, CSS, JS, images, filters |
install-doc |
Install man pages + HTML + PDF |
install-man |
Man pages only |
install-html |
HTML docs only |
install-pdf |
PDF docs only |
clean |
Remove cgit objects, VERSION, CGIT-CFLAGS, tags |
cleanall |
clean + make -C git clean |
clean-doc |
Remove generated doc files |
get-git |
Download and extract Git source into git/ |
tags |
Generate ctags for all *.[ch] files |
sparse |
Run sparse static analysis via cgit.mk |
uninstall |
Remove installed binary and assets |
uninstall-doc |
Remove installed documentation |
Documentation Generation
Man pages are generated from cgitrc.5.txt using asciidoc/a2x:
MAN5_TXT = $(wildcard *.5.txt)
DOC_MAN5 = $(patsubst %.txt,%,$(MAN5_TXT))
DOC_HTML = $(patsubst %.txt,%.html,$(MAN_TXT))
DOC_PDF = $(patsubst %.txt,%.pdf,$(MAN_TXT))
%.5 : %.5.txt
a2x -f manpage $<
$(DOC_HTML): %.html : %.txt
$(TXT_TO_HTML) -o $@+ $< && mv $@+ $@
$(DOC_PDF): %.pdf : %.txt
a2x -f pdf cgitrc.5.txt
Cross-Compilation
For cross-compiling (e.g. targeting MinGW on Linux):
make CC=x86_64-w64-mingw32-gcc
The toolchain-mingw32.cmake file in the repository is for CMake-based
projects; cgit itself uses Make exclusively.
Customizing the Build
Create a cgit.conf file alongside the Makefile:
# cgit.conf — local build overrides
CGIT_VERSION = 1.0.0-custom
CGIT_CONFIG = /usr/local/etc/cgitrc
CACHE_ROOT = /tmp/cgit-cache
NO_LUA = 1
This file is -included by both Makefile and cgit.mk, so it applies to
all build stages.
Troubleshooting
| Problem | Solution |
|---|---|
make: *** No rule to make target 'git/Makefile' |
Run make get-git first |
lua.h: No such file or directory |
Install Lua dev package or set NO_LUA=1 |
openssl/sha.h: No such file or directory |
Install libssl-dev / openssl-devel |
sendfile: undefined reference |
Set HAVE_LINUX_SENDFILE= (empty) on non-Linux |
Build fails with redefinition of 'struct cache_slot' |
Git's cache.h conflict — cgit uses CGIT_CACHE_H guard |
dlsym: symbol not found: write |
Lua filter's write() interposition requires -ldl (auto on Linux) |
Version shows as unknown |
Run ./gen-version.sh "$(CGIT_VERSION)" or check VERSION file |