2019-11-23 16:25:11 +01:00
|
|
|
# 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 <nixpkgs> { }
|
|
|
|
, ...
|
|
|
|
}:
|
|
|
|
|
|
|
|
let
|
|
|
|
inherit (builtins)
|
|
|
|
attrNames
|
|
|
|
baseNameOf
|
2019-11-25 17:42:49 +01:00
|
|
|
dirOf
|
2019-11-23 16:25:11 +01:00
|
|
|
elemAt
|
|
|
|
filter
|
2019-12-09 01:27:05 +01:00
|
|
|
listToAttrs
|
2019-11-23 16:25:11 +01:00
|
|
|
map
|
|
|
|
match
|
2019-11-24 21:17:17 +01:00
|
|
|
readDir
|
2019-12-09 01:27:05 +01:00
|
|
|
replaceStrings
|
|
|
|
toString;
|
2019-11-23 16:25:11 +01:00
|
|
|
|
2022-10-30 22:28:02 +01:00
|
|
|
inherit (pkgs) lib runCommand fetchFromGitHub protobuf symlinkJoin;
|
|
|
|
|
2023-10-24 22:36:18 +02:00
|
|
|
# TODO: Adapt to Go 1.20 changes
|
|
|
|
go = pkgs.go_1_19;
|
2019-11-23 16:25:11 +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);
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
allDeps = deps: lib.unique (lib.flatten (deps ++ (map (d: d.goDeps) deps)));
|
|
|
|
|
2019-11-24 21:41:01 +01:00
|
|
|
xFlags = x_defs: spaceOut (map (k: "-X ${k}=${x_defs."${k}"}") (attrNames x_defs));
|
|
|
|
|
2019-11-25 17:42:49 +01:00
|
|
|
pathToName = p: replaceStrings [ "/" ] [ "_" ] (toString p);
|
|
|
|
|
2019-12-09 01:51:27 +01:00
|
|
|
# Add an `overrideGo` attribute to a function result that works
|
|
|
|
# similar to `overrideAttrs`, but is used specifically for the
|
|
|
|
# arguments passed to Go builders.
|
|
|
|
makeOverridable = f: orig: (f orig) // {
|
|
|
|
overrideGo = new: makeOverridable f (orig // (new orig));
|
|
|
|
};
|
|
|
|
|
2019-11-23 16:25:11 +01:00
|
|
|
# High-level build functions
|
|
|
|
|
|
|
|
# Build a Go program out of the specified files and dependencies.
|
2019-11-24 21:41:01 +01:00
|
|
|
program = { name, srcs, deps ? [ ], x_defs ? { } }:
|
2020-08-03 20:42:42 +02:00
|
|
|
let uniqueDeps = allDeps (map (d: d.gopkg) deps);
|
2019-11-23 16:25:11 +01:00
|
|
|
in runCommand name { } ''
|
2023-10-24 22:36:18 +02:00
|
|
|
${go}/bin/go tool compile -o ${name}.a -trimpath=$PWD -trimpath=${go} -p main ${includeSources uniqueDeps} ${spaceOut srcs}
|
2019-11-23 16:25:11 +01:00
|
|
|
mkdir -p $out/bin
|
2020-03-31 02:29:35 +02:00
|
|
|
export GOROOT_FINAL=go
|
2019-11-24 21:41:01 +01:00
|
|
|
${go}/bin/go tool link -o $out/bin/${name} -buildid nix ${xFlags x_defs} ${includeLibs uniqueDeps} ${name}.a
|
2019-11-23 16:25:11 +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.
|
2019-12-13 16:15:22 +01:00
|
|
|
package = { name, srcs, deps ? [ ], path ? name, sfiles ? [ ] }:
|
2019-12-13 22:23:41 +01:00
|
|
|
let
|
2020-08-03 20:42:42 +02:00
|
|
|
uniqueDeps = allDeps (map (d: d.gopkg) deps);
|
2022-01-30 17:06:58 +01:00
|
|
|
|
2019-12-13 22:23:41 +01:00
|
|
|
# The build steps below need to be executed conditionally for Go
|
|
|
|
# assembly if the analyser detected any *.s files.
|
|
|
|
#
|
|
|
|
# This is required for several popular packages (e.g. x/sys).
|
2020-01-24 14:30:12 +01:00
|
|
|
ifAsm = do: lib.optionalString (sfiles != [ ]) do;
|
2019-12-13 22:23:41 +01:00
|
|
|
asmBuild = ifAsm ''
|
2023-10-24 22:36:18 +02:00
|
|
|
${go}/bin/go tool asm -p ${path} -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -gensymabis -o ./symabis ${spaceOut sfiles}
|
|
|
|
${go}/bin/go tool asm -p ${path} -trimpath $PWD -I $PWD -I ${go}/share/go/pkg/include -D GOOS_linux -D GOARCH_amd64 -o ./asm.o ${spaceOut sfiles}
|
2019-12-13 22:23:41 +01:00
|
|
|
'';
|
|
|
|
asmLink = ifAsm "-symabis ./symabis -asmhdr $out/go_asm.h";
|
|
|
|
asmPack = ifAsm ''
|
|
|
|
${go}/bin/go tool pack r $out/${path}.a ./asm.o
|
|
|
|
'';
|
2022-01-30 17:06:58 +01:00
|
|
|
|
2020-08-03 20:38:04 +02:00
|
|
|
gopkg = (runCommand "golib-${name}" { } ''
|
|
|
|
mkdir -p $out/${path}
|
|
|
|
${srcList path (map (s: "${s}") srcs)}
|
|
|
|
${asmBuild}
|
|
|
|
${go}/bin/go tool compile -pack ${asmLink} -o $out/${path}.a -trimpath=$PWD -trimpath=${go} -p ${path} ${includeSources uniqueDeps} ${spaceOut srcs}
|
|
|
|
${asmPack}
|
2022-02-02 11:24:37 +01:00
|
|
|
'').overrideAttrs (_: {
|
|
|
|
passthru = {
|
|
|
|
inherit gopkg;
|
|
|
|
goDeps = uniqueDeps;
|
|
|
|
goImportPath = path;
|
|
|
|
};
|
|
|
|
});
|
2020-08-03 20:38:04 +02:00
|
|
|
in
|
|
|
|
gopkg;
|
2019-11-24 21:17:17 +01:00
|
|
|
|
2019-12-13 00:07:42 +01:00
|
|
|
# Build a tree of Go libraries out of an external Go source
|
|
|
|
# directory that follows the standard Go layout and was not built
|
|
|
|
# with buildGo.nix.
|
|
|
|
#
|
2019-12-13 00:27:43 +01:00
|
|
|
# The derivation for each actual package will reside in an attribute
|
|
|
|
# named "gopkg", and an attribute named "gobin" for binaries.
|
2019-12-13 00:07:42 +01:00
|
|
|
external = import ./external { inherit pkgs program package; };
|
|
|
|
|
2019-11-23 16:25:11 +01:00
|
|
|
in
|
|
|
|
{
|
2019-12-09 01:51:27 +01:00
|
|
|
# Only the high-level builder functions are exposed, but made
|
|
|
|
# overrideable.
|
|
|
|
program = makeOverridable program;
|
|
|
|
package = makeOverridable package;
|
|
|
|
external = makeOverridable external;
|
2023-10-29 11:24:10 +01:00
|
|
|
|
|
|
|
# re-expose the Go version used
|
|
|
|
inherit go;
|
2019-11-23 16:25:11 +01:00
|
|
|
}
|