2019-11-25 16:34:59 +01:00
|
|
|
# Copyright 2019 Google LLC.
|
|
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
|
|
#
|
2019-11-21 11:55:10 +01:00
|
|
|
# buildGo provides Nix functions to build Go packages in the style of Bazel's
|
|
|
|
# rules_go.
|
|
|
|
#
|
|
|
|
# TODO(tazjin): Go through Bazel rules_go options and implement corresponding flags
|
|
|
|
# TODO(tazjin): Refactor to include /golang/protobuf/descriptor in goProto deps
|
2019-11-22 17:14:14 +01:00
|
|
|
# TODO(tazjin): Find a way to expose documentation (esp. for generated stuff)
|
2019-11-21 11:55:10 +01:00
|
|
|
|
2019-11-25 16:34:59 +01:00
|
|
|
{ pkgs, ... }:
|
2019-11-21 11:55:10 +01:00
|
|
|
|
|
|
|
let
|
|
|
|
inherit (builtins)
|
|
|
|
attrNames
|
|
|
|
baseNameOf
|
2019-11-22 17:14:14 +01:00
|
|
|
elemAt
|
2019-11-21 11:55:10 +01:00
|
|
|
filter
|
|
|
|
map
|
|
|
|
match
|
|
|
|
readDir
|
2019-11-22 17:14:14 +01:00
|
|
|
replaceStrings
|
|
|
|
toPath;
|
2019-11-21 11:55:10 +01:00
|
|
|
|
2019-11-25 16:34:59 +01:00
|
|
|
inherit (pkgs) lib go runCommand fetchFromGitHub protobuf;
|
2019-11-21 11:55:10 +01:00
|
|
|
|
|
|
|
# Helpers for low-level Go compiler invocations
|
|
|
|
spaceOut = lib.concatStringsSep " ";
|
|
|
|
|
|
|
|
includeDepSrc = dep: "-I ${dep}";
|
|
|
|
includeSources = deps: spaceOut (map includeDepSrc deps);
|
|
|
|
|
|
|
|
includeDepLib = dep: "-L ${dep}";
|
|
|
|
includeLibs = deps: spaceOut (map includeDepLib deps);
|
|
|
|
|
2019-11-22 17:14:35 +01:00
|
|
|
srcBasename = src: elemAt (match "([a-z0-9]{32}\-)?(.*\.go)" (baseNameOf src)) 1;
|
2019-11-21 11:55:10 +01:00
|
|
|
srcCopy = path: src: "cp ${src} $out/${path}/${srcBasename src}";
|
|
|
|
srcList = path: srcs: lib.concatStringsSep "\n" (map (srcCopy path) srcs);
|
|
|
|
|
|
|
|
isGoFile = f: (match ".*\.go" f) != null;
|
|
|
|
isGoTest = f: (match ".*_test\.go" f) != null;
|
|
|
|
goFileFilter = k: v: (v == "regular") && (isGoFile k) && (!isGoTest k);
|
|
|
|
goFilesIn = dir:
|
|
|
|
let files = readDir dir;
|
|
|
|
goFiles = filter (f: goFileFilter f files."${f}") (attrNames files);
|
|
|
|
in map (f: dir + "/" + f) goFiles;
|
|
|
|
|
|
|
|
allDeps = deps: lib.unique (lib.flatten (deps ++ (map (d: d.goDeps) deps)));
|
|
|
|
|
2019-11-25 16:34:59 +01:00
|
|
|
xFlags = x_defs: spaceOut (map (k: "-X ${k}=${x_defs."${k}"}") (attrNames x_defs));
|
|
|
|
|
2019-11-21 11:55:10 +01:00
|
|
|
# High-level build functions
|
|
|
|
|
|
|
|
# Build a Go program out of the specified files and dependencies.
|
2019-11-25 16:34:59 +01:00
|
|
|
program = { name, srcs, deps ? [], x_defs ? {} }:
|
2019-11-21 11:55:10 +01:00
|
|
|
let uniqueDeps = allDeps deps;
|
|
|
|
in runCommand name {} ''
|
2019-11-22 17:14:52 +01:00
|
|
|
${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD -trimpath=${go} ${includeSources uniqueDeps} ${spaceOut srcs}
|
2019-11-21 11:55:10 +01:00
|
|
|
mkdir -p $out/bin
|
2019-11-25 16:34:59 +01:00
|
|
|
${go}/bin/go tool link -o $out/bin/${name} -buildid nix ${xFlags x_defs} ${includeLibs uniqueDeps} ${name}.a
|
2019-11-21 11:55:10 +01:00
|
|
|
'';
|
|
|
|
|
|
|
|
# Build a Go library assembled out of the specified files.
|
|
|
|
#
|
|
|
|
# This outputs both the sources and compiled binary, as both are
|
|
|
|
# needed when downstream packages depend on it.
|
|
|
|
package = { name, srcs, deps ? [], path ? name }:
|
|
|
|
let uniqueDeps = allDeps deps;
|
|
|
|
in (runCommand "golib-${name}" {} ''
|
|
|
|
mkdir -p $out/${path}
|
|
|
|
${srcList path (map (s: "${s}") srcs)}
|
2019-11-22 17:14:14 +01:00
|
|
|
${go}/bin/go tool compile -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs}
|
2019-11-21 11:55:10 +01:00
|
|
|
'') // { goDeps = uniqueDeps; };
|
|
|
|
|
2019-11-22 17:14:14 +01:00
|
|
|
# Build a Go library out of the specified protobuf definition.
|
|
|
|
proto = { name, proto, path ? name, protocFlags ? "", extraDeps ? [] }: package {
|
2019-11-21 11:55:10 +01:00
|
|
|
inherit name path;
|
2019-11-22 17:14:14 +01:00
|
|
|
deps = [ goProto ] ++ extraDeps;
|
2019-11-21 11:55:10 +01:00
|
|
|
srcs = lib.singleton (runCommand "goproto-${name}.pb.go" {} ''
|
|
|
|
cp ${proto} ${baseNameOf proto}
|
|
|
|
${protobuf}/bin/protoc --plugin=${protocGo}/bin/protoc-gen-go \
|
2019-11-22 17:14:14 +01:00
|
|
|
--go_out=${protocFlags}import_path=${baseNameOf path}:. ${baseNameOf proto}
|
2019-11-21 11:55:10 +01:00
|
|
|
mv *.pb.go $out
|
|
|
|
'');
|
|
|
|
};
|
|
|
|
|
|
|
|
# Protobuf & gRPC integration requires these dependencies:
|
|
|
|
proto-go-src = fetchFromGitHub {
|
|
|
|
owner = "golang";
|
|
|
|
repo = "protobuf";
|
|
|
|
rev = "ed6926b37a637426117ccab59282c3839528a700";
|
|
|
|
sha256 = "0fynqrim022x9xi2bivkw19npbz4316v4yr7mb677s9s36z4dc4h";
|
|
|
|
};
|
|
|
|
|
2019-11-22 17:14:14 +01:00
|
|
|
protoPart = path: deps: package {
|
|
|
|
inherit deps;
|
|
|
|
name = replaceStrings ["/"] ["_"] path;
|
|
|
|
path = "github.com/golang/protobuf/${path}";
|
|
|
|
srcs = goFilesIn (toPath "${proto-go-src}/${path}");
|
|
|
|
};
|
|
|
|
|
2019-11-21 11:55:10 +01:00
|
|
|
goProto =
|
|
|
|
let
|
|
|
|
protobuf = package {
|
|
|
|
name = "protobuf";
|
|
|
|
path = "github.com/golang/protobuf/proto";
|
2019-11-22 17:14:14 +01:00
|
|
|
# TODO(tazjin): How does this build toggle work?
|
2019-11-21 11:55:10 +01:00
|
|
|
srcs = filter
|
|
|
|
(f: (match "(.*)/pointer_reflect.go" f) == null)
|
|
|
|
(goFilesIn (toPath "${proto-go-src}/proto"));
|
|
|
|
};
|
2019-11-22 17:14:14 +01:00
|
|
|
type = name: protoPart "ptypes/${name}" [ protobuf ];
|
|
|
|
descriptor = protoPart "descriptor" [ protobuf ];
|
2019-11-21 11:55:10 +01:00
|
|
|
ptypes = package {
|
|
|
|
name = "ptypes";
|
|
|
|
path = "github.com/golang/protobuf/ptypes";
|
|
|
|
srcs = goFilesIn (toPath "${proto-go-src}/ptypes");
|
|
|
|
deps = map type [
|
|
|
|
"any"
|
|
|
|
"duration"
|
|
|
|
"empty"
|
|
|
|
"struct"
|
|
|
|
"timestamp"
|
|
|
|
"wrappers"
|
|
|
|
];
|
|
|
|
};
|
|
|
|
in protobuf // { goDeps = allDeps (protobuf.goDeps ++ [ ptypes ]); };
|
|
|
|
|
2019-11-22 17:14:14 +01:00
|
|
|
protocDescriptor = (protoPart "protoc-gen-go/descriptor" [ goProto ]);
|
2019-11-21 11:55:10 +01:00
|
|
|
protocGo =
|
|
|
|
let
|
2019-11-22 17:14:14 +01:00
|
|
|
generator = protoPart "protoc-gen-go/generator" [
|
|
|
|
(protoPart "protoc-gen-go/generator/internal/remap" [])
|
|
|
|
(protoPart "protoc-gen-go/plugin" [ protocDescriptor ])
|
|
|
|
];
|
|
|
|
grpc = protoPart "protoc-gen-go/grpc" [ generator ];
|
2019-11-21 11:55:10 +01:00
|
|
|
in program {
|
|
|
|
name = "protoc-gen-go";
|
|
|
|
deps = [ goProto grpc generator ];
|
|
|
|
srcs = filter
|
|
|
|
(f: (match "(.*)/doc.go" f) == null)
|
|
|
|
(goFilesIn (toPath "${proto-go-src}/protoc-gen-go"));
|
|
|
|
};
|
|
|
|
in {
|
|
|
|
# Only the high-level builder functions are exposed
|
|
|
|
inherit program package proto;
|
|
|
|
}
|