blob: 91290179a1b2a69f89c50d5a98d4b9d0f8b9b4ef [file] [log] [blame] [view]
Ian Lance Taylor6a2ebdf2022-07-15 10:45:48 -07001# Go generate: A Proposal
2
3Author: Rob Pike
4
5Accepted in the Go 1.4 release.
6
7## Introduction
8
9The go build command automates the construction of Go programs but
10sometimes preliminary processing is required, processing that go build
11does not support.
12Motivating examples include:
13
14- yacc: generating .go files from yacc grammar (.y) files
15- protobufs: generating .pb.go files from protocol buffer definition (.proto) files
16- Unicode: generating tables from UnicodeData.txt
17- HTML: embedding .html files into Go source code
18- bindata: translating binary files such as JPEGs into byte arrays in Go source
19
20There are other processing steps one can imagine:
21
22- string methods: generating String() string methods for types used as enumerated constants
23- macros: generating customized implementations given generalized packages, such as sort.Ints from ints
24
25This proposal offers a design for smooth automation of such processing.
26
27## Non-goal
28
29It is not a goal of this proposal to build a generalized build system
30like the Unix make(1) utility.
31We deliberately avoid doing any dependency analysis.
32The tool does what is asked of it, nothing more.
33
34It is hoped, however, that it may replace many existing uses of
35make(1) in the Go repo at least.
36
37## Design
38
39There are two basic elements, a new subcommand for the go command,
40called go generate, and directives inside Go source files that control
41generation.
42
43When go generate runs, it scans Go source files looking for those
44directives, and for each one executes a generator that typically
45creates a new Go source file.
46The go generate tool also sets the build tag "generate" so that files
47may be examined by go generate but ignored during build.
48
49The usage is:
50
51```
52go generate [-run regexp] [file.go...|packagePath...]
53```
54
55(Plus the usual `-x`, `-n`, `-v` and `-tags` options.)
56If packages are named, each Go source file in each package is scanned
57for generator directives, and for each directive, the specified
58generator is run; if files are named, they must be Go source files and
59generation happens only for directives in those files.
60Given no arguments, generator processing is applied to the Go source
61files in the current directory.
62
63The `-run` flag takes a regular expression, analogous to that of the
64go test subcommand, that restricts generation to those directives
65whose command (see below) matches the regular expression.
66
67Generator directives may appear anywhere in the Go source file and are
68processed sequentially (no parallelism) in source order as presented
69to the tool.
70Each directive is a // comment beginning a line, with syntax
71
72```
73//go:generate command arg...
74```
75
76where command is the generator (such as `yacc`) to be run,
77corresponding to an executable file that can be run locally; it must
78either be in the shell path (`gofmt`) or fully qualified
79(`/usr/you/bin/mytool`) and is run in the package directory.
80
81The arguments are space-separated tokens (or double-quoted strings)
82passed to the generator as individual arguments when it is run.
83Shell-like variable expansion is available for any environment
84variables such as `$HOME`.
85Also, the special variable `$GOFILE` refers to the name of the file
86containing the directive.
87(We may need other special variables such as `$GOPACKAGE`.
88When the generator is run, these are also provided in the shell
89environment.)
90No other special processing, such as globbing, is provided.
91
92No further generators are run if any generator returns an error exit
93status.
94
95As an example, say we have a package `my/own/gopher` that includes a
96yacc grammar in file `gopher.y`.
97Inside `main.go` (not `gopher.y`) we place the directive
98
99```
100//go:generate yacc -o gopher.go gopher.y
101```
102
103(More about what `yacc` means in the next section.)
104Whenever we need to update the generated file, we give the shell
105command,
106
107```
108% go generate my/own/gopher
109```
110
111or, if we are already in the source directory,
112
113```
114% go generate
115```
116
117If we want to make sure that only the yacc generator is run, we
118execute
119
120```
121% go generate -run yacc
122```
123
124If we have fixed a bug in yacc and want to update all yacc-generated
125files in our tree, we can run
126
127```
128% go generate -run yacc all
129```
130
131The typical cycle for a package author developing software that uses
132`go generate` is
133
134```
135% edit …
136% go generate
137% go test
138```
139
140and once things are settled, the author commits the generated files to
141the source repository, so that they are available to clients that use
142go get:
143
144```
145% git add *.go
146% git commit
147```
148
149## Commands
150
151The yacc program is of course not the standard version, but is
152accessed from the command line by
153
154```
155go tool yacc args...
156```
157
158To make it easy to use tools like yacc that are not installed in
159$PATH, have complex access methods, or benefit from extra flags or
160other wrapping, there is a special directive that defines a shorthand
161for a command.
162It is a `go:generate` directive followed by the keyword/flag
163`-command` and which generator it defines; the rest of the line is
164substituted for the command name when the generator is run.
165Thus to define `yacc` as a generator command we access normally by
166running `go tool yacc`, we first write the directive
167
168```
169//go:generate -command yacc go tool yacc
170```
171
172and then all other generator directives using `yacc` that follow in
173that file (only) can be written as above:
174
175```
176//go:generate yacc -o gopher.go gopher.y
177```
178
179which will be translated to
180
181```
182go tool yacc -o gopher.go gopher.y
183```
184
185when run.
186
187## Discussion
188
189This design is unusual but is driven by several motivating principles.
190
191First, `go generate` is intended[^1] to be run by the author of a
192package, not the client of it.
193The author of the package generates the required Go files and includes
194them in the package; the client does a regular `go get` or `go
195build`.
196Generation through `go generate` is not part of the build, just a tool
197for package authors.
198This avoids complicating the dependency analysis done by Go build.
199
200[^1]: One can imagine scenarios where the author wishes the client to
201run the generator, but in such cases the author must guarantee that
202the client has the generator available.
203Regardless, `go get` will not automate the running of the processor,
204so further installation instructions will need to be provided by the
205author.
206
207Second, `go build` should never cause generation to happen
208automatically by the client of the package. Generators should run only
209when explicitly requested.
210
211Third, the author of the package should have great freedom in what
212generator to use (that is a key goal of the proposal), but the client
213might not have that processor available.
214As a simple example, if it is a shell script, it will not run on
215Windows.
216It is important that automated generation not break clients but be
217invisible to them, which is another reason it should be run only by
218the author of the package.
219
220Finally, it must fit well with the existing go command, which means it
221applies only to Go source files and packages.
222This is why the directives are in Go files but not, for example, in
223the .y file holding a yacc grammar.
224
225## Examples
226
227Here are some hypothetical worked examples.
228There are countless more possibilities.
229
230### String methods
231
232We wish to generate a String method for a named constant type.
233We write a tool, say `strmeth`, that reads a definition for a single
234constant type and values and prints a complete Go source file
235containing a method definition for that type.
236
237In our Go source file, `main.go`, we decorate each constant
238declaration like this (with some blank lines interposed so the
239generator directive does not appear in the doc comment):
240
241```Go
242//go:generate strmeth Day -o day_string.go $GOFILE
243
244// Day represents the day of the week
245type Day int
246const (
247 Sunday Day = iota
248 Monday
249 ...
250)
251```
252
253The `strmeth` generator parses the Go source to find the definition of
254the `Day` type and its constants, and writes out a `String() string`
255method for that type.
256For the user, generation of the string method is trivial: just run `go
257generate`.
258
259### Yacc
260
261As outlined above, we define a custom command
262
263```
264//go:generate -command yacc go tool yacc
265```
266
267and then anywhere in main.go (say) we write
268
269```
270//go:generate yacc -o foo.go foo.y
271```
272
273### Protocol buffers
274
275The process is the same as with yacc.
276Inside `main.go`, we write, for each protocol buffer file we have, a
277line like
278
279```
280//go:generate protoc -go_out=. file.proto
281```
282
283Because of the way protoc works, we could generate multiple proto
284definitions into a single `.pb.go` file like this:
285
286```
287//go:generate protoc -go_out=. file1.proto file2.proto
288```
289
290Since no globbing is provided, one cannot say `*.proto`, but this is
291intentional, for simplicity and clarity of dependency.
292
293Caveat: The protoc program must be run at the root of the source tree;
294we would need to provide a `-cd` option to it or wrap it somehow.
295
296### Binary data
297
298A tool that converts binary files into byte arrays that can be
299compiled into Go binaries would work similarly.
300Again, in the Go source we write something like
301
302```
303//go:generate bindata -o jpegs.go pic1.jpg pic2.jpg pic3.jpg
304```
305
306This is also demonstrates another reason the annotations are in Go
307source: there is no easy way to inject them into binary files.
308
309### Sort
310
311One could imagine a variant sort implementation that allows one to
312specify concrete types that have custom sorters, just by automatic
313rewriting of macro-like sort definition.
314To do this, we write a `sort.go` file that contains a complete
315implementation of sort on an explicit but undefined type spelled, say,
316`TYPE`.
317In that file we provide a build tag so it is never compiled (`TYPE` is
318not defined, so it won't compile) but is processed by `go generate`:
319
320```
321// +build generate
322```
323
324Then we write an generator directive for each type for which we want a
325custom sort:
326
327```
328//go:generate rename TYPE=int
329//go:generate rename TYPE=strings
330```
331
332or perhaps
333
334```
335//go:generate rename TYPE=int TYPE=strings
336```
337
338The rename processor would be a simple wrapping of `gofmt -r`, perhaps
339written as a shell script.
340
341There are many more possibilities, and it is a goal of this proposal
342to encourage experimentation with pre-build-time code generation.