206 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
			
		
		
	
	
			206 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Nix
		
	
	
	
	
	
{ lib
 | 
						|
, stdenv
 | 
						|
, callPackage
 | 
						|
, dpkg
 | 
						|
, fetchurl
 | 
						|
, recurseIntoAttrs
 | 
						|
 | 
						|
, sqlite
 | 
						|
, elfutils
 | 
						|
}:
 | 
						|
 | 
						|
let
 | 
						|
  inherit (builtins)
 | 
						|
    elem attrNames attrValues concatMap filter fromJSON getAttr groupBy head isNull listToAttrs map mapAttrs readFile replaceStrings splitVersion ;
 | 
						|
  inherit (lib)
 | 
						|
    converge findFirst groupBy' hasPrefix optional pipe take toInt toList versionAtLeast versionOlder ;
 | 
						|
 | 
						|
  aptData = fromJSON (readFile ./packages.json);
 | 
						|
 | 
						|
  # Compare versions in debian control file syntax
 | 
						|
  # See: https://www.debian.org/doc/debian-policy/ch-relationships.html#syntax-of-relationship-fields
 | 
						|
  #
 | 
						|
  # NOTE: this is not a proper version comparison
 | 
						|
  #
 | 
						|
  # A proper version solver, should aggregate dependencies with the same name
 | 
						|
  # and compute the constraint (e.g. a (>= 2) a (<< 5) -> 2 <= a << 5)
 | 
						|
  #
 | 
						|
  # But in the intel repo, there are no such "duplicated" dependencies to specify
 | 
						|
  # upper limits, which leads to issues when intel-hpckit-2021 depends on things
 | 
						|
  # like intel-basekit >= 2021.1.0-2403 and we end up installing the newest
 | 
						|
  # basekit instead of the one from 2021.
 | 
						|
  #
 | 
						|
  # To mitigate this, >= is set to take the latest version with matching major
 | 
						|
  # and minor (only revision and patch are allowed to change)
 | 
						|
  compareVersions = got: kind: want:
 | 
						|
    let
 | 
						|
      g0 = take 2 (splitVersion got);
 | 
						|
      w0 = take 2 (splitVersion want);
 | 
						|
    in if isNull want then true
 | 
						|
    else if kind == "=" then got == want
 | 
						|
    else if kind == "<<" then versionOlder got want
 | 
						|
    else if kind == "<=" then versionAtLeast want got
 | 
						|
    else if kind == ">>" then versionOlder want got
 | 
						|
    else if kind == ">=" then (g0 == w0) && versionAtLeast got want # always match major version
 | 
						|
    else throw "unknown operation: ${kind}";
 | 
						|
 | 
						|
  findMatching = { pname, kind, version }:
 | 
						|
    findFirst (x: pname == x.pname && compareVersions x.version kind version) null aptData;
 | 
						|
 | 
						|
  isIntel = pkg: (hasPrefix "intel-" pkg.pname);
 | 
						|
 | 
						|
  expandDeps = pkg: (map findMatching (filter isIntel pkg.dependencies)) ++ (optional (pkg.size != 0) pkg);
 | 
						|
 | 
						|
  # get the oldest by major version. If they have the same major version, take
 | 
						|
  # the newest. This prevents most issues with resolutions
 | 
						|
  # versionOlder b a -> true if b is older than a (b `older` a)
 | 
						|
  getNewerInMajor = a: b: let
 | 
						|
    va = a.version;
 | 
						|
    vb = b.version;
 | 
						|
    va0 = head (splitVersion va);
 | 
						|
    vb0 = head (splitVersion vb);
 | 
						|
  in
 | 
						|
  if isNull a then b
 | 
						|
  else if va0 != vb0 then
 | 
						|
    if va0 > vb0 then b else a
 | 
						|
  else if versionOlder vb va then a else b;
 | 
						|
  removeDups = l: attrValues (groupBy' getNewerInMajor null (getAttr "provides") l);
 | 
						|
 | 
						|
  _resolveDeps = converge (l: removeDups (concatMap expandDeps l));
 | 
						|
  resolveDeps = pkg: let deps = _resolveDeps (toList pkg);
 | 
						|
      namedDeps = (map (x: "${x.pname}-${x.version}") deps);
 | 
						|
    in builtins.traceVerbose (builtins.deepSeq namedDeps namedDeps) deps;
 | 
						|
 | 
						|
  blacklist = [
 | 
						|
    "intel-basekit-env"
 | 
						|
    "intel-basekit-getting-started"
 | 
						|
    "intel-hpckit-env"
 | 
						|
    "intel-hpckit-getting-started"
 | 
						|
    "intel-oneapi-advisor"
 | 
						|
    "intel-oneapi-common-licensing"
 | 
						|
    "intel-oneapi-common-oneapi-vars"
 | 
						|
    "intel-oneapi-common-vars"
 | 
						|
    "intel-oneapi-compiler-cpp-eclipse-cfg"
 | 
						|
    "intel-oneapi-compiler-dpcpp-eclipse-cfg"
 | 
						|
    "intel-oneapi-condaindex"
 | 
						|
    "intel-oneapi-dev-utilities-eclipse-cfg"
 | 
						|
    "intel-oneapi-dpcpp-ct-eclipse-cfg"
 | 
						|
    "intel-oneapi-eclipse-ide"
 | 
						|
    "intel-oneapi-hpc-toolkit-getting-started"
 | 
						|
    "intel-oneapi-icc-eclipse-plugin-cpp"
 | 
						|
    "intel-oneapi-vtune"
 | 
						|
    "intel-oneapi-vtune-eclipse-plugin-vtune"
 | 
						|
  ];
 | 
						|
 | 
						|
  isInBlacklist = pkg: elem pkg.provides blacklist;
 | 
						|
  removeBlacklist = filter (e: !(isInBlacklist e));
 | 
						|
 | 
						|
  dpkgExtractAll = pname: version: {srcs, deps}: stdenv.mkDerivation {
 | 
						|
    inherit pname version srcs;
 | 
						|
 | 
						|
    nativeBuildInputs = [ dpkg ];
 | 
						|
    phases = [ "installPhase" ];
 | 
						|
 | 
						|
    passthru = { inherit deps; };
 | 
						|
 | 
						|
    installPhase = ''
 | 
						|
      mkdir -p $out
 | 
						|
      for src in $srcs; do
 | 
						|
        echo "Unpacking $src"
 | 
						|
        dpkg -x $src $out
 | 
						|
      done
 | 
						|
    '';
 | 
						|
  };
 | 
						|
 | 
						|
  apthost = "https://apt.repos.intel.com/oneapi/";
 | 
						|
  fetchDeb = p: fetchurl { url = apthost + p.filename; inherit (p) sha256; };
 | 
						|
 | 
						|
  buildIntel = pkg: pipe pkg [
 | 
						|
    resolveDeps
 | 
						|
    removeBlacklist
 | 
						|
    (l: {srcs = map fetchDeb l; deps = l; })
 | 
						|
    (dpkgExtractAll "${pkg.provides}-extracted" pkg.version)
 | 
						|
  ];
 | 
						|
 | 
						|
  findHpcKit = year: findMatching { pname = "intel-hpckit"; kind = "<<"; version = toString (year+1); };
 | 
						|
  years = map toInt (attrNames components);
 | 
						|
 | 
						|
  patchIntel = callPackage ./patch_intel.nix { };
 | 
						|
 | 
						|
  # Version information for each hpckit. This is used to normalize the paths
 | 
						|
  # so that files are in $out/{bin,lib,include...} instead of all over the place
 | 
						|
  # in $out/opt/intel/oneapi/*/*/{...}.
 | 
						|
  #
 | 
						|
  # The most important is the compiler component, which is used to build the
 | 
						|
  # stdenv for the hpckit.
 | 
						|
  #
 | 
						|
  # NOTE: this have to be manually specified, so we can avoid IFD. To add a
 | 
						|
  # new version, add a new field with an empty attrset, (e.g. "2026" = {}; ),
 | 
						|
  # build hpckit_2026.unpatched and use the values from
 | 
						|
  # result/opt/intel/oneapi/* to populate the attrset.
 | 
						|
  #
 | 
						|
  # WARN: if there are more than one version in the folders of the unpatched
 | 
						|
  # components, our dependency resolution hacks have probably failed and the
 | 
						|
  # package set may be broken.
 | 
						|
  components = {
 | 
						|
    "2025" = {
 | 
						|
      ishmem = "1.3";
 | 
						|
      pti = "0.12";
 | 
						|
      tcm = "1.3";
 | 
						|
      umf = "0.10";
 | 
						|
 | 
						|
      ccl = "2021.15";
 | 
						|
      compiler = "2025.1";
 | 
						|
      dal = "2025.5";
 | 
						|
      debugger = "2025.1";
 | 
						|
      dev-utilities = "2025.1";
 | 
						|
      dnnl = "2025.1";
 | 
						|
      dpcpp-ct = "2025.1";
 | 
						|
      dpl = "2022.8";
 | 
						|
      ipp = "2022.1";
 | 
						|
      ippcp = "2025.1";
 | 
						|
      mkl = "2025.1";
 | 
						|
      mpi = "2021.15";
 | 
						|
      tbb = "2022.1";
 | 
						|
    };
 | 
						|
    "2024" = {
 | 
						|
      tcm = "1.1";
 | 
						|
 | 
						|
      ccl = "2021.13";
 | 
						|
      compiler = "2024.2";
 | 
						|
      dal = "2024.6";
 | 
						|
      debugger = "2024.2";
 | 
						|
      dev-utilities = "2024.2";
 | 
						|
      diagnostics = "2024.2";
 | 
						|
      dnnl = "2024.2";
 | 
						|
      dpcpp-ct = "2024.2";
 | 
						|
      dpl = "2022.6";
 | 
						|
      ipp = "2021.12";
 | 
						|
      ippcp = "2021.12";
 | 
						|
      mkl = "2024.2";
 | 
						|
      mpi = "2021.13";
 | 
						|
      tbb = "2021.13";
 | 
						|
 | 
						|
      extraPackages = [
 | 
						|
        sqlite
 | 
						|
        elfutils
 | 
						|
      ];
 | 
						|
    };
 | 
						|
  };
 | 
						|
 | 
						|
  replaceDots = replaceStrings ["."] ["_"];
 | 
						|
 | 
						|
in recurseIntoAttrs (listToAttrs (map (year: let
 | 
						|
      year_str = toString year;
 | 
						|
    in {
 | 
						|
      name = "hpckit_${year_str}";
 | 
						|
      value = patchIntel {unpatched = buildIntel (findHpcKit year); components = components.${year_str}; };
 | 
						|
  }) years)) // {
 | 
						|
  apt = pipe aptData [
 | 
						|
    (groupBy (p: replaceDots p.provides))
 | 
						|
    (mapAttrs (_: l: listToAttrs (map (pkg: { name = replaceDots ("v" + pkg.version); value = pkg; }) l)))
 | 
						|
  ] ;
 | 
						|
 | 
						|
  inherit resolveDeps patchIntel buildIntel;
 | 
						|
}
 |