Go ships with several useful commands that simplify the development process. The commands themselves are commonly included in IDEs, making the tooling consistent across development environments. Let’s take a look at some of these commands.
The go run Command
One of the more common commands you’ll execute during development, go run will compile and execute the main package, your program’s entry point.
As an example, save the following code under a project directory within $GOPATH/src ( you created this workspace during installation of Go) as main.go
package main import "fmt" func main() { fmt.Println("Common Go Tool Commands") fmt.Println("1. go run") }
From the command line, within the directory containing this file, execute go run main.go. You should see the following output printed to your screen.
$ go run main.go
Common Go Tool Commands
1. go run
The go build Command
Note that go run executed your file, but it didn’t produce a standalone binary file. That’s where go build comes in. The go build command compiles your application, including any packages and their dependencies, without installing the results. It creates a binary file on disk but doesn’t execute your program. The files it creates follow reasonable naming conventions, but it’s not uncommon to change the name of the created binary file by using the -o output command line option.
Rename main.go from the previous example to hello.go. In a terminal window, execute go build hello.go.
~/calling-c-code-from-go$ ls
go.mod hello.go main Makefile replit.nix
~/calling-c-code-from-go$ go build hello.go
~/calling-c-code-from-go$ ls
go.mod hello hello.go main Makefile replit.nix
For you If everything goes as intended, this command should create an executable file within the name hello as shown in above output. Now enter this command to run the binary:
~/calling-c-code-from-go$ ./hello
Common Go Tool Commands
1. go run
This should run the standalone binary file.
By default, the produced binary file contains debugging information and the symbol table. This can bloat the size of the file. To reduce the file size, you can include additional flags during the build process to strip this information from the binary. For example, the following command will reduce the binary size by approximately 30 percent:
generated binary size with go build -o hello.go command
~/calling-c-code-from-go$ ls -la
total 3492
-rwxr-xr-x 1 runner runner 1774982 Oct 21 09:15 hello
-rw-r--r-- 1 runner runner 112 Oct 21 09:14 hello.go
generated binary size with go build -o new_hello -ldflags "-w -s" command
~/calling-c-code-from-go$ ls -lt
total 4668
-rwxr-xr-x 1 runner runner 1208320 Oct 21 09:30 new_hello
-rwxr-xr-x 1 runner runner 1774982 Oct 21 09:15 hello
-rw-r--r-- 1 runner runner 112 Oct 21 09:14 hello.go
Having a smaller binary will make it more efficient to transfer or embed while pursuing your nefarious endeavors.
Cross-Compiling
Using go build works great for running a binary on your current system or one of identical architecture, but what if you want to create a binary that can run on a different architecture? That’s where cross-compiling comes in. Cross-compiling is one of the coolest aspects of Go, as no other language can do it as easily. The build command allows you to cross-compile your program for multiple operating systems and architectures. Reference the official Go documentation for further details regarding allowable combinations of compatible operating system and architecture compilation types.
To cross-compile, you need to set a constraint. This is just a means to pass information to build command about the operating system and architecture for which you’d like to compile your code. These constraints include GOOS (for the operating system) and GOARCH ( for the architecture).
You can introduce build constraints in three ways: via the command line, code comments, or a file suffix naming convention. We’ll discuss the command line method here and leave the other two methods for you to research if you wish.
Let’s suppose that you want to cross-compile your previous hello.go program residing on a windows system so that it runs on a Linux 64-bit architecture. You can accomplish this via the command line by setting the GOOS and GOARCH constraints when running build command:
$ GOOS="linux" GOARCH="amd64" go build hello.go
$ ls
hello hello.go
$ file hello
hello: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, not stripped
The output confirms that the resulting binary is a 64-bit ELF(Linux) file.
The cross-compilation process in much simpler in Go than in just about any other modern programming language. The only read ‘gotcha’ happens when you try to cross-compile applications that use native C bindings. We’ll stay out of the weeds and let you dig into those challenges independently. Depending on the packages you import and the projects you develop, you may not have to worry about that very often.
The go doc Command
The go doc command lets you interrogate documentation about a package, function method, or variable. This documentation is embedded as comments through your code. Let’s take a look at how to obtain details about the json.Unmarshal() function:
$ go doc json.Unmarshal
package json // import "encoding/json"
func Unmarshal(data []byte, v any) error
Unmarshal parses the JSON-encoded data and stores the result in the value
pointed to by v. If v is nil or not a pointer, Unmarshal returns an
InvalidUnmarshalError.
Unmarshal uses the inverse of the encodings that Marshal uses, allocating
maps, slices, and pointers as necessary, with the following additional
rules:
To unmarshal JSON into a pointer, Unmarshal first handles the case of the
JSON being the JSON literal null. In that case, Unmarshal sets the pointer
to nil. Otherwise, Unmarshal unmarshals the JSON into the value pointed at
by the pointer. If the pointer is nil, Unmarshal allocates a new value for
it to point to.
To unmarshal JSON into a value implementing the Unmarshaler interface,
Unmarshal calls that value's UnmarshalJSON method, including when the input
is a JSON null. Otherwise, if the value implements encoding.TextUnmarshaler
and the input is a JSON quoted string, Unmarshal calls that value's
UnmarshalText method with the unquoted form of the string.
To unmarshal JSON into a struct, Unmarshal matches incoming object keys to
the keys used by Marshal (either the struct field name or its tag),
preferring an exact match but also accepting a case-insensitive match. By
default, object keys which don't have a corresponding struct field are
ignored (see Decoder.DisallowUnknownFields for an alternative).
To unmarshal JSON into an interface value, Unmarshal stores one of these in
the interface value:
bool, for JSON booleans
float64, for JSON numbers
string, for JSON strings
[]interface{}, for JSON arrays
map[string]interface{}, for JSON objects
nil for JSON null
To unmarshal a JSON array into a slice, Unmarshal resets the slice length to
zero and then appends each element to the slice. As a special case, to
unmarshal an empty JSON array into a slice, Unmarshal replaces the slice
with a new empty slice.
To unmarshal a JSON array into a Go array, Unmarshal decodes JSON array
elements into corresponding Go array elements. If the Go array is smaller
than the JSON array, the additional JSON array elements are discarded. If
the JSON array is smaller than the Go array, the additional Go array
elements are set to zero values.
To unmarshal a JSON object into a map, Unmarshal first establishes a map to
use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
reuses the existing map, keeping existing entries. Unmarshal then stores
key-value pairs from the JSON object into the map. The map's key type must
either be any string type, an integer, implement json.Unmarshaler, or
implement encoding.TextUnmarshaler.
If a JSON value is not appropriate for a given target type, or if a JSON
number overflows the target type, Unmarshal skips that field and completes
the unmarshaling as best it can. If no more serious errors are encountered,
Unmarshal returns an UnmarshalTypeError describing the earliest such error.
In any case, it's not guaranteed that all the remaining fields following the
problematic one will be unmarshaled into the target object.
The JSON null value unmarshals into an interface, map, pointer, or slice by
setting that Go value to nil. Because null is often used in JSON to mean
“not present,” unmarshaling a JSON null into any other Go type has no effect
on the value and produces no error.
When unmarshaling quoted strings, invalid UTF-8 or invalid UTF-16 surrogate
pairs are not treated as an error. Instead, they are replaced by the Unicode
replacement character U+FFFD.
The output that go doc produces is taken directly out of the source code comments. As long as you adequately comment your packages, functions, methods, and variables, you’ll be able to automatically inspect the documentation via the go doc command.
The go get Command
Many of the Go programs that you’ll develop requires third-party packages. To obtain package source code, use the go get command. For instance, let’s assume you’ve written the following code that imports the github.com/gorilla/mux package:
package main import ( "fmt" "net/http" "github.com/gorilla/mux" )
Even though you’ve imported the github.com/gorilla/mux package, you can’t access the package quite yet. You first have to run the go get command. Using go get github.com/gorilla/mux downloads the actual package and places it within the $GOPATH/pkg directory.
The following directory tree illustrate the placement of the gorilla mux package within your GOPATH workspace:
$ tree pkg/mod/github.com/gorilla/
pkg/mod/github.com/gorilla/
|-- mux@v1.8.0
| |-- AUTHORS
| |-- LICENSE
| |-- README.md
| |-- bench_test.go
| |-- doc.go
| |-- example_authentication_middleware_test.go
| |-- example_cors_method_middleware_test.go
| |-- example_route_test.go
| |-- go.mod
| |-- middleware.go
| |-- middleware_test.go
| |-- mux.go
| |-- mux_httpserver_test.go
| |-- mux_test.go
| |-- old_test.go
| |-- regexp.go
| |-- regexp_test.go
| |-- route.go
| `-- test_helpers.go
0 directories, 19 files
Notice that the path and the imported package name are constructed in a way that avoids assigning the same name to multiple packages. Using github.com/gorilla/mux as a preface to the actual package name mux ensures that the package name remains unique.
Although Go developers traditionally install dependencies with go get, problems can arise if those dependent packages receive updated that break backward compatibility. Go has introduced two separate tools dep and mod to lock dependencies in order to prevent backward compatibility issues.
The go fmt Command
The go fmt command automatically formats your source code. For example, running go fmt /path/to/your/packge will style your code by enforcing the use of proper line breaks, indentation, and brace alignment.
Adhering to arbitrary styling preference might seem strange at first, particularly if they differ from your habits. However, you should find this consistency refreshing over time, as you code will look similar to other third-party packages and feel more organized. Most IDEs contain hooks that will automatically run go fmt when you save your file, so you don’t need to explicitly run the command.
The golint and go vet Commands
Whereas go fmt changes the syntactical styling of your code, golint reports style mistakes such as missing comments, variable naming that doesn’t follow conventions, useless type specifications, and more. Notice that golint is a standalone tool, and not a subcommand of the main go binary. You’ll need to install it separately by using go get -u golang.org/x/lint/golint.
Similarly, go vet inspects your code and uses heuristics to identify suspicious constructs, such as calling Printf() with the incorrect format string types. The go vet command attempts to identify issues, some of which might be legitimate bugs, that a compiler might miss.
Other Commands and Tools
Although I won’t explicitly discuss other tools and commands, I encourage you to do your own research. As you create increasingly complex projects, you’re likely to run into a desire to, for example, use of the go test tool to run unit tests and benchmarks, cover to check for test coverage, imports to fix import statements, and more.
your comments are appreciated and if you wants to see your articles on this platform then please shoot a mail at this address kusingh@programmingeeksclub.com
Thanks for reading 🙂