Something went wrong. Try again.
flake for building a declarative fusesoc dev environment
Something went wrong. Try again.
9.6 kB · 357 lines
Nix
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358{ fetchFromGitHub, fetchgit, fetchsvn, fetchurl, formats, fusesoc, lib, linkFarm, remarshal, runCommand, stdenv, stdenvNoCC, writableTmpDirAsHomeHook, writeScriptBin, writeText,}:rec { readYAML = path: let jsonFile = runCommand "from-yaml-${baseNameOf path}" { nativeBuildInputs = [ remarshal ]; } ''remarshal --stringify --from yaml --to json "${path}" "$out"''; in builtins.fromJSON (builtins.readFile jsonFile);
parseVlnv = vlnv: let split = lib.splitString ":" vlnv; vlnvParts = builtins.length split; noVersion = "0"; in if vlnvParts == 1 then { vendor = ""; library = ""; } // ( let legacySplit = lib.splitString "-" vlnv; in if builtins.length legacySplit == 1 then { name = vlnv; version = noVersion; } else let dropIfMatch = regex: list: if (isNull (builtins.match regex (lib.last list))) then list else (lib.dropEnd 1 list); dropRevision = dropIfMatch "^r[[:digit:]]+$"; dropVersion = list: if (builtins.length list > 1) then (dropIfMatch ''^[\.0-9]+$'' list) else list; trimmed = dropVersion (dropRevision legacySplit); dropAmt = (builtins.length legacySplit) - (builtins.length trimmed); in { name = lib.concatStringsSep "-" trimmed; version = if dropAmt == 0 then noVersion else (lib.concatStringsSep "-" (lib.takeEnd dropAmt legacySplit)); } )
else if vlnvParts >= 3 then { vendor = builtins.elemAt split 0; library = builtins.elemAt split 1; name = builtins.elemAt split 2; version = if builtins.length split == 4 then lib.last split else noVersion; } else throw "Unable to parse vlnv ${vlnv}. Expected format: `vendor:library:name:version`.";
parseDependency = cvlnv: let # https://fusesoc.readthedocs.io/en/stable/user/build_system/dependencies.html#version-constraints split = lib.splitString ":" cvlnv; match = builtins.match "(^\>\=|\<\=|[~^=><]?)(.*$)" (builtins.head split); parsedCondition = builtins.elemAt match 0; vendor = builtins.elemAt match 1; vlnv = lib.concatStringsSep ":" ([ vendor ] ++ (builtins.tail split)); parsed = parseVlnv vlnv;
condition = check: let inherit (parsed) version;
cmp = builtins.compareVersions check version;
specificity = if builtins.length split < 4 then 0 else builtins.length (builtins.splitVersion version);
caretVersion = lib.concatStringsSep "." (builtins.foldl' (acc: elem: { hitNonZero = acc.hitNonZero || (elem != "0"); newVer = (if acc.hitNonZero then acc.newVer else acc.newVer ++ [ elem ]); }) { hitNonZero = false; newVer = [ ]; } (builtins.splitVersion version) ).newVer;
conds = { "=" = cmp == 0; "<" = cmp < 0; ">" = cmp > 0; "<=" = cmp <= 0; ">=" = cmp >= 0; "^" = conds.">=" && (lib.versions.compareVersions (lib.zipListsWith (a: _: a) check caretVersion) caretVersion <= 0); "~" = let f = if specificity > 1 then lib.versions.majorMinor else lib.versions.major; in conds.">=" && ((lib.versions.compareVersions (f check) (f version)) <= 0); "" = conds."="; }; in conds.${parsedCondition} || (specificity == 0); in parsed // { inherit condition; };
stripCond = cond: let # extract the argument from conditional syntax # e.g. # "tool_quartus ? (data/fifo.sdc)" -> ["data/fifo.sdc"] # "rtl/fifo.v" -> Null stripped = builtins.match ''^!?[_a-zA-Z]*[[:space:]]*\??[[:space:]]*\((.*)\)$'' cond; in if (isNull stripped) then cond else builtins.head stripped;
resolveDeps = import ./resolveDeps.nix { inherit lib parseDependency unique; };
fetchProvider = core: hash: let inherit (core) provider; in { local = throw "local providers should not be fetched! use coreRoot."; github = fetchFromGitHub { inherit (core) name; owner = provider.user; repo = provider.repo; rev = provider.version; inherit hash; }; git = fetchgit { inherit (core) name; url = provider.repo; rev = provider.version; inherit hash; }; svn = fetchsvn { inherit (core) name; inherit (provider) url; rev = provider.revision; inherit hash; }; opencores = fetchsvn { inherit (core) name; url = "http://opencores.org/ocsvn/${provider.repo_name}/${provider.repo_name}/${provider.repo_root}"; rev = provider.revision; inherit hash; }; url = let fetch = fetchurl { inherit (core) name; inherit (provider) url; inherit hash; }; in { tar = fetch; zip = fetch; simple = let fileName = lib.last (lib.splitString "/" provider.url); in runCommand "${core.name}-source" { } '' mkdir -p $out ln -s ${fetch} $out/${fileName} ''; } .${provider.filetype} or (throw "Unknown url provider filetype ${provider.filetype} in ${core.name}"); } .${provider.name} or (throw "Unknown provider name: ${provider.name}");
# uniquify by vlnv unique = coreList: lib.mapAttrsToList (_: v: v) ( builtins.listToAttrs ( map (x: { inherit (x.core) name; value = x; }) coreList ) );
addCore = prevSet: coreDrv: let inherit (coreDrv.parsed) vendor library name; in lib.recursiveUpdateUntil ( path: _: _: builtins.length path == 3 ) prevSet { ${vendor}.${library}.${name} = let prevCore = prevSet.${vendor}.${library}.${name} or { }; prev = prevCore.passthru or { }; defaultCore = if lib.versionAtLeast coreDrv.version (prevCore.version or "0") then coreDrv else prevCore; in defaultCore.overrideAttrs ( _: prevAttrs: { passthru = # copy previous core versions (lib.filterAttrs (n: _: !(isNull (builtins.match "^[[:digit:]]+.*$" n))) prev) // prevAttrs.passthru // { ${coreDrv.version} = coreDrv; }; } ); };
extendCoreSet = coreSet: cores: let coreList = coerceCoresToList cores; flattened = unique (coreList ++ (builtins.concatMap (x: x.dependencies or [ ]) coreList)); self = builtins.foldl' addCore coreSet (map (x: x.linkWith self) flattened); in self;
mkCoreSet = extendCoreSet { };
toCoreList = let unwrap = builtins.concatMap (x: lib.attrsToList x.value); in coreSet: builtins.concatMap (x: x.value.list or [ x.value ]) (unwrap (unwrap (lib.attrsToList coreSet)));
coerceCoresToList = cores: if builtins.isList cores then cores else (toCoreList cores);
mkConf = cores: let libPath = dumpCores cores; in writeText "fusesoc.conf" '' [library.fusesoc-flake] location = ${libPath} sync-url = ${libPath} sync-type = local auto-sync = false '';
dumpCores = cores: linkFarm "fusesocCores" ( map (x: { inherit (x) name; path = x; }) (coerceCoresToList cores) );
runCore = import ./runCore.nix { inherit dumpCores fusesoc lib parseVlnv stdenv writableTmpDirAsHomeHook ; };
mkRunners = { core, dependencies, tools ? [ ], }: lib.mapAttrs ( target: v: runCore (_: { inherit core target dependencies; tools = if (builtins.isList tools) then tools else tools."${target}" or tools.default or [ ]; }) ) core.targets;
importCore = import ./importCore.nix { inherit fetchProvider formats lib mkRunners parseVlnv readYAML resolveDeps stdenvNoCC stripCond ; };
importCores = root: map ( coreFile: importCore { coreRoot = dirOf coreFile; coreName = baseNameOf coreFile; } ) ( lib.filter (path: (lib.pathIsRegularFile path) && (lib.hasSuffix ".core" (baseNameOf path))) ( lib.filesystem.listFilesRecursive root ) );
mkCore = core: coreRoot: importCore { inherit core coreRoot; coreName = "${(parseVlnv core.name).name}.core"; };
wrapFusesoc = sources: lib.warn "wrapFusesoc is deprecated, add `export FUSESOC_CONFIG=\${fusesoc.lib.dumpCores coreSet}` to your shellHook instead." ( writeScriptBin "fusesoc" '' export FUSESOC_CONFIG=${mkConf sources} exec ${fusesoc}/bin/fusesoc $@ '' );}