-
Notifications
You must be signed in to change notification settings - Fork 0
/
tooling.tex
580 lines (436 loc) · 15.8 KB
/
tooling.tex
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
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
\cleardoublepage
\phantomsection
\chapter{Tooling}
\begin{quote}
\textit{We become what we behold. We shape our tools, and thereafter our tools shape us.} --- Marshall McLuhan
\end{quote}
Good support for lots of useful tools is another strength of Go.
Apart from the built-in tools, there any many other community-built
tools. This chapter covers the built-in Go tools and few other
external tools.
The built-in Go tools can access through the \texttt{go} command.
When you install the Go compiler (\texttt{gc}); the \texttt{go} tool
is available in the path. The \texttt{go} tool has many commands.
You can use the \texttt{go} tool to compile Go programs, run test
cases, and format source files among other things.
\section{Getting Help}
The go tool is self-documented\index{tool!help}. You can get help
about any commands easily. To see the list of all commands, you can
run the \texttt{"help"} command. For example, to see help
for \texttt{build} command, you can run like this:
\begin{lstlisting}[numbers=none]
go help build
\end{lstlisting}
The help command also provides help for specific topics like
"buildmode", "cache", "filetype", and "environment" among other
topics. To see help for a specific topic, you can run the command
like this:
\begin{lstlisting}[numbers=none]
go help environment
\end{lstlisting}
\section{Basic Information}
\subsection{Version}
When reporting bugs, it is essential to specify the Go version\index{version}
number and environment details. The Go tool gives access to this information
through the following commands.
To get version information, run this command\index{tool!version}:
\begin{lstlisting}[numbers=none]
go version
\end{lstlisting}
The output should look something like this:
\begin{lstlisting}[numbers=none]
go version go1.20.4 linux/amd64
\end{lstlisting}
As you can see, it shows the version number followed by operating
system and CPU architecture.
\subsection{Environment}
To get environment variables, you can run this command\index{tool!env}:
\begin{lstlisting}[numbers=none]
go env
\end{lstlisting}
The output should display all the environment variables used by the Go
tool when running different commands.
A typical output will look like this:
\begin{lstlisting}[numbers=none]
GO111MODULE=""
GOARCH="amd64"
GOBIN=""
GOCACHE="/home/baiju/.cache/go-build"
GOENV="/home/baiju/.config/go/env"
GOEXE=""
GOEXPERIMENT=""
GOFLAGS=""
GOHOSTARCH="amd64"
GOHOSTOS="linux"
GOINSECURE=""
GOMODCACHE="/home/baiju/go/pkg/mod"
GONOPROXY=""
GONOSUMDB=""
GOOS="linux"
GOPATH="/home/baiju/go"
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOROOT="/usr/local/go"
GOSUMDB="sum.golang.org"
GOTMPDIR=""
GOTOOLDIR="/usr/local/go/pkg/tool/linux_amd64"
GOVCS=""
GOVERSION="go1.20.4"
GCCGO="gccgo"
GOAMD64="v1"
AR="ar"
CC="gcc"
CXX="g++"
CGO_ENABLED="1"
GOMOD="/dev/null"
GOWORK=""
CGO_CFLAGS="-O2 -g"
CGO_CPPFLAGS=""
CGO_CXXFLAGS="-O2 -g"
CGO_FFLAGS="-O2 -g"
CGO_LDFLAGS="-O2 -g"
PKG_CONFIG="pkg-config"
GOGCCFLAGS="-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0
-fdebug-prefix-map=/tmp/go-build1378738152=/tmp/go-build
-gno-record-gcc-switches"
\end{lstlisting}
You can temporarily set environment variable with \texttt{-w} option. This is an
example to set \textit{GOPATH} in Windows system.
\begin{lstlisting}[numbers=none]
C:\> go env -w GOPATH=C:\mygo
\end{lstlisting}
Note: To set an environment variable permenantly in Windows, see the first
chapter which explains about Windows installation.
\subsection{List}
The \textit{list} command provides meta information about packages.
Running without any arguments shows the current packages import path.
The \textit{-f} helps to extract more information, and it can specify
a format. The \textit{text/template} package syntax can be used to
specify the format.
The struct used to format has many attributes, here is a subset:
\begin{itemize}
\item \textit{Dir} -- directory containing package sources
\item \textit{ImportPath} -- import path of package in dir
\item \textit{ImportComment} -- path in import comment on package statement
\item \textit{Name} -- package name
\item \textit{Doc} -- package documentation string
\item \textit{Target} -- install path
\item \textit{GoFiles} -- list of \texttt{.go} source files
\end{itemize}
Here is an example usage:
\begin{lstlisting}[numbers=none]
$ go list -f '{{.GoFiles}}' text/template
[doc.go exec.go funcs.go helper.go option.go template.go]
\end{lstlisting}
\section{Building and Running}
To compile a program, you can use the \texttt{build}
command\index{tool!build}. To compile a package, first change to the
directory where the program is located and run the \texttt{build}
command:
\begin{lstlisting}[numbers=none]
go build
\end{lstlisting}
You can also compile Go programs without changing the directory. To
do that, you are required to specify the package location in the
command line. For example, to
compile \texttt{github.com/baijum/introduction} package run the
command given below:
\begin{lstlisting}[numbers=none]
go build github.com/baijum/introduction
\end{lstlisting}
If you want to set the executable binary file name, use
the \texttt{-o} option:
\begin{lstlisting}[numbers=none]
go build -o myprog
\end{lstlisting}
If you want to build and run at once, you can use the \texttt{"run"}
command:
\begin{lstlisting}[numbers=none]
go run program.go
\end{lstlisting}
You can specify more that one Go source file in the command line
arguments:
\begin{lstlisting}[numbers=none]
go run file1.go file2.go file3.go
\end{lstlisting}
Of course, when you specify more than one file names, only one "main"
function should be defined among all of the files.
\subsection{Conditional Compilation}
Sometimes you need to write code specific to a particular operating
system. In some other case the code for a particular CPU
architecture. It could be code optimized for that particular
combination. The Go build tool supports conditional compilation using
build constraints. The Build constraint is also known as build tag.
There is another approach for conditional compilation using a naming
convention for files names. This section is going to discuss both
these approaches.
The build tag should be given as comments at the top of the source
code. The build tag comment should start like this:
\begin{lstlisting}[numbers=none]
// +build
\end{lstlisting}
The comment should be before package documentation and there should be
a line in between.
The space is \textit{OR} and comma is \textit{AND}. The exclamation
character is stands for negation.
Here is an example:
\begin{lstlisting}[numbers=none]
// +build linux,386
\end{lstlisting}
In the above example, the file will compile on 32-bit x86 Linux
system.
\begin{lstlisting}[numbers=none]
// +build linux darwin
\end{lstlisting}
The above one compiles on Linux or Darwin (Mac OS).
\begin{lstlisting}[numbers=none]
// +build !linux
\end{lstlisting}
The above runs on anything that is not Linux.
The other approach uses file naming convention for conditional
compilation. The files are ignore if it doesn't match the target OS
and CPU architecture, if any.
This compiles only on Linux:
\begin{lstlisting}[numbers=none]
stat_linux.go
\end{lstlisting}
This one on 64 bit ARM linux:
\begin{lstlisting}[numbers=none]
os_linux_arm64.go
\end{lstlisting}
\section{Running Test}
The Go tool has a built-in test runner\index{tool!test}. To run tests
for the current package, run this command:
\begin{lstlisting}[numbers=none]
go test
\end{lstlisting}
To demonstrate the remaining commands, consider packages organized
like this:
\begin{lstlisting}[numbers=none]
.
|-- hello.go
|-- hello_test.go
|-- sub1
| |-- sub1.go
| `-- sub1_test.go
`-- sub2
|-- sub2.go
`-- sub2_test.go
\end{lstlisting}
If you run \texttt{go test} from the top-level directory, it's going
to run tests in that directory, and not any sub directories. You can
specify directories as command line arguments to \texttt{go test}
command to run tests under multiple packages simultaneously.
In the above listed case, you can run all tests like this:
\begin{lstlisting}[numbers=none]
go test . ./sub1 ./sub2
\end{lstlisting}
Instead of listing each packages separates, you can use the ellipsis
syntax:
\begin{lstlisting}[numbers=none]
go test ./...
\end{lstlisting}
The above command run tests under current directory and its child
directories.
By default \texttt{go test} shows very few details about the tests.
\begin{lstlisting}[numbers=none]
$ go test ./...
ok _/home/baiju/code/mypkg 0.001s
ok _/home/baiju/code/mypkg/sub1 0.001s
--- FAIL: TestSub (0.00s)
FAIL
FAIL _/home/baiju/code/mypkg/sub2 0.003s
\end{lstlisting}
In the above results, it shows the name of failed test. But details
about other passing tests are not available. If you want to see
verbose results, use the \texttt{-v} option.
\begin{lstlisting}[numbers=none]
$ go test ./... -v
=== RUN TestHello
--- PASS: TestHello (0.00s)
PASS
ok _/home/baiju/code/mypkg 0.001s
=== RUN TestSub
--- PASS: TestSub (0.00s)
PASS
ok _/home/baiju/code/mypkg/sub1 0.001s
=== RUN TestSub
--- FAIL: TestSub (0.00s)
FAIL
FAIL _/home/baiju/code/mypkg/sub2 0.002s
\end{lstlisting}
If you need to filter tests based on the name, you can use
the \texttt{-run} option.
\begin{lstlisting}[numbers=none]
$ go test ./... -v -run Sub
testing: warning: no tests to run
PASS
ok _/home/baiju/code/mypkg 0.001s [no tests to run]
=== RUN TestSub
--- PASS: TestSub (0.00s)
PASS
ok _/home/baiju/code/mypkg/sub1 0.001s
=== RUN TestSub
--- FAIL: TestSub (0.00s)
FAIL
FAIL _/home/baiju/code/mypkg/sub2 0.002s
\end{lstlisting}
As you can see above, the \texttt{TestHello} test was skipped as it
doesn't match "Sub" pattern.
The chapter on testing has more details about writing test cases.
\textit{golangci-lint}\index{lint} is a handy program to run various lint tools and
normalize their output. This program is useful to run through continuous
integration. You can download the program from here:
\url{https://github.com/golangci/golangci-lint}\\
The supported lint tools include Vet, Golint, Varcheck, Errcheck, Deadcode,
Gocyclo among others. \textit{golangci-lint} allows to enable/disable the lint
tools through a configuration file.
\section{Formatting Code}
Go has a recommended source code formatting\index{tool!format}. To
format any Go source file to conform to that format, it's just a
matter of running one command. Normally you can integrate this
command with your text editor or IDE. But if you really want to
invoke this program from command line, this is how you do it:
\begin{lstlisting}[numbers=none]
go fmt myprogram.go
\end{lstlisting}
In the above command, the source file name is explicitly specified.
You can also give package name:
\begin{lstlisting}[numbers=none]
go fmt github.com/baijum/introduction
\end{lstlisting}
The command will format source files and write it back to the same
file. Also it will list the files that is formatted.
\section{Generating Code}
If you have use case to generate Go code from a grammar, you may consider
the \textit{go generate}. In fact, you can add any command to be run before
compiling the code. You can add a special comment in your Go code with this
syntax:
\begin{lstlisting}[numbers=none]
//go:generate command arguments
\end{lstlisting}
For example, if you want to use \textit{peg}
(\url{https://github.com/pointlander/peg}), a Parsing Expression Grammar
implementation, you can add the command like this:
\begin{lstlisting}[numbers=none]
//go:generate peg -output=parser.peg.go grammar.peg
\end{lstlisting}
When you build the program, the parser will be generated and will be part of the
code that compiles.
\section{Embedding Code}
Go programs are normally distributed as a single binary. What if your program
need some files to run. Go has a feature to embed files in the binary. You can
embed any type of files, including text files and binary files. Some of the
commonly embedded files are SQL, HTML, CSS, JavaScript, and images. You can
embed individual files or diectories including nested sub-directories.
You need to import the \textit{embed} package and use the \texttt{//go:embed}
compiler directive to embed. Here is an example to embed an SQL file:
\begin{lstlisting}[numbers=none]
import _ "embed"
//go:embed database-schema.sql
var dbSchema string
\end{lstlisting}
As you can see, the "embed" package is imported with a blank identifier as it is
not directly used in the code. This is required to initialize the package to
embed files. The variable must be at package level and not at function or method
level.
The variable could be slice of bytes. This is useful for binary files. Here is
an example:
\begin{lstlisting}[numbers=none]
import _ "embed"
//go:embed logo.jpg
var logo []byte
\end{lstlisting}
If you need an entire directory, you can use the \texttt{embed.FS} as the type:
\begin{lstlisting}[numbers=none]
import "embed"
//go:embed static
var content embed.FS
\end{lstlisting}
\section{Displaying Documentation}
Go has good support for writing documentation along with source
code\index{tool!doc}. You can write documentation for packages,
functions and custom defined types. The Go tool can be used to
display those documentation.
To see the documentation for the current packages, run this command:
\begin{lstlisting}[numbers=none]
go doc
\end{lstlisting}
To see documentation for a specific package:
\begin{lstlisting}[numbers=none]
go doc strings
\end{lstlisting}
The above command shows documentation for the "strings" package.
\begin{lstlisting}[numbers=none]
go doc strings
\end{lstlisting}
If you want to see documentation for a particular function within that
package:
\begin{lstlisting}[numbers=none]
go doc strings.ToLower
\end{lstlisting}
or a type:
\begin{lstlisting}[numbers=none]
go doc strings.Reader
\end{lstlisting}
Or a method:
\begin{lstlisting}[numbers=none]
go doc strings.Reader.Size
\end{lstlisting}
\section{Find Suspicious Code Using Vet}
There is a handy tool named \textit{vet}\index{tool!vet} to find
suspicious code in your program. Your program might compile and
run. But some of the results may not be desired output.
Consider this program:
\lstinputlisting{code/tooling/suspicious/suspicious.go}
If you compile and run it. It's going to be give some output. But if
you observe the code, there is an unnecessary \texttt{\%s} format
string.
If you run \texttt{vet} command, you can see the issue:
%% TODO: Change the font size back to \small and change filename to
%% suspicious.go (Probably this can be changed after moving the
%% content to next page}
\begin{lstlisting}[numbers=none]
$ go vet susp.go
# command-line-arguments
./susp.go:9: Printf format %s reads arg #2,
but call has only 1 arg
\end{lstlisting}
Note: The \textit{vet} command is automatically run along with
the \textit{test} command.
\section{Exercises}
\textbf{Exercise 1:} Create a program with function to return "Hello, world!" and
write test and run it.
\textit{hello.go}:
\begin{lstlisting}[numbers=none]
package hello
// SayHello returns a "Hello word!" message
func SayHello() string {
return "Hello, world!"
}
\end{lstlisting}
\textit{hello\_test.go}:
\begin{lstlisting}[numbers=none]
package hello
import "testing"
func TestSayHello(t *testing.T) {
out := SayHello()
if out != "Hello, world!" {
t.Error("Incorrect message", out)
}
}
\end{lstlisting}
To run the test:
\begin{lstlisting}[numbers=none]
go test . -v
\end{lstlisting}
\subsection{Additional Exercises}
Answers to these additional exercises are given in the Appendix A.
{\bfseries Problem 1:} Write a program with exported type and methods
with documentation strings. Then print the documentation
using the \texttt{go doc} command.
\section*{Summary}
This chapter introduced the Go tool. It explained all the major Go commands in
detail and provided practical examples for each command. It covered how to build
and run programs, run tests, format code, and display documentation. It also
mentioned a few other useful tools.