WIP. Posting just to make sure people know this is something I'd like to do. Context: https://matrix.to/#/!PvnunzXUk4Vm1CmKS4:auxolotl.org/$bOm6iaBpWbo-KRJgo7FUZdeFIv9StzRHxklbx7OQ23g?via=auxolotl.org&via=matrix.org&via=catgirl.cloud Reasons: 1. Why should GCC inflict complication upon all of tidepool just because of its own architectural deficiencies? 2. Most other compilers are multi-target so it doesn't matter 2. Target is useless for 99.9% of packages and only leads to user confusion, especially since many compilers also call what would be host here "target". 3. Canadian-cross is not very well supported. GCC barely supports it, and is broken in many cases. Nixpkgs does not support it (regardless of what its API may imply) and no one has ever complained. Plan: 1. Remove most target related things. No reason to have it. 2. Add configuration parameter on GCC that selects its target What does this mean: This basically moves target to be a GCC-specific artifact rather than an official parameter every package must endure the cognitive load of. This is because it is. Nixpkgs plans on dumping target in the future as well because of this. Or at least making it an alias. If you want to create a compiler with a different target, then override GCC to do so. No need to pervade all of tidepool just for GCC. Co-authored-by: Victor Fuentes <vlinkz@snowflakeos.org> Reviewed-on: #31 Reviewed-by: vlinkz <vlinkz@snowflakeos.org> Co-authored-by: Ross Smyth <snix@treefroog.com> Co-committed-by: Ross Smyth <snix@treefroog.com>
834 lines
28 KiB
Nix
834 lines
28 KiB
Nix
{ config }@global:
|
|
let
|
|
inherit (config) lib;
|
|
|
|
pretty = lib.generators.pretty { };
|
|
in
|
|
{
|
|
config = {
|
|
lib.types = {
|
|
license =
|
|
let
|
|
type = lib.types.submodule (
|
|
{ config }:
|
|
{
|
|
options = {
|
|
|
|
name = lib.options.create {
|
|
description = "The short name of the license.";
|
|
type = lib.types.string;
|
|
};
|
|
|
|
fullName = lib.options.create {
|
|
description = "The full name of the license.";
|
|
type = lib.types.string;
|
|
};
|
|
|
|
spdxId = lib.options.create {
|
|
description = "The SPDX identifier for the license.";
|
|
type = lib.types.nullish lib.types.string;
|
|
default.value = null;
|
|
};
|
|
|
|
url = lib.options.create {
|
|
description = "The URL for the license.";
|
|
type = lib.types.string;
|
|
default = {
|
|
text = "spdx.org entry, if `spdxId` is set, `null` otherwise";
|
|
value = if config.spdxId == null then null else "https://spdx.org/licenses/${config.spdxId}.html";
|
|
};
|
|
};
|
|
|
|
free = lib.options.create {
|
|
description = "Whether the license is free.";
|
|
type = lib.types.bool;
|
|
default.value = true;
|
|
};
|
|
|
|
redistributable = lib.options.create {
|
|
description = "Whether the license is allows redistribution.";
|
|
type = lib.types.bool;
|
|
default = {
|
|
text = "config.free";
|
|
value = config.free;
|
|
};
|
|
};
|
|
};
|
|
}
|
|
);
|
|
in
|
|
lib.types.either type (lib.types.list.of type);
|
|
|
|
context = lib.types.submodule {
|
|
options = global.config.packages.context.options;
|
|
};
|
|
|
|
settings = lib.types.submodule {
|
|
options = global.config.packages.settings.options;
|
|
};
|
|
|
|
platform =
|
|
lib.types.coerce lib.types.string lib.systems.withBuildInfo
|
|
lib.systems.types.platformWithBuildInfo;
|
|
|
|
builder =
|
|
let
|
|
normalize =
|
|
value:
|
|
if builtins.isNull value then
|
|
{ }
|
|
else if builtins.isPath value then
|
|
{ includes = [ value ]; }
|
|
else if builtins.isFunction value || builtins.isList value then
|
|
value
|
|
else if value ? __modules__ then
|
|
value.__modules__
|
|
else
|
|
{ config = value; };
|
|
|
|
initial = lib.types.create {
|
|
name = "BuilderConfig";
|
|
description = "configuration for a builder";
|
|
check =
|
|
value:
|
|
builtins.isFunction value
|
|
|| builtins.isAttrs value
|
|
|| builtins.isList value
|
|
|| builtins.isNull value
|
|
|| builtins.isPath value;
|
|
merge =
|
|
location: definitions:
|
|
let
|
|
normalized = builtins.map (definition: lib.lists.from.any (normalize definition.value)) definitions;
|
|
in
|
|
builtins.concatLists normalized;
|
|
};
|
|
|
|
transform =
|
|
location: value:
|
|
let
|
|
modules = lib.lists.from.any (normalize value);
|
|
|
|
result = lib.modules.run {
|
|
prefix = location;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = modules ++ [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
];
|
|
};
|
|
in
|
|
result.config;
|
|
|
|
final = lib.types.raw // {
|
|
merge =
|
|
location: definitions:
|
|
let
|
|
modules = builtins.concatMap (
|
|
definition: lib.lists.from.any (normalize definition.value)
|
|
) definitions;
|
|
|
|
result = lib.modules.run {
|
|
prefix = location;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = modules ++ [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
];
|
|
};
|
|
in
|
|
result.config;
|
|
};
|
|
|
|
submodule =
|
|
{
|
|
config,
|
|
meta,
|
|
name ? "builder",
|
|
}:
|
|
{
|
|
options = {
|
|
__modules__ = lib.options.create {
|
|
description = "User specified modules for the builder definition.";
|
|
type = lib.types.list.of (initial // { merge = lib.options.merge.one; });
|
|
internal = true;
|
|
default.value = [ ];
|
|
};
|
|
|
|
extend = lib.options.create {
|
|
description = "Extend the package definition.";
|
|
type = lib.types.function lib.types.raw;
|
|
default.value =
|
|
module:
|
|
let
|
|
normalized =
|
|
if builtins.isList module then
|
|
module
|
|
else if builtins.isFunction module || module ? config then
|
|
[ module ]
|
|
else
|
|
[
|
|
{
|
|
config = module;
|
|
}
|
|
];
|
|
|
|
modules = config.__modules__ ++ normalized;
|
|
|
|
result = lib.modules.run {
|
|
prefix = meta.prefix;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
]
|
|
++ modules;
|
|
};
|
|
in
|
|
result.config;
|
|
};
|
|
|
|
name = lib.options.create {
|
|
description = "The name of the builder.";
|
|
type = lib.types.string;
|
|
default = lib.attrs.when (name != "builder") {
|
|
value = name;
|
|
};
|
|
writable = false;
|
|
};
|
|
|
|
build = lib.options.create {
|
|
description = "The build function which takes a package definition and creates a derivation.";
|
|
type = lib.types.function lib.types.artifact;
|
|
};
|
|
|
|
settings = lib.options.create {
|
|
description = "The settings for the builder.";
|
|
type = lib.types.submodule ({ config }: { });
|
|
default.value = { };
|
|
};
|
|
};
|
|
};
|
|
|
|
type = (lib.types.coerceWithLocation initial transform final) // {
|
|
name = "Builder";
|
|
description = "a builder";
|
|
};
|
|
in
|
|
type
|
|
// {
|
|
children = type.children // {
|
|
inherit submodule;
|
|
};
|
|
};
|
|
|
|
aliases =
|
|
let
|
|
normalize =
|
|
value:
|
|
if builtins.isNull value then
|
|
{ }
|
|
else if builtins.isPath value then
|
|
{ includes = [ value ]; }
|
|
else if builtins.isFunction value || builtins.isList value then
|
|
value
|
|
else if value ? __modules__ then
|
|
value.__modules__
|
|
else
|
|
{ config = value; };
|
|
|
|
initial = lib.types.create {
|
|
name = "PackageConfig";
|
|
description = "configuration for a package";
|
|
check =
|
|
value:
|
|
builtins.isFunction value
|
|
|| builtins.isAttrs value
|
|
|| builtins.isList value
|
|
|| builtins.isNull value
|
|
|| builtins.isPath value;
|
|
};
|
|
|
|
transform =
|
|
value:
|
|
let
|
|
result = builtins.mapAttrs (
|
|
namespace: aliases:
|
|
builtins.mapAttrs (
|
|
id: alias:
|
|
alias
|
|
// {
|
|
versions = builtins.mapAttrs (version: package: {
|
|
__modules__ = (lib.lists.from.any (normalize package)) ++ [
|
|
{
|
|
config = {
|
|
id = lib.modules.overrides.default id;
|
|
version = lib.modules.overrides.default version;
|
|
namespace = lib.modules.overrides.default namespace;
|
|
};
|
|
}
|
|
];
|
|
}) alias.versions;
|
|
}
|
|
) aliases
|
|
) value;
|
|
in
|
|
result;
|
|
|
|
final = lib.types.attrs.of (lib.types.attrs.of lib.types.alias);
|
|
in
|
|
lib.types.coerce initial transform final;
|
|
|
|
platforms = {
|
|
build = lib.types.attrs.of lib.types.platforms.host;
|
|
host = lib.types.attrs.of lib.types.platforms.host;
|
|
alias = lib.types.submodule {
|
|
options = {
|
|
stable = lib.options.create {
|
|
description = "The stable version of the artifact.";
|
|
type = lib.types.artifact;
|
|
default.value = null;
|
|
};
|
|
latest = lib.options.create {
|
|
description = "The latest version of the artifact.";
|
|
type = lib.types.artifact;
|
|
default.value = null;
|
|
};
|
|
# NOTE: When adding a version alias here, update lib.packages.WELL_KNOWN_ALIASES
|
|
versions = lib.options.create {
|
|
description = "Available versions of the artifact.";
|
|
type = lib.types.attrs.of lib.types.artifact;
|
|
default.value = { };
|
|
};
|
|
};
|
|
};
|
|
|
|
spec = lib.types.submodule (
|
|
{ config }:
|
|
{
|
|
options = {
|
|
build = lib.options.create {
|
|
description = "The build platform for the package.";
|
|
type = lib.types.string;
|
|
default.value = "@all";
|
|
};
|
|
|
|
host = lib.options.create {
|
|
description = "The host platform for the package.";
|
|
type = lib.types.string;
|
|
default.value = "@build";
|
|
};
|
|
};
|
|
}
|
|
);
|
|
};
|
|
|
|
artifact =
|
|
let
|
|
base = lib.types.derivation // {
|
|
name = "Artifact";
|
|
description = "package artifact";
|
|
};
|
|
in
|
|
lib.types.nullish (
|
|
lib.types.withCheck base (
|
|
value:
|
|
value ? package
|
|
&& builtins.isAttrs value.package
|
|
&& value ? meta
|
|
&& builtins.isAttrs value.meta
|
|
&& value ? extend
|
|
&& builtins.isFunction value.extend
|
|
&& value ? extras
|
|
&& builtins.isAttrs value.extras
|
|
)
|
|
);
|
|
|
|
dependencies =
|
|
let
|
|
type = lib.types.withCheck lib.types.raw lib.types.package.children.final.check;
|
|
entries = type // {
|
|
name = "Dependency";
|
|
description = "a package dependency";
|
|
};
|
|
in
|
|
lib.types.attrs.of entries;
|
|
|
|
alias = lib.types.submodule (
|
|
{ config, name }:
|
|
{
|
|
options = {
|
|
extend = lib.options.create {
|
|
description = "Extend the default version with additional attributes.";
|
|
type = lib.types.function lib.types.raw;
|
|
writable = false;
|
|
default.value =
|
|
let
|
|
default = config.${global.config.preferences.packages.version};
|
|
in
|
|
default.extend
|
|
or (builtins.throw "Package \"${name}\" does not have a ${global.config.preferences.packages.version} release.");
|
|
};
|
|
|
|
stable = lib.options.create {
|
|
description = "The stable version of the package.";
|
|
type = lib.types.package;
|
|
default.value = config.latest;
|
|
};
|
|
|
|
latest = lib.options.create {
|
|
description = "The latest version of the package.";
|
|
type = lib.types.package;
|
|
default.value =
|
|
if config.versions == { } then null else config.versions.${lib.packages.getLatest config};
|
|
};
|
|
|
|
# NOTE: When adding a version alias here, update lib.packages.WELL_KNOWN_ALIASES
|
|
|
|
versions = lib.options.create {
|
|
description = "Available versions of the package.";
|
|
type = lib.types.attrs.of lib.types.package;
|
|
default.value = { };
|
|
};
|
|
};
|
|
}
|
|
);
|
|
|
|
package =
|
|
let
|
|
normalize =
|
|
value:
|
|
if builtins.isNull value then
|
|
{ }
|
|
else if builtins.isPath value then
|
|
{ includes = [ value ]; }
|
|
else if builtins.isFunction value || builtins.isList value then
|
|
value
|
|
else if value ? __modules__ then
|
|
value.__modules__
|
|
else
|
|
{ config = value; };
|
|
|
|
initial = lib.types.create {
|
|
name = "PackageConfig";
|
|
description = "configuration for a package";
|
|
check =
|
|
value:
|
|
builtins.isFunction value
|
|
|| builtins.isAttrs value
|
|
|| builtins.isList value
|
|
|| builtins.isNull value
|
|
|| builtins.isPath value;
|
|
merge =
|
|
location: definitions:
|
|
let
|
|
normalized = builtins.map (definition: lib.lists.from.any (normalize definition.value)) definitions;
|
|
in
|
|
builtins.concatLists normalized;
|
|
};
|
|
|
|
transform =
|
|
location: value:
|
|
let
|
|
modules = lib.lists.from.any (normalize value);
|
|
|
|
result = lib.modules.run {
|
|
prefix = location;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = modules ++ [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
];
|
|
};
|
|
in
|
|
result.config;
|
|
|
|
final = lib.types.raw // {
|
|
merge =
|
|
location: definitions:
|
|
let
|
|
modules = builtins.concatMap (
|
|
definition: lib.lists.from.any (normalize definition.value)
|
|
) definitions;
|
|
|
|
result = lib.modules.run {
|
|
prefix = location;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = modules ++ [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
];
|
|
};
|
|
in
|
|
result.config;
|
|
};
|
|
|
|
deps =
|
|
build: host:
|
|
lib.types.submodule {
|
|
options = {
|
|
build = lib.options.create {
|
|
description = "Dependencies which are executed in the build environment.";
|
|
type = lib.types.dependencies;
|
|
default.value = { };
|
|
};
|
|
host = lib.options.create {
|
|
description = "Dependencies which are executed in the host environment.";
|
|
type = lib.types.dependencies;
|
|
default.value = { };
|
|
};
|
|
};
|
|
};
|
|
|
|
submodule =
|
|
{
|
|
config,
|
|
meta,
|
|
}:
|
|
let
|
|
build = config.platform.build;
|
|
host = config.platform.host;
|
|
in
|
|
{
|
|
options = {
|
|
__modules__ = lib.options.create {
|
|
description = "User specified modules for the package definition.";
|
|
type = lib.types.list.of (initial // { merge = lib.options.merge.one; });
|
|
internal = true;
|
|
default.value = [ ];
|
|
};
|
|
|
|
__toString = lib.options.create {
|
|
description = "The derivation of the package as a string.";
|
|
type = lib.types.function lib.types.string;
|
|
internal = true;
|
|
writable = false;
|
|
default.value = value: builtins.toString value.package;
|
|
};
|
|
|
|
extend = lib.options.create {
|
|
description = "Extend the package definition.";
|
|
type = lib.types.function lib.types.raw;
|
|
default.value =
|
|
module:
|
|
let
|
|
normalized =
|
|
if builtins.isList module then
|
|
module
|
|
else if builtins.isFunction module || module ? config then
|
|
[ module ]
|
|
else
|
|
[
|
|
{
|
|
config = module;
|
|
}
|
|
];
|
|
|
|
modules = config.__modules__ ++ normalized;
|
|
|
|
result = lib.modules.run {
|
|
prefix = meta.prefix;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
]
|
|
++ modules;
|
|
};
|
|
in
|
|
result.config;
|
|
};
|
|
|
|
extendTemporarily = lib.options.create {
|
|
description = "Extend the package definition.";
|
|
type = lib.types.function lib.types.raw;
|
|
internal = true;
|
|
default.value =
|
|
module:
|
|
let
|
|
normalized =
|
|
if builtins.isList module then
|
|
module
|
|
else if builtins.isFunction module || module ? config then
|
|
[ module ]
|
|
else
|
|
[
|
|
{
|
|
config = module;
|
|
}
|
|
];
|
|
|
|
modules = config.__modules__;
|
|
|
|
result = lib.modules.run {
|
|
prefix = meta.prefix;
|
|
|
|
args = {
|
|
global = global.config;
|
|
};
|
|
|
|
modules = [
|
|
submodule
|
|
{ config.__modules__ = modules; }
|
|
{
|
|
config = {
|
|
packages = lib.modules.override 0 config.packages;
|
|
extend = lib.modules.override 0 config.extend;
|
|
extendTemporarily = lib.modules.override 0 config.extendTemporarily;
|
|
};
|
|
}
|
|
]
|
|
++ modules
|
|
++ normalized;
|
|
};
|
|
in
|
|
result.config
|
|
// {
|
|
inherit (config)
|
|
extend
|
|
extendTemporarily
|
|
packages
|
|
;
|
|
};
|
|
};
|
|
|
|
meta = {
|
|
description = lib.options.create {
|
|
description = "The description for the package.";
|
|
type = lib.types.string;
|
|
default.value = "";
|
|
};
|
|
|
|
homepage = lib.options.create {
|
|
description = "The homepage for the package.";
|
|
type = lib.types.nullish lib.types.string;
|
|
default.value = null;
|
|
};
|
|
|
|
license = lib.options.create {
|
|
description = "The license for the package.";
|
|
type = lib.types.nullish lib.types.license;
|
|
default.value = null;
|
|
};
|
|
|
|
free = lib.options.create {
|
|
description = "Whether the package is free.";
|
|
type = lib.types.bool;
|
|
default.value = true;
|
|
};
|
|
|
|
insecure = lib.options.create {
|
|
description = "Whether the package is insecure.";
|
|
type = lib.types.bool;
|
|
default.value = false;
|
|
};
|
|
|
|
broken = lib.options.create {
|
|
description = "Whether the package is broken.";
|
|
type = lib.types.bool;
|
|
default.value = false;
|
|
};
|
|
|
|
main = lib.options.create {
|
|
description = "The main entry point for the package.";
|
|
type = lib.types.nullish lib.types.string;
|
|
default.value = null;
|
|
};
|
|
};
|
|
|
|
extras = lib.options.create {
|
|
description = "Extra information for the package.";
|
|
type = lib.types.attrs.of lib.types.any;
|
|
default.value = { };
|
|
};
|
|
|
|
platforms = lib.options.create {
|
|
description = "The platforms that the package supports.";
|
|
type = lib.types.either lib.types.platforms.spec (lib.types.list.of lib.types.platforms.spec);
|
|
default.value = [ ];
|
|
apply = spec: lib.platforms.from.spec spec;
|
|
};
|
|
|
|
platform =
|
|
let
|
|
initial = builtins.head config.platforms;
|
|
in
|
|
{
|
|
build = lib.options.create {
|
|
description = "The build platform for the package.";
|
|
type = lib.types.string;
|
|
default.value = initial.build or "x86_64-linux";
|
|
};
|
|
|
|
host = lib.options.create {
|
|
description = "The host platform for the package.";
|
|
type = lib.types.string;
|
|
default.value = initial.host or "x86_64-linux";
|
|
};
|
|
};
|
|
|
|
name = lib.options.create {
|
|
description = "The name of the package.";
|
|
type = lib.types.string;
|
|
default = {
|
|
text = "\${config.id}-\${config.version}";
|
|
value = "${config.namespace}-${config.id}-${config.version}";
|
|
};
|
|
};
|
|
|
|
namespace = lib.options.create {
|
|
description = "The namespace that the package belongs to.";
|
|
type = lib.types.string;
|
|
default.value = "unknown";
|
|
};
|
|
|
|
id = lib.options.create {
|
|
description = "The program name for the package";
|
|
type = lib.types.string;
|
|
default.value = "unknown";
|
|
};
|
|
|
|
version = lib.options.create {
|
|
description = "The version for the package.";
|
|
type = lib.types.nullish lib.types.version;
|
|
default.value = "unknown";
|
|
};
|
|
|
|
builder = lib.options.create {
|
|
description = "The builder for the package.";
|
|
type = lib.types.builder;
|
|
};
|
|
|
|
src = lib.options.create {
|
|
description = "The source for the package.";
|
|
type =
|
|
let
|
|
type = lib.types.nullish (
|
|
lib.types.one [
|
|
lib.types.derivation
|
|
lib.types.path
|
|
]
|
|
);
|
|
in
|
|
lib.types.either type (lib.types.attrs.of type);
|
|
default.value = null;
|
|
};
|
|
|
|
outputs = lib.options.create {
|
|
description = "The outputs for the package.";
|
|
type =
|
|
let
|
|
initial = lib.types.attrs.of lib.types.derivation;
|
|
|
|
transform = builtins.attrNames;
|
|
|
|
final = lib.types.list.of lib.types.string;
|
|
in
|
|
lib.types.coerce initial transform final;
|
|
default.value = [ "out" ];
|
|
apply = outputs: lib.attrs.generate outputs (output: config.package.${output});
|
|
};
|
|
|
|
env = lib.options.create {
|
|
description = "The environment for the package.";
|
|
type = lib.types.attrs.of lib.types.string;
|
|
default.value = { };
|
|
};
|
|
|
|
package = lib.options.create {
|
|
description = "The built derivation.";
|
|
type = lib.types.derivation;
|
|
default.value = config.builder.build config;
|
|
};
|
|
|
|
packages = lib.options.create {
|
|
description = "The built derivations for all platforms.";
|
|
type = lib.types.raw;
|
|
writable = false;
|
|
default.value = lib.attrs.generate lib.systems.doubles.all (
|
|
build: lib.attrs.generate lib.systems.doubles.all (host: lib.packages.build config build host)
|
|
);
|
|
};
|
|
|
|
phases = lib.options.create {
|
|
description = "The phases for the package.";
|
|
type = lib.types.either (lib.types.dag.of lib.types.string) (
|
|
lib.types.function (lib.types.dag.of lib.types.string)
|
|
);
|
|
default.value = { };
|
|
};
|
|
|
|
context = lib.options.create {
|
|
description = "The context information that the package provides.";
|
|
type = lib.types.context;
|
|
default.value = { };
|
|
};
|
|
|
|
settings = lib.options.create {
|
|
description = "The settings for the package.";
|
|
type = lib.types.settings;
|
|
default.value = { };
|
|
};
|
|
|
|
hooks = lib.options.create {
|
|
description = "The hooks that the package provides.";
|
|
type = lib.types.function (lib.types.dag.of lib.types.string);
|
|
default.value = ctx: { };
|
|
};
|
|
|
|
propagate = lib.options.create {
|
|
description = "Whether the package should propagate its hooks and context.";
|
|
type = lib.types.bool;
|
|
default.value = false;
|
|
};
|
|
|
|
deps = lib.options.create {
|
|
description = "The dependencies for the package.";
|
|
type = deps build host;
|
|
default.value = { };
|
|
apply = value: {
|
|
build = lib.packages.dependencies.build build build value.build;
|
|
host = lib.packages.dependencies.build build host value.host;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
type = (lib.types.coerceWithLocation initial transform final) // {
|
|
name = "Package";
|
|
description = "a package definition";
|
|
};
|
|
in
|
|
type
|
|
// {
|
|
children = type.children // {
|
|
inherit submodule;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|