summaryrefslogtreecommitdiff
path: root/docs/handbook/cgit/building.md
blob: 00f9e1244f942e865ea5db1010b3391b9cd7a123 (plain)
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# 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:

```makefile
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:

```makefile
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

```makefile
$(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

```makefile
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

```makefile
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

```makefile
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:

```makefile
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

```bash
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

```bash
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`:

```makefile
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):

```bash
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:

```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 `-include`d 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 |