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.