-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMakefile
362 lines (293 loc) · 11.1 KB
/
Makefile
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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# This Makefile works in GNU Make, bmake, and OpenBSD Make ("omake")
# It contains helptext which can be parsed by "mmake": https://github.com/tj/mmake
# built binary names
MOAC_BIN = moac
MOAC_PWGEN_BIN = moac-pwgen
BINS = $(MOAC_BIN) $(MOAC_PWGEN_BIN)
# source files
GOFILES != go list -f '{{range .GoFiles}}{{ $$.Dir }}/{{ . }} {{end}}{{range .TestGoFiles}}{{ $$.Dir }}/{{ . }} {{end}}' ./...
SHARED_SRC = Makefile *.go entropy/*.go internal/*/*.go charsets/*.go
MOAC_SRC = cmd/moac/*.go
MOAC_PWGEN_SRC = pwgen/*.go cmd/moac-pwgen/*.go
SRC = Makefile $(GOFILES)
SH_SRC = .builds/*.sh
COVERPKG = ./...
# go env
CGO_ENABLED ?= 0
GOPATH != go env GOPATH
GOBIN ?= $(GOPATH)/bin
GOOS != go env GOOS
GOARCH != go env GOARCH
# binary paths
GOLANGCI_LINT = $(GOBIN)/golangci-lint
GOKART = $(GOBIN)/gokart
CHECKMAKE = $(GOBIN)/checkmake
CONSISTENT = $(GOBIN)/go-consistent
NANCY = $(GOBIN)/nancy
GOFUMPT = $(GOBIN)/gofumpt
FIELDALIGNMENT = $(GOBIN)/fieldalignment
SHFMT = $(GOBIN)/shfmt
ARCHLINT = $(GOBIN)/go-arch-lint
# change this on freebsd/openbsd
SHA256 = sha256sum
# version identifier to embed in binaries
TAG != git describe --abbrev=0 --tags
REVISION != git rev-parse --short HEAD
VERSION = $(TAG)-$(REVISION)
# install destinations
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
DATAROOTDIR ?= $(PREFIX)/share
MANDIR ?= $(DATAROOTDIR)/man
ZSHCOMPDIR ?= $(DATAROOTDIR)/zsh/site-functions
# general build flags
# extldflags is ignored unless you use one of the cgo options at the bottom
DEFAULT_GO_LDFLAGS = -w -X git.sr.ht/~seirdy/moac/v2/internal/cli.version="$(VERSION)"
GO_LDFLAGS ?= $(DEFAULT_GO_LDFLAGS) -linkmode=internal
BUILDMODE = default
GO_BUILDFLAGS += -trimpath -mod=readonly -buildmode=$(BUILDMODE) -ldflags '$(GO_LDFLAGS)'
# used internally
CMD = build
default: build
.PHONY: default
all: build doc
.PHONY: all
vendor/modules.txt:
go mod vendor
vendor: vendor/modules.txt
.PHONY: vendor
golangci-lint: $(SRC)
$(GOLANGCI_LINT) run
gokart-lint: $(SRC)
$(GOKART) scan -g ./...
go-consistent: $(SRC)
$(CONSISTENT) -pedantic ./...
checkmake: Makefile
$(CHECKMAKE) Makefile
shfmt-lint: $(SH_SRC)
$(SHFMT) -p -s -d $(SH_SRC)
nancy: $(SRC)
go list -json -mod=readonly -m all | $(NANCY) sleuth --skip-update-check --loud
archlint: vendor $(SRC)
$(ARCHLINT) check
.PHONY: golangci-lint gokart-lint go-consistent checkmake shfmt-lint nancy archlint
# run all the project's linters
#
# see .builds/install-linters.sh for more info
lint: shfmt-lint go-consistent checkmake gokart-lint golangci-lint nancy archlint
.PHONY: lint
.fmt-go: $(GOFILES)
$(FIELDALIGNMENT) -fix ./...
$(GOFUMPT) -s -w .
.PHONY: .fmt-go
.fmt-sh: $(SH_SRC)
$(SHFMT) -p -s -w -bn $(SH_SRC)
.PHONY: .fmt-sh
# Format all go/shell files
#
# see .builds/install-linters.sh for more info
fmt: .fmt-go .fmt-sh
.PHONY: fmt
#- every task in this makefile except "clean" just calls .base with different vars
#- instead of invoking "go" directly
.PHONY: .base
.base: $(SRC)
go $(CMD) $(GO_BUILDFLAGS) $(ARGS)
$(MOAC_BIN): $(SHARED_SRC) $(MOAC_SRC)
@$(MAKE) GO_BUILDFLAGS="$(GO_BUILDFLAGS) -o $(MOAC_BIN)" CMD=build ARGS=./cmd/moac .base
$(MOAC_PWGEN_BIN): $(SHARED_SRC) $(MOAC_PWGEN_SRC)
@$(MAKE) GO_BUILDFLAGS="$(GO_BUILDFLAGS) -o $(MOAC_PWGEN_BIN)" CMD=build ARGS=./cmd/moac-pwgen .base
# Build the CLI programs in cmd/
build: $(BINS)
.PHONY: build
.clean-bins:
rm -f $(BINS)
.PHONY: .clean-bins
.clean-caches:
@go clean -testcache ./...
.PHONY: .clean-caches
.clean-artifacts:
rm -rf doc/*.1 ./coverage.out *.prof *.test $(DIST)
.PHONY: .clean-artifacts
# Remove all artifacts generated by this Makefile
clean: clean-san-bins .clean-bins .clean-caches .clean-artifacts
.PHONY: clean
# Run standard unit tests
test:
@$(MAKE) CMD="test" GO_BUILDFLAGS="$(GO_BUILDFLAGS)" ARGS="$(TESTFLAGS) ./..." .base
.PHONY: test
# Run faster tests with fewer repetitions
test-quick:
@LOOPS=10 $(MAKE) test
.PHONY: test-quick
coverage.out: $(SRC)
@$(MAKE) TESTFLAGS="$(TESTFLAGS) -coverpkg=$(COVERPKG) -coverprofile=coverage.out" test
@echo "Write coverage data to coverage.out"
# Collect and view test coverage
test-cov: coverage.out
@go tool cover -func=coverage.out
.PHONY: test-cov
cpu.prof: $(SRC)
@$(MAKE) CMD="test" GO_BUILDFLAGS="$(GO_BUILDFLAGS)" ARGS="-cpuprofile=cpu.prof ./pwgen" .base
# Save a cpu profile to analyze
test-prof: cpu.prof
.PHONY: test-prof
# Profile a long/slow test with many loops
test-prof-long:
@LOOPS=512 $(MAKE) test-prof
.PHONY: test-prof
# Run all pre-commit checks
pre-commit: fmt lint test-quick
.PHONY: pre-commit
doc/moac.1: doc/moac.1.scd
scdoc < doc/moac.1.scd > doc/moac.1
doc/moac-pwgen.1: doc/moac-pwgen.1.scd
scdoc < doc/moac-pwgen.1.scd > doc/moac-pwgen.1
# Build manpages
doc: doc/moac.1 doc/moac-pwgen.1
.PHONY: doc
# final install jobs include these two targets
INSTALL_SHARE = install-man install-completion
INSTALL_ALL = install-bin $(INSTALL_SHARE) # just to make packaging easier
install-bin: build
mkdir -p $(DESTDIR)$(BINDIR)
cp -f $(BINS) $(DESTDIR)$(BINDIR)
chmod 755 $(DESTDIR)$(BINDIR)/$(MOAC_BIN) $(DESTDIR)$(BINDIR)/$(MOAC_PWGEN_BIN)
install-bin-strip:
@$(MAKE) GO_LDFLAGS='$(GO_LDFLAGS) -s' install-bin
install-man: doc
mkdir -p $(DESTDIR)$(MANDIR)/man1
cp -f doc/*.1 $(DESTDIR)$(MANDIR)/man1
chmod 644 $(DESTDIR)$(MANDIR)/man1/moac.1 $(DESTDIR)$(MANDIR)/man1/moac-pwgen.1
install-completion:
mkdir -p $(DESTDIR)$(ZSHCOMPDIR)
cp -f completions/zsh/_* $(DESTDIR)$(ZSHCOMPDIR)
chmod 644 $(DESTDIR)$(ZSHCOMPDIR)/_moac $(DESTDIR)$(ZSHCOMPDIR)/_moac-pwgen
.PHONY: install-bin install-bin-strip install-man install-completion
# Install the project
install: $(INSTALL_ALL)
.PHONY: install
# Install the project with stripped binaries
install-strip: install-bin-strip $(INSTALL_SHARE)
.PHONY: install-strip
# Uninstall the project
uninstall:
rm -f \
$(DESTDIR)$(BINDIR)/$(MOAC_BIN) $(DESTDIR)$(BINDIR)/$(MOAC_PWGEN_BIN) \
$(DESTDIR)$(MANDIR)/man1/moac.1 $(DESTDIR)$(MANDIR)/man1/moac-pwgen.1 \
$(DESTDIR)$(ZSHCOMPDIR)/_moac $(DESTDIR)$(ZSHCOMPDIR)/_moac-pwgen
.PHONY: uninstall
# =================================================================================
# Build tarballs containing reproducible builds
PLATFORM_ID = $(GOOS)-$(GOARCH)
RELNAME = moac-$(VERSION)-$(PLATFORM_ID)
# allow excluding the git version from the archive name
# this lets the archive name be deterministic, which is useful in CI
# because sourcehut artifact names are interpreted literally.
ARCHIVE_PREFIX = moac-$(VERSION) # override ARCHIVE_PREFIX in CI
ARCHIVE_NAME = $(ARCHIVE_PREFIX)-$(PLATFORM_ID)
DIST = dist
DIST_LOCATION = $(DIST)/$(RELNAME)
# Build a tarball for distribution
dist:
@DESTDIR=$(DIST)/$(RELNAME) $(MAKE) install-strip
@$(SHA256) $(DIST)/$(RELNAME)/$(BINDIR)/*
@tar czf "$(DIST)/$(ARCHIVE_NAME).tar.gz" -C $(DIST)/ $(RELNAME)
@rm -rf $(DIST)/$(RELNAME)
.PHONY: dist
# Same as "dist" but with reproducible binaries
dist-reprod:
@$(MAKE) GO_LDFLAGS='-buildid= $(GO_LDFLAGS)' .clean-bins dist
.PHONY: dist-reprod
# Build reproducible tarballs for multiple arches
dist-multiarch:
@$(MAKE) GOARCH=amd64 dist-reprod
@$(MAKE) GOARCH=arm64 dist-reprod
@$(MAKE) GOARCH=arm dist-reprod
@$(MAKE) GOARCH=386 dist-reprod
.PHONY: dist-multiarch
# Run dist-multiarch for Linux + FreeBSD
#
# This does not include OpenBSD because OpenBSD builds should use libc
# for syscalls, and that means building with OpenBSD's libc.
dist-full:
@$(MAKE) GOOS=linux dist-multiarch
@$(MAKE) GOOS=freebsd dist-multiarch
.PHONY: dist-full
# =================================================================================
# everything below this line requires CGO + Clang. Building with CGO allows a few
# extra goodies:
# - static-pie binaries (note that go puts the heap at a fixed address
# anyway and this isn't useful without CGO, but some platforms enforce PIE-ness)
# - msan and race detection (msan requires clang)
# - support for platforms that require CGO like OpenBSD
# moac doesn't really need CGO outside platforms like OpenBSD but this Makefile is
# just a template that I use for all my Go projects.
# if building with CGO, turn on some hardening
CC ?= clang
CCLD ?= clang++
NON_OPENBSD_FLAGS = -fstack-clash-protection
shared_flags = -O2 -fno-semantic-interposition -g -pipe -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fexceptions -fstack-protector-all -m64 -fasynchronous-unwind-tables $(NON_OPENBSD_FLAGS) -fcf-protection=full -ffunction-sections -fdata-sections -flto=thin
SANFLAGS = ''
CFLAGS += $(shared_flags) -ftrivial-auto-var-init=zero -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang
LDFLAGS += $(shared_flags) -Wl,-z,relro,-z,now,-z,noexecstack,--as-needed,-E,--gc-sections
GO_LDFLAGS_CGO = $(DEFAULT_GO_LDFLAGS) -linkmode=external -extldflags \\\"$(LDFLAGS)\\\"
# on openbsd, set this to "exe" or nothing
BUILDMODE_CGO = pie
# on ARMv8, you can switch safe-stack to shadow-call-stack
# on Alpine, set this to cfi since compiler-rt isn't built properly.
# openbsd doesn't support either
EXTRA_SANITIZERS ?= cfi,bounds
CFI = -fsanitize=$(EXTRA_SANITIZERS)
CFLAGS_CFI = $(CFLAGS) $(CFI) -fvisibility=hidden -fpic -fpie
LDFLAGS_CFI = $(LDFLAGS) $(CFI) -pie
CGO_CFLAGS != go env CGO_CFLAGS
CGO_CFLAGS += $(CFLAGS)
#- shared across regular, msan, and race CGO builds/tests
.build-cgo-base:
@GO_LDFLAGS="$(GO_LDFLAGS_CGO)" CC="$(CC)" CCLD="$(CCLD)" CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" CGO_CFLAGS="$(CFLAGS)" $(MAKE) CGO_ENABLED=1 $(CMD)
.PHONY: .build-cgo-base
# Build bins with CGO (ideal for OpenBSD)
#
# This is ideal for systems like OpenBSD that require CGO; MOAC does
# not otherwise have any C deps.
build-cgo:
@$(MAKE) BUILDMODE=$(BUILDMODE_CGO) CFLAGS="$(CFLAGS_CFI)" LDFLAGS="$(LDFLAGS_CFI)" .build-cgo-base
.PHONY: build-cgo
# Build static-pie CGO binaries
#
# This should be done with a musl toolchain, as glibc isn't optimized
# for static linking and tends to cause crashes.
build-cgo-static:
@$(MAKE) LDFLAGS_CFI='$(LDFLAGS) $(CFI) -static-pie' build-cgo
.PHONY: build-cgo-static
build-msan:
@GO_BUILDFLAGS="-msan" $(MAKE) MOAC_BIN=$(MOAC_BIN)-msan MOAC_PWGEN_BIN=$(MOAC_PWGEN_BIN)-msan build-cgo
.PHONY: build-msan
build-race:
@GO_BUILDFLAGS='-race' $(MAKE) MOAC_BIN=$(MOAC_BIN)-race MOAC_PWGEN_BIN=$(MOAC_PWGEN_BIN)-race BUILDMODE_CGO=default .build-cgo-base
.PHONY: build-race
# Build binaries with -msan + -race
build-san: build-msan build-race
.PHONY: build-san
#- cleans just the artifacts produced by build-san
clean-san-bins:
@$(MAKE) CMD=.clean-bins build-san
.PHONY: clean-san-bins
# Run tests with the race detector (slow)
#
# MOAC itself is single-threaded, but the tests use parallelism.
# This is mostly useful for testing the tests themselves.
test-race:
@$(MAKE) CMD='test' build-race
.PHONY: test-race
# Run tests with -msan (slow, needs Clang)
#
# This doesn't work on some distros (inc. Alpine) since they have an
# incomplete compiler-rt package
test-msan:
@$(MAKE) CMD='test' build-msan
.PHONY: test-msan
# Same as test-msan + test-race
test-san: test-race test-msan
.PHONY: test-san