summary refs log tree commit diff
path: root/pkgs/stdenv/generic/make-derivation.nix
blob: be271daf8c8eba4cfa8d31ee0d020fb84bbc7722 (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
{ lib, config, stdenv }:

rec {
  # `mkDerivation` wraps the builtin `derivation` function to
  # produce derivations that use this stdenv and its shell.
  #
  # See also:
  #
  # * https://nixos.org/nixpkgs/manual/#sec-using-stdenv
  #   Details on how to use this mkDerivation function
  #
  # * https://nixos.org/nix/manual/#ssec-derivation
  #   Explanation about derivations in general
  mkDerivation =
    { name ? ""

    , nativeBuildInputs ? []
    , buildInputs ? []

    , propagatedNativeBuildInputs ? []
    , propagatedBuildInputs ? []

    , configureFlags ? []
    , # Target is not included by default because most programs don't care.
      # Including it then would cause needless mass rebuilds.
      #
      # TODO(@Ericson2314): Make [ "build" "host" ] always the default.
      configurePlatforms ? lib.optionals
        (stdenv.hostPlatform != stdenv.buildPlatform)
        [ "build" "host" ]
    , crossConfig ? null
    , meta ? {}
    , passthru ? {}
    , pos ? # position used in error messages and for meta.position
        (if attrs.meta.description or null != null
          then builtins.unsafeGetAttrPos "description" attrs.meta
          else builtins.unsafeGetAttrPos "name" attrs)
    , separateDebugInfo ? false
    , outputs ? [ "out" ]
    , __impureHostDeps ? []
    , __propagatedImpureHostDeps ? []
    , sandboxProfile ? ""
    , propagatedSandboxProfile ? ""
    , ... } @ attrs:
    let
      dependencies = [
        (map (drv: drv.nativeDrv or drv) nativeBuildInputs)
        (map (drv: drv.crossDrv or drv) buildInputs)
      ];
      propagatedDependencies = [
        (map (drv: drv.nativeDrv or drv) propagatedNativeBuildInputs)
        (map (drv: drv.crossDrv or drv) propagatedBuildInputs)
      ];
    in let

      outputs' =
        outputs ++
        (if separateDebugInfo then assert stdenv.hostPlatform.isLinux; [ "debug" ] else []);

      dependencies' = let
          justMap = map lib.chooseDevOutputs dependencies;
          nativeBuildInputs = lib.head justMap
            ++ lib.optional separateDebugInfo ../../build-support/setup-hooks/separate-debug-info.sh
            ++ lib.optional stdenv.hostPlatform.isWindows ../../build-support/setup-hooks/win-dll-link.sh;
        in [ nativeBuildInputs ] ++ lib.tail justMap;

      propagatedDependencies' = map lib.chooseDevOutputs propagatedDependencies;

      derivationArg =
        (removeAttrs attrs
          ["meta" "passthru" "crossAttrs" "pos"
           "__impureHostDeps" "__propagatedImpureHostDeps"
           "sandboxProfile" "propagatedSandboxProfile"])
        // (let
          computedSandboxProfile =
            lib.concatMap (input: input.__propagatedSandboxProfile or []) (stdenv.extraBuildInputs ++ lib.concatLists dependencies');
          computedPropagatedSandboxProfile =
            lib.concatMap (input: input.__propagatedSandboxProfile or []) (lib.concatLists propagatedDependencies');
          computedImpureHostDeps =
            lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (stdenv.extraBuildInputs ++ lib.concatLists dependencies'));
          computedPropagatedImpureHostDeps =
            lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (lib.concatLists propagatedDependencies'));
        in
        {
          name = name + lib.optionalString
            (stdenv.hostPlatform != stdenv.buildPlatform)
            stdenv.hostPlatform.config;
          builder = attrs.realBuilder or stdenv.shell;
          args = attrs.args or ["-e" (attrs.builder or ./default-builder.sh)];
          inherit stdenv;
          inherit (stdenv) system;
          userHook = config.stdenv.userHook or null;
          __ignoreNulls = true;

          nativeBuildInputs = lib.elemAt dependencies' 0;
          buildInputs = lib.elemAt dependencies' 1;

          propagatedNativeBuildInputs = lib.elemAt propagatedDependencies' 0;
          propagatedBuildInputs = lib.elemAt propagatedDependencies' 1;

          # This parameter is sometimes a string, sometimes null, and sometimes a list, yuck
          configureFlags = let inherit (lib) optional elem; in
            (/**/ if lib.isString configureFlags then [configureFlags]
             else if configureFlags == null      then []
             else                                     configureFlags)
            ++ optional (elem "build"  configurePlatforms) "--build=${stdenv.buildPlatform.config}"
            ++ optional (elem "host"   configurePlatforms) "--host=${stdenv.hostPlatform.config}"
            ++ optional (elem "target" configurePlatforms) "--target=${stdenv.targetPlatform.config}";

        } // lib.optionalAttrs (stdenv.buildPlatform.isDarwin) {
          # TODO: remove lib.unique once nix has a list canonicalization primitive
          __sandboxProfile =
          let profiles = [ stdenv.extraSandboxProfile ] ++ computedSandboxProfile ++ computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile sandboxProfile ];
              final = lib.concatStringsSep "\n" (lib.filter (x: x != "") (lib.unique profiles));
          in final;
          __propagatedSandboxProfile = lib.unique (computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile ]);
          __impureHostDeps = computedImpureHostDeps ++ computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps ++ __impureHostDeps ++ stdenv.__extraImpureHostDeps ++ [
            "/dev/zero"
            "/dev/random"
            "/dev/urandom"
            "/bin/sh"
          ];
          __propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps;
        } // (if outputs' != [ "out" ] then {
          outputs = outputs';
        } else { }));

      # The meta attribute is passed in the resulting attribute set,
      # but it's not part of the actual derivation, i.e., it's not
      # passed to the builder and is not a dependency.  But since we
      # include it in the result, it *is* available to nix-env for queries.
      meta = { }
          # If the packager hasn't specified `outputsToInstall`, choose a default,
          # which is the name of `p.bin or p.out or p`;
          # if he has specified it, it will be overridden below in `// meta`.
          #   Note: This default probably shouldn't be globally configurable.
          #   Services and users should specify outputs explicitly,
          #   unless they are comfortable with this default.
        // { outputsToInstall =
          let
            outs = outputs'; # the value passed to derivation primitive
            hasOutput = out: builtins.elem out outs;
          in [( lib.findFirst hasOutput null (["bin" "out"] ++ outs) )];
        }
        // attrs.meta or {}
          # Fill `meta.position` to identify the source location of the package.
        // lib.optionalAttrs (pos != null)
          { position = pos.file + ":" + toString pos.line; }
        ;

    in

      lib.addPassthru
        (derivation (import ./check-meta.nix
          {
            inherit lib config meta derivationArg;
            mkDerivationArg = attrs;
            # Nix itself uses the `system` field of a derivation to decide where
            # to build it. This is a bit confusing for cross compilation.
            inherit (stdenv) system;
          }))
        ( {
            overrideAttrs = f: mkDerivation (attrs // (f attrs));
            inherit meta passthru;
          } //
          # Pass through extra attributes that are not inputs, but
          # should be made available to Nix expressions using the
          # derivation (e.g., in assertions).
          passthru);
}