about summary refs log tree commit diff
path: root/nix/buildGo/README.md
blob: e84ede663bf8e199e00dedede2c74eb69b24632c (plain) (blame)
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
buildGo.nix
===========

This is an alternative [Nix][] build system for [Go][]. It supports building Go
libraries and programs, and even automatically generating Protobuf & gRPC
libraries.

*Note:* This will probably end up being folded into [Nixery][].

## Background

Most language-specific Nix tooling outsources the build to existing
language-specific build tooling, which essentially means that Nix ends up being
a wrapper around all sorts of external build systems.

However, systems like [Bazel][] take an alternative approach in which the
compiler is invoked directly and the composition of programs and libraries stays
within a single homogeneous build system.

Users don't need to learn per-language build systems and especially for
companies with large monorepo-setups ([like Google][]) this has huge
productivity impact.

This project is an attempt to prove that Nix can be used in a similar style to
build software directly, rather than shelling out to other build systems.

## Example

Given a program layout like this:

```
.
├── lib          <-- some library component
│   ├── bar.go
│   └── foo.go
├── api.proto    <-- gRPC API definition
├── main.go      <-- program implementation
└── default.nix  <-- build instructions
```

The contents of `default.nix` could look like this:

```nix
{ buildGo }:

let
  api = buildGo.grpc {
    name  = "someapi";
    proto = ./api.proto;
  };

  lib = buildGo.package {
    name = "somelib";
    srcs = [
      ./lib/bar.go
      ./lib/foo.go
    ];
  };
in buildGo.program {
  name = "my-program";
  deps = [ api lib ];

  srcs = [
    ./main.go
  ];
}
```

(If you don't know how to read Nix, check out [nix-1p][])

## Usage

`buildGo` exposes five different functions:

* `buildGo.program`: Build a Go binary out of the specified source files.

  | parameter | type                    | use                                            | required? |
  |-----------|-------------------------|------------------------------------------------|-----------|
  | `name`    | `string`                | Name of the program (and resulting executable) | yes       |
  | `srcs`    | `list<path>`            | List of paths to source files                  | yes       |
  | `deps`    | `list<drv>`             | List of dependencies (i.e. other Go libraries) | no        |
  | `x_defs`  | `attrs<string, string>` | Attribute set of linker vars (i.e. `-X`-flags) | no        |

* `buildGo.package`: Build a Go library out of the specified source files.

  | parameter | type         | use                                            | required? |
  |-----------|--------------|------------------------------------------------|-----------|
  | `name`    | `string`     | Name of the library (and resulting executable) | yes       |
  | `srcs`    | `list<path>` | List of paths to source files                  | yes       |
  | `deps`    | `list<drv>`  | List of dependencies (i.e. other Go libraries) | no        |
  | `path`    | `string`     | Go import path for the resulting library       | no        |

* `buildGo.external`: Build an externally defined Go library or program.

  This function performs analysis on the supplied source code (which
  can use the standard Go tooling layout) and creates a tree of all
  the packages contained within.

  This exists for compatibility with external libraries that were not
  defined using buildGo.

  | parameter | type           | use                                           | required? |
  |-----------|----------------|-----------------------------------------------|-----------|
  | `path`    | `string`       | Go import path for the resulting package      | yes       |
  | `src`     | `path`         | Path to the source **directory**              | yes       |
  | `deps`    | `list<drv>`    | List of dependencies (i.e. other Go packages) | no        |

  For some examples of how `buildGo.external` is used, check out
  [`proto.nix`](./proto.nix).

* `buildGo.proto`: Build a Go library out of the specified Protobuf definition.

  | parameter   | type        | use                                              | required? |
  |-------------|-------------|--------------------------------------------------|-----------|
  | `name`      | `string`    | Name for the resulting library                   | yes       |
  | `proto`     | `path`      | Path to the Protobuf definition file             | yes       |
  | `path`      | `string`    | Import path for the resulting Go library         | no        |
  | `extraDeps` | `list<drv>` | Additional Go dependencies to add to the library | no        |

* `buildGo.grpc`: Build a Go library out of the specified gRPC definition.

  The parameters are identical to `buildGo.proto`.

## Current status

This project is work-in-progress. Crucially it is lacking the following features:

* feature flag parity with Bazel's Go rules
* documentation building
* test execution

There are still some open questions around how to structure some of those
features in Nix.

[Nix]: https://nixos.org/nix/
[Go]: https://golang.org/
[Nixery]: https://github.com/google/nixery
[Bazel]: https://bazel.build/
[like Google]: https://ai.google/research/pubs/pub45424
[nix-1p]: https://github.com/tazjin/nix-1p