github.com/jonsyu1/godel@v0.0.0-20171017211503-64567a0cf169/docs/Build.md (about) 1 Summary 2 ------- 3 `./godelw build` builds the products in the project based on the build configuration. 4 5 Tutorial start state 6 -------------------- 7 8 * `$GOPATH/src/github.com/nmiyake/echgo` exists and is the working directory 9 * Project contains `godel` and `godelw` 10 * Project contains `main.go` 11 * Project contains `.gitignore` that ignores IDEA files 12 * Project contains `echo/echo.go`, `echo/echo_test.go` and `echo/echoer.go` 13 14 ([Link](https://github.com/nmiyake/echgo/tree/404c745e6bc0f70f4d4b58b60502e5b9620a00a7)) 15 16 Build 17 ----- 18 19 Now that we have a functional program with some tests, it's time to think about how to build and distribute the program. 20 We will start by considering how to build the program. We will be providing binary distributions for `darwin-amd64` and 21 `linux-amd64` systems. We also want to include a version variable in the product so that users can determine the version 22 of the product by invoking it with a `-version` flag. 23 24 Start by running `./godelw build` in the project to observe the default behavior: 25 26 ``` 27 ➜ ./godelw build 28 Building echgo for darwin-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/unspecified/darwin-amd64/echgo 29 Finished building echgo for darwin-amd64 (0.442s) 30 ``` 31 32 The default build settings builds all `main` packages for the executing platform. As stated by the output, this command 33 built an executable for the OS/architecture of the host system in the `build` directory of the project. The executable 34 is fully built and can be run: 35 36 ``` 37 ➜ ./build/unspecified/darwin-amd64/echgo foo 38 foo 39 ``` 40 41 The output of the `build` command can be removed by running `./godelw clean`. The output directory can be specified 42 using the `output-dir` key, but we will keep it as `build` for this product. We do not want to track build artifacts in 43 git, so run the following to add `/build/` to the `.gitignore` file and commit it: 44 45 ``` 46 ➜ echo '/build/' >> .gitignore 47 ➜ git add .gitignore 48 ➜ git commit -m "Update .gitignore to ignore build directory" 49 [master 4e51282] Update .gitignore to ignore build directory 50 1 file changed, 1 insertion(+) 51 ``` 52 53 The first step of customizing the build parameters for the product is to explicitly define the products in the project. 54 Builds operate on the concepts of products, where a product is a Go `main` package. A single project may have multiple 55 products. Define the `echgo` product for this project as follows: 56 57 ``` 58 ➜ echo 'products: 59 echgo: 60 build: 61 main-pkg: .' > godel/config/dist.yml 62 ``` 63 64 The `main-pkg` key specifies that the main package for the product is located at `.` (relative to the root directory of 65 the project). 66 67 Define OS/architectures 68 ----------------------- 69 70 By default, the `./godelw build` command builds an executable that matches the OS and architecture of the host system. 71 The `os-archs` parameter can be used to define the exact OS/architecture pairs for which a product should be built. Run 72 the following command to update the configuration to specify that `echgo` should be built for `darwin-amd64` and 73 `linux-amd64`: 74 75 ``` 76 ➜ echo 'products: 77 echgo: 78 build: 79 main-pkg: . 80 os-archs: 81 - os: darwin 82 arch: amd64 83 - os: linux 84 arch: amd64' > godel/config/dist.yml 85 ``` 86 87 `os-archs` is a list of OS and architectures for which the product should be built. For a list of available 88 OS/architecture combinations, refer to the [Go documentation](https://golang.org/doc/install/source#environment) or run 89 `go tool dist list`. 90 91 Run `./godelw build` with the updated configuration: 92 93 ``` 94 ➜ ./godelw build 95 Building echgo for darwin-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/unspecified/darwin-amd64/echgo 96 Building echgo for linux-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/unspecified/linux-amd64/echgo 97 Finished building echgo for darwin-amd64 (0.362s) 98 Finished building echgo for linux-amd64 (0.365s) 99 ``` 100 101 As indicated by the output, the product has now been built for both `darwin-amd64` and `linux-amd64`. 102 103 NOTE: if you have not cross-compiled a Go program before, the command may produce an error of the form: 104 `go install <path>: mkdir <path>: permission denied`. gödel should provide a description of the error and a 105 suggested fix. This error occurs because the standard Go distribution only includes the compiled object files for 106 the standard library for the target platform. The gödel command attempts to build the standard library for all 107 target platforms, but the Go library is often in a location that is not writable by the standard user. When 108 cross-compiling, gödel expects the standard library for the target platform to be present (this saves time by 109 ensuring that the standard library is not constantly re-compiled). Running `go install std` using `sudo` (or as a 110 user who can write to the Go library directory) for the target OS/architecture should resolve the issue. For 111 example, if you were running on a `darwin` system and encountered an error having to do with the `linux` libraries 112 not being installed, run `sudo env GOOS=linux GOARCH=amd64 go install std`. 113 114 Set a version variable 115 ---------------------- 116 117 The `version-var` configuration can be used to set the value of a variable to be the version of the project determined 118 at build time. The project version is based on the output of `git describe`. 119 120 Update `main.go` to add support for printing a version variable: 121 122 ``` 123 ➜ echo 'package main 124 125 import ( 126 "flag" 127 "fmt" 128 "strings" 129 130 "github.com/nmiyake/echgo/echo" 131 ) 132 133 var version = "none" 134 135 func main() { 136 versionVar := flag.Bool("version", false, "print version") 137 flag.Parse() 138 if *versionVar { 139 fmt.Println("echgo version:", version) 140 return 141 } 142 echoer := echo.NewEchoer() 143 fmt.Println(echoer.Echo(strings.Join(flag.Args(), " "))) 144 }' > main.go 145 ``` 146 147 Running this program with `-version` outputs the value `none`: 148 149 ``` 150 ➜ go run main.go -version 151 echgo version: none 152 ``` 153 154 The desired behavior is to set the `version` variable to be the version of the program when it is built. Configure this 155 by updating the build configuration as follows: 156 157 ``` 158 ➜ echo 'products: 159 echgo: 160 build: 161 main-pkg: . 162 version-var: main.version 163 os-archs: 164 - os: darwin 165 arch: amd64 166 - os: linux 167 arch: amd64' > godel/config/dist.yml 168 ``` 169 170 Run `./godelw build` and invoke the build executable to see that the version variable has been set: 171 172 ``` 173 ➜ ./godelw build 174 Building echgo for linux-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/unspecified/linux-amd64/echgo 175 Building echgo for darwin-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/unspecified/darwin-amd64/echgo 176 Finished building echgo for linux-amd64 (0.495s) 177 Finished building echgo for darwin-amd64 (0.501s) 178 ➜ ./build/unspecified/darwin-amd64/echgo -version 179 echgo version: unspecified 180 ``` 181 182 The fact that the output is now "unspecified" (rather than "none" as specified in the source code) demonstrates that the 183 version was set by the build. The version is "unspecified" because there are no git tags present. We can fix this by 184 tagging a release. 185 186 Commit the files that were modified and tag a release: 187 188 ``` 189 ➜ git add main.go godel/config/dist.yml 190 ➜ git commit -m "Add version variable and define build configuration" 191 [master 7799802] Add version variable and define build configuration 192 2 files changed, 20 insertions(+), 2 deletions(-) 193 ➜ git tag 0.0.1 194 ``` 195 196 Now that the repository is tagged, run `./godelw build` and run version on the executable: 197 198 ``` 199 ➜ ./godelw build 200 Building echgo for linux-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/0.0.1/linux-amd64/echgo 201 Building echgo for darwin-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/0.0.1/darwin-amd64/echgo 202 Finished building echgo for linux-amd64 (0.362s) 203 Finished building echgo for darwin-amd64 (0.365s) 204 ➜ ./build/0.0.1/darwin-amd64/echgo -version 205 echgo version: 0.0.1 206 ``` 207 208 Tutorial end state 209 ------------------ 210 211 * `$GOPATH/src/github.com/nmiyake/echgo` exists and is the working directory 212 * Project contains `godel` and `godelw` 213 * Project contains `main.go` 214 * Project contains `.gitignore` that ignores IDEA files 215 * Project contains `echo/echo.go`, `echo/echo_test.go` and `echo/echoer.go` 216 * `godel/config/dist.yml` is configured to build `echgo` 217 * Project is tagged as 0.0.1 218 219 ([Link](https://github.com/nmiyake/echgo/tree/7799802bb82db52e99dda67edf9c98333b28fca3)) 220 221 Tutorial next step 222 ------------------ 223 224 [Run](https://github.com/palantir/godel/wiki/Run) 225 226 More 227 ---- 228 229 ### Differences between `./godelw build` and `go build ./...` 230 231 The primary difference between `./godelw build` and `go build ./...` is that `./godelw build` uses the `dist.yml` 232 configuration to build the outputs, which gives much more control over the build process. It also creates binaries for 233 all of its products, whereas `go build` will only generate a binary if only a `main` package is built. 234 235 `./godelw build` also strives to be efficient in its operation by doing the following: 236 237 * Build operations are performed in parallel 238 * Builds operate in "install" mode so that intermediate object files are generated and re-used on subsequent runs 239 * Products will only be built if code has changed in such a way that necessitates a re-build 240 241 These optimizations make building projects that build binaries for multiple different OS/architecture combinations 242 significantly faster than simply using `go build` to build them serially. 243 244 ### Build specific products 245 246 By default, `./godelw build` will build all of the products defined for a project. Product names can be specified as 247 arguments to build only those products. For example, if the `echgo` project defined multiple products, you could specify 248 that you want to build only `echgo` by running the following: 249 250 ``` 251 ➜ ./godelw build echgo 252 Building echgo for darwin-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/0.0.1/darwin-amd64/echgo 253 Building echgo for linux-amd64 at /Volumes/git/go/src/github.com/nmiyake/echgo/build/0.0.1/linux-amd64/echgo 254 Finished building echgo for linux-amd64 (0.402s) 255 Finished building echgo for darwin-amd64 (0.405s) 256 ``` 257 258 ### Specify build environment variables 259 260 In some instances, products will want specific environment variables set during the build phase. These can be specified 261 using the `environment` map, where the key specifies the name of the environment variable and the value specifies the 262 value of the environment variable. For example, the following configuration sets `CGO_ENABLED` to `0`: 263 264 ```yaml 265 products: 266 echgo: 267 build: 268 main-pkg: . 269 environment: 270 CGO_ENABLED: "0" 271 ``` 272 273 ### Specify build arguments 274 275 In some cases, it is desirable to have values that are dynamically computed passed to the `build` command. It is 276 possible to specify a script that will be executed to generate the arguments that are passed to the build script by 277 using the `build-args-script` configuration key. The content of the script is evaluated when `build` is run for the 278 product and each line of output is passed as a separate argument to the `build` command. For example, consider the 279 following configuration: 280 281 ```yaml 282 products: 283 echgo: 284 build: 285 main-pkg: . 286 build-args-script: | 287 YEAR=$(date +%Y) 288 echo "-ldflags" 289 echo "-X" 290 echo "main.year=$YEAR" 291 ``` 292 293 This configuration evaluates `$(date +%Y)` when the `echgo` product is built and passes the arguments "-ldflags" "-X" 294 "main.year=$YEAR" to the build command.