From 1cb1853573de833ff506579c8ece3d1f896e15d8 Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Sun, 14 Apr 2024 08:53:41 -0400 Subject: [PATCH 01/24] ld-wrapper: use a temporary file for reponse file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This changes ld-wrapper to use a temporary file for the response file passed to ld instead of using process substitution. ld64 does not handle long command-lines when reading from the response file, which defeats the point of using a response file to handle long command-lines. cctools-port was patched to work around this, but nixpkgs is now using Apple’s source release directly instead of the port. Since it’s preferable not to patch Apple’s release heavily (to reduce the difficulty of updating to new versions and to match upstream’s behavior), use the approach that was adopted in cc-wrapper to work around issues with response files in newer versions of clang. Related PRs (cctools-port): - https://github.com/NixOS/nixpkgs/pull/213831 - https://github.com/tpoechtrager/cctools-port/pull/132 Related PRs (cc-wrapper): - https://github.com/NixOS/nixpkgs/pull/245282 - https://github.com/NixOS/nixpkgs/pull/258608 --- pkgs/build-support/bintools-wrapper/ld-wrapper.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh index dcbe8a4c24948..3bd9c68f23366 100644 --- a/pkgs/build-support/bintools-wrapper/ld-wrapper.sh +++ b/pkgs/build-support/bintools-wrapper/ld-wrapper.sh @@ -257,10 +257,13 @@ PATH="$path_backup" # Old bash workaround, see above. if (( "${NIX_LD_USE_RESPONSE_FILE:-@use_response_file_by_default@}" >= 1 )); then - @prog@ @<(printf "%q\n" \ - ${extraBefore+"${extraBefore[@]}"} \ - ${params+"${params[@]}"} \ - ${extraAfter+"${extraAfter[@]}"}) + responseFile=$(mktemp "${TMPDIR:-/tmp}/ld-params.XXXXXX") + trap 'rm -f -- "$responseFile"' EXIT + printf "%q\n" \ + ${extraBefore+"${extraBefore[@]}"} \ + ${params+"${params[@]}"} \ + ${extraAfter+"${extraAfter[@]}"} > "$responseFile" + @prog@ "@$responseFile" else @prog@ \ ${extraBefore+"${extraBefore[@]}"} \ From 4712e8fe80f44c6fd12a79b1f279461135ac838a Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Mon, 15 Apr 2024 20:02:07 -0400 Subject: [PATCH 02/24] libredirect: use llvmPackages unconditionally Darwin and its bootstrap tools both use LLVM 16, which is sufficient for arm64e support in LLVM. Thsi change removes an unnecessary LLVM 13 build from the stdenv bootstrap. --- pkgs/build-support/libredirect/default.nix | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/pkgs/build-support/libredirect/default.nix b/pkgs/build-support/libredirect/default.nix index c4399189b7a21..9998241673886 100644 --- a/pkgs/build-support/libredirect/default.nix +++ b/pkgs/build-support/libredirect/default.nix @@ -1,12 +1,5 @@ -{ lib, stdenv, bintools-unwrapped, llvmPackages, llvmPackages_13, coreutils }: - -let - # aarch64-darwin needs a clang that can build arm64e binaries, so make sure a version of LLVM - # is used that can do that, but prefer the stdenv one if it is new enough. - llvmPkgs = if (lib.versionAtLeast (lib.getVersion llvmPackages.clang) "13") - then llvmPackages - else llvmPackages_13; - in +{ lib, stdenv, bintools-unwrapped, llvmPackages, coreutils }: + if stdenv.hostPlatform.isStatic then throw '' libredirect is not available on static builds. @@ -46,11 +39,11 @@ else stdenv.mkDerivation rec { # and the library search directory for libdl. # We can't build this on x86_64, because the libSystem we point to doesn't # like arm64(e). - PATH=${bintools-unwrapped}/bin:${llvmPkgs.clang-unwrapped}/bin:$PATH \ + PATH=${bintools-unwrapped}/bin:${llvmPackages.clang-unwrapped}/bin:$PATH \ clang -arch x86_64 -arch arm64 -arch arm64e \ - -isystem ${llvmPkgs.clang.libc}/include \ - -isystem ${llvmPkgs.libclang.lib}/lib/clang/*/include \ - -L${llvmPkgs.clang.libc}/lib \ + -isystem ${llvmPackages.clang.libc}/include \ + -isystem ${llvmPackages.libclang.lib}/lib/clang/*/include \ + -L${llvmPackages.clang.libc}/lib \ -Wl,-install_name,$libName \ -Wall -std=c99 -O3 -fPIC libredirect.c \ -shared -o "$libName" From 91d8dd928fff9f2626d3359fcb2e63bd6b075b1e Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Tue, 2 Jul 2024 23:13:28 -0400 Subject: [PATCH 03/24] darwin.apple_sdk_10_12.sdkRoot: specify exact SDK version --- pkgs/os-specific/darwin/apple-sdk/default.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkgs/os-specific/darwin/apple-sdk/default.nix b/pkgs/os-specific/darwin/apple-sdk/default.nix index 7298eba6c50aa..30081c8243784 100644 --- a/pkgs/os-specific/darwin/apple-sdk/default.nix +++ b/pkgs/os-specific/darwin/apple-sdk/default.nix @@ -363,7 +363,7 @@ in rec { objc4 = pkgs.darwin.libobjc; - sdkRoot = pkgs.callPackage ./sdkRoot.nix { sdkVersion = "10.12"; }; + sdkRoot = pkgs.callPackage ./sdkRoot.nix { sdkVersion = "10.12.4"; }; inherit (pkgs.darwin) Libsystem; From 3a545f673ecba345ee6bd2d33f0e52b58efd77a8 Mon Sep 17 00:00:00 2001 From: Randy Eckenrode Date: Thu, 18 Apr 2024 20:11:31 -0400 Subject: [PATCH 04/24] darwin.AvailabilityVersions: init at 140.1 --- ...t-setting-an-upper-bound-on-versions.patch | 244 ++++++++++++++++++ .../AvailabilityVersions/default.nix | 99 +++++++ .../darwin/apple-source-releases/default.nix | 4 + 3 files changed, 347 insertions(+) create mode 100644 pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/0001-Support-setting-an-upper-bound-on-versions.patch create mode 100644 pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/default.nix diff --git a/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/0001-Support-setting-an-upper-bound-on-versions.patch b/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/0001-Support-setting-an-upper-bound-on-versions.patch new file mode 100644 index 0000000000000..6dcf8eef36196 --- /dev/null +++ b/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/0001-Support-setting-an-upper-bound-on-versions.patch @@ -0,0 +1,244 @@ +From dd3a2378cca465ec783fd792158b2fc11f83722c Mon Sep 17 00:00:00 2001 +From: Randy Eckenrode +Date: Tue, 2 Jul 2024 20:04:56 -0400 +Subject: [PATCH] Support setting an upper bound on versions + +--- + availability | 94 ++++++++++++++++++++++++++++++++++------------------ + 1 file changed, 61 insertions(+), 33 deletions(-) + +diff --git a/availability b/availability +index 8ebd250..5bb9edb 100755 +--- a/availability ++++ b/availability +@@ -17,12 +17,34 @@ MIN_PYTHON = (3, 7) #Required for ordered dictionaries as default + if sys.version_info < MIN_PYTHON: + sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) + ++ ++def parse_version(ver): ++ if hasattr(ver, "string"): ++ ver = ver.string() ++ ++ return (tuple(map(int, ver.split("."))) + (0, 0))[:3] ++ ++ ++def version_older_or_equal(lhs, rhs): ++ if not rhs: ++ return True ++ ++ lhs_major, lhs_minor, lhs_patch = parse_version(lhs) ++ rhs_major, rhs_minor, rhs_patch = parse_version(rhs) ++ ++ return ( ++ lhs_major < rhs_major ++ or (lhs_major == rhs_major and lhs_minor < rhs_minor) ++ or (lhs_major == rhs_major and lhs_minor == rhs_minor and lhs_patch <= rhs_patch) ++ ) ++ ++ + # The build script will embed the DSL content here, otherwise we build it at runtime + dslContent = None + # @@INSERT_DSL_CONTENT()@@ + + class VersionSetDSL: +- def __init__(self, data): self.parsedDSL = self.Parser(data) ++ def __init__(self, data, threshold): self.parsedDSL = self.Parser(data, threshold) + def sets(self): return self.parsedDSL.version_sets + def platforms(self): return self.parsedDSL.platforms + +@@ -104,12 +126,15 @@ class VersionSetDSL: + self.availability_deprecation_define_name = optionals["availability_deprecation_define_name"] + if "version_define_name" in optionals: + self.availability_define_prefix = f"__{optionals['version_define_name']}_" +- def add_version(self, version): return self.versions.append(version); ++ def add_version(self, version, threshold): ++ if version_older_or_equal(version, threshold): ++ self.versions.append(version) + def add_variant(self, variant): return self.variants.append(variant); + class Parser: + platforms = {} + version_sets = [] +- def __init__(self, data): ++ def __init__(self, data, threshold): ++ self.threshold = threshold + for line in data.splitlines(): + line = line.strip().split('#',1)[0] + if not line: +@@ -129,7 +154,7 @@ class VersionSetDSL: + def set(self, name, version, uversion): + platforms = {} + for (platformName, platform) in self.platforms.items(): +- if platform.versioned: ++ if platform.versioned and platform.versions: + platforms[platformName] = platform.versions[-1] + version_set = {} + version_set["name"] = name +@@ -138,7 +163,7 @@ class VersionSetDSL: + self.version_sets.append(version_set) + # TODO add error checking for version decrease + def version(self, platform, version): +- if platform in self.platforms: self.platforms[platform].add_version(VersionSetDSL.Version(version)) ++ if platform in self.platforms: self.platforms[platform].add_version(VersionSetDSL.Version(version), self.threshold) + else: + print(f"Unknown platform \"{platform}\"") + exit(-1) +@@ -165,9 +190,8 @@ if not dslContent: + parts = line.split() + if uversion and parts and parts[0] == "set" and parts[3] == uversion: + break +-versions = VersionSetDSL(dslContent) + +-def print_sets(): ++def print_sets(versions): + print("---") + for set in versions.sets(): + print(f'{set["name"]}:') +@@ -178,7 +202,8 @@ def print_versions(platform): + print(" ".join([version.string() for version in versions.platforms()[platform].versions])) + + class Preprocessor: +- def __init__(self, inputFile, outputFile): ++ def __init__(self, versions, inputFile, outputFile): ++ self.versions = versions + bufferedOutput = "" + with tempfile.NamedTemporaryFile('w') as tmp: + with open(inputFile, 'r') as input: +@@ -207,10 +232,10 @@ class Preprocessor: + output.write("\"\"\"\n") + def VERSION_MAP(self, output): + sets = [] +- for set in versions.sets(): ++ for set in self.versions.sets(): + set_string = ", ".join(sorted({".{} = {}".format(os,osVersion.hex()) for (os,osVersion) in set["platforms"].items()})) + sets.append("\t{{ .set = {}, {} }}".format(set["version"].hex(), set_string)) +- platform_string = "\n".join([" uint32_t {} = 0;".format(name) for name in versions.platforms().keys()]) ++ platform_string = "\n".join([" uint32_t {} = 0;".format(name) for name in self.versions.platforms().keys()]) + output.write(""" + #include + #include +@@ -229,16 +254,16 @@ static const std::array sVersionMap = {{{{ + }}; + """.format(platform_string, len(sets), ",\n".join(sets))) + def DYLD_HEADER_VERSIONS(self, output): +- for (name,platform) in versions.platforms().items(): ++ for (name,platform) in self.versions.platforms().items(): + for version in platform.versions: + output.write(f"#define {platform.dyld_version_define_name + version.symbol() : <48}{version.hex()}\n"); + output.write("\n") +- for set in versions.sets(): ++ for set in self.versions.sets(): + set_string = " / ".join(sorted({"{} {}".format(os,osVersion.string()) for(os,osVersion) in set["platforms"].items()})) + output.write("// dyld_{}_os_versions => {}\n".format(set["name"], set_string)) + output.write("#define dyld_{}_os_versions".format(set["name"]).ljust(56, ' ')) + output.write("({{ (dyld_build_version_t){{0xffffffff, {}}}; }})\n\n".format(set["version"].hex())) +- for (name,platform) in versions.platforms().items(): ++ for (name,platform) in self.versions.platforms().items(): + for version in platform.versions: + output.write("#define dyld_platform_version_{}_{}".format(platform.stylized_name, version.symbol()).ljust(56, ' ')) + output.write("({{ (dyld_build_version_t){{{}, {}{}}}; }})\n".format(platform.platform_define, platform.dyld_version_define_name, version.symbol())) +@@ -247,14 +272,14 @@ static const std::array sVersionMap = {{{{ + def ALIAS_VERSION_MACROS(self, output, platformString, newName, oldName, **optionals): + minVersion = literal_eval(optionals.get("minVersion", "0x00000000")) + maxVersion = literal_eval(optionals.get("maxVersion", "0xFFFFFFFF")) +- platform = versions.platforms()[platformString]; ++ platform = self.versions.platforms()[platformString]; + for version in platform.versions: + if literal_eval(version.hex()) < minVersion: continue + if literal_eval(version.hex()) >= maxVersion: continue + output.write(f'#define {newName + version.symbol() : <48} {oldName + version.symbol()}\n') + def AVAILABILITY_DEFINES(self, output): +- for platformString in versions.platforms(): +- platform = versions.platforms()[platformString]; ++ for platformString in self.versions.platforms(): ++ platform = self.versions.platforms()[platformString]; + if platform.bleached: + output.write(f"#ifndef __APPLE_BLEACH_SDK__\n") + output.write(f"#ifndef __API_TO_BE_DEPRECATED_{platform.availability_deprecation_define_name}\n") +@@ -268,16 +293,16 @@ static const std::array sVersionMap = {{{{ + output.write(f"#endif /* __APPLE_BLEACH_SDK__ */\n") + output.write(f"\n"); + def AVAILABILITY_VERSION_DEFINES(self, output): +- for platformString in versions.platforms(): +- short = platform = versions.platforms()[platformString].short_version_numbers +- platform = versions.platforms()[platformString]; ++ for platformString in self.versions.platforms(): ++ short = platform = self.versions.platforms()[platformString].short_version_numbers ++ platform = self.versions.platforms()[platformString]; + for version in platform.versions: + output.write(f"#define {platform.availability_define_prefix + version.symbol() : <48}{version.decimal(short)}\n") + output.write(f"/* {platform.availability_define_prefix}_NA is not defined to a value but is used as a token by macros to indicate that the API is unavailable */\n\n") + def AVAILABILITY_MIN_MAX_DEFINES(self, output): +- for platformString in versions.platforms(): +- platform = versions.platforms()[platformString]; +- if not platform.versioned: ++ for platformString in self.versions.platforms(): ++ platform = self.versions.platforms()[platformString]; ++ if not platform.versioned or not platform.versions: + continue + if platform.bleached: + output.write(f"#ifndef __APPLE_BLEACH_SDK__\n") +@@ -310,8 +335,8 @@ static const std::array sVersionMap = {{{{ + output.write(f" #define __API_UNAVAILABLE_PLATFORM_{displayName} {realName},unavailable\n") + output.write(f"#if defined(__has_feature) && defined(__has_attribute)\n") + output.write(f" #if __has_attribute(availability)\n") +- for platformString in versions.platforms(): +- platform = versions.platforms()[platformString]; ++ for platformString in self.versions.platforms(): ++ platform = self.versions.platforms()[platformString]; + if platform.bleached: + output.write(f"#ifndef __APPLE_BLEACH_SDK__\n") + writeDefines(platformString, platformString, platform.versioned) +@@ -326,9 +351,9 @@ static const std::array sVersionMap = {{{{ + output.write(f" #endif /* __has_attribute(availability) */\n") + output.write(f"#endif /* defined(__has_feature) && defined(__has_attribute) */\n") + def AVAILABILITY_MACRO_IMPL(self, output, prefix, dispatcher, **optionals): +- count = len(versions.platforms()) +- for platformString in versions.platforms(): +- platform = versions.platforms()[platformString] ++ count = len(self.versions.platforms()) ++ for platformString in self.versions.platforms(): ++ platform = self.versions.platforms()[platformString] + count = count + len(platform.variants) + platformList = [] + argList = [] +@@ -344,9 +369,9 @@ static const std::array sVersionMap = {{{{ + scoped_availablity = False + if "scoped_availablity" in optionals and optionals["scoped_availablity"] == "TRUE": + scoped_availablity=True +- count = len(versions.platforms()) +- for platformString in versions.platforms(): +- platform = versions.platforms()[platformString] ++ count = len(self.versions.platforms()) ++ for platformString in self.versions.platforms(): ++ platform = self.versions.platforms()[platformString] + count = count + len(platform.variants) + argList = ','.join([f'{macroName}{x}' for x in reversed(range(0, count))]) + if "argCount" in optionals: +@@ -358,8 +383,9 @@ static const std::array sVersionMap = {{{{ + output.write(f" #define {name}(...) {macroName}_GET_MACRO(__VA_ARGS__,{argList},0)(__VA_ARGS__)\n") + + parser = argparse.ArgumentParser() ++parser.add_argument("--threshold", default=False, help='Specifies the maximum version (inclusive) included in pre-processed headers') + group = parser.add_mutually_exclusive_group() +-for (name, platform) in versions.platforms().items(): ++for (name, platform) in VersionSetDSL(dslContent, threshold=None).platforms().items(): + group.add_argument("--{}".format(name), default=False, action='store_true', help="Prints all SDK versions defined for {}".format(name)) + for alias in platform.cmd_aliases: + group.add_argument("--{}".format(alias), dest=name, default=False, action='store_true', help="Alias for --{}".format(name)) +@@ -367,8 +393,10 @@ group.add_argument("--sets", default=False, actio + group.add_argument("--preprocess", nargs=2, help=argparse.SUPPRESS) + args = parser.parse_args() + +-if args.sets: print_sets(); +-elif args.preprocess: Preprocessor(args.preprocess[0], args.preprocess[1]); ++versions = VersionSetDSL(dslContent, threshold=args.threshold) ++ ++if args.sets: print_sets(versions); ++elif args.preprocess: Preprocessor(versions, args.preprocess[0], args.preprocess[1]); + else: + for platform in versions.platforms().keys(): + if getattr(args, platform, None): +-- +2.45.2 + diff --git a/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/default.nix b/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/default.nix new file mode 100644 index 0000000000000..c80dd6235e41a --- /dev/null +++ b/pkgs/os-specific/darwin/apple-source-releases/AvailabilityVersions/default.nix @@ -0,0 +1,99 @@ +{ + lib, + stdenvNoCC, + appleDerivation', + gnused, + python3, + unifdef, +}: + +appleDerivation' stdenvNoCC { + nativeBuildInputs = [ unifdef ]; + + patches = [ ./0001-Support-setting-an-upper-bound-on-versions.patch ]; + + buildPhase = '' + runHook preBuild + + declare -a unifdef_sources=( + os_availability.modulemap + os_availability_private.modulemap + AvailabilityPrivate.modulemap + ) + unifdef -x2 -UBUILD_FOR_DRIVERKIT -m $(for x in "''${unifdef_sources[@]}"; do echo templates/$x; done) + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p "$out/bin" "$out/libexec" "$out/share/availability" + + cp -r availability.dsl templates "$out/share/availability/" + + substitute availability "$out/libexec/availability" \ + --replace-fail '/usr/bin/env python3' '${lib.getBin python3}/bin/python3' \ + --replace-fail 'f"{os.path.abspath(os.path.dirname(sys.argv[0]))}/' "\"$out/share/availability/" + chmod a+x "$out/libexec/availability" + + cat <