about summary refs log tree commit diff
path: root/README.md
blob: 489cf128173f744720d45e2d80d4c3b5d73db0cb (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
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 a Go library or program using standard `go` tooling.

  This exists for compatibility with complex external dependencies. In theory it
  is possible to write `buildGo.package` specifications for each subpackage of
  an external dependency, but it is often cumbersome to do so.

  | parameter | type           | use                                            | required? |
  |-----------|----------------|------------------------------------------------|-----------|
  | `path`    | `string`       | Go import path for the resulting library       | yes       |
  | `src`     | `path`         | Path to the source **directory**               | yes       |
  | `deps`    | `list<drv>`    | List of dependencies (i.e. other Go libraries) | no        |
  | `srcOnly` | `bool`         | Only copy sources, do not perform a build.     | no        |
  | `targets` | `list<string>` | Sub-packages to build (defaults to all)        | 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