diff --git a/buildGo.nix b/buildGo.nix new file mode 100644 index 000000000..090627c59 --- /dev/null +++ b/buildGo.nix @@ -0,0 +1,70 @@ +# Copyright 2019 Google LLC. +# SPDX-License-Identifier: Apache-2.0 +# +# buildGo provides Nix functions to build Go packages in the style of Bazel's +# rules_go. + +{ pkgs ? import {} +, ... }: + +let + inherit (builtins) + attrNames + baseNameOf + elemAt + filter + map + match + readDir; + + inherit (pkgs) lib go runCommand; + + # 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); + + srcBasename = src: elemAt (match "([a-z0-9]{32}\-)?(.*\.go)" (baseNameOf src)) 1; + 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))); + + # High-level build functions + + # Build a Go program out of the specified files and dependencies. + program = { name, srcs, deps ? [] }: + let uniqueDeps = allDeps deps; + in runCommand name {} '' + ${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD -trimpath=${go} ${includeSources uniqueDeps} ${spaceOut srcs} + mkdir -p $out/bin + ${go}/bin/go tool link -o $out/bin/${name} -buildid nix ${includeLibs uniqueDeps} ${name}.a + ''; + + # 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)} + ${go}/bin/go tool compile -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs} + '') // { goDeps = uniqueDeps; }; +in { + # Only the high-level builder functions are exposed + inherit program package; +}