summary refs log tree commit diff
path: root/pkgs/os-specific/darwin/cctools/llvm.nix
blob: 11ec2b4d04faa166fdde2db4f0096eda695175d0 (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
# Create a cctools-compatible bintools that uses equivalent tools from LLVM in place of the ones
# from cctools when possible.

{ lib, stdenv, makeWrapper, cctools-port, llvmPackages, enableManpages ? true }:

let
  cctoolsVersion = lib.getVersion cctools-port;
  llvmVersion = llvmPackages.release_version;

  # `bitcode_strip` is not available until LLVM 12.
  useLLVMBitcodeStrip = lib.versionAtLeast llvmVersion "12";

  # A compatible implementation of `otool` was not added until LLVM 13.
  useLLVMOtool = lib.versionAtLeast llvmVersion "13";

  # Older versions of `strip` cause problems for the version of `codesign_allocate` available in
  # the version of cctools in nixpkgs. The version of `codesign_allocate` in cctools-1005.2 does
  # not appear to have issues, but the source is not available yet (as of June 2023).
  useLLVMStrip = lib.versionAtLeast llvmVersion "15" || lib.versionAtLeast cctoolsVersion "1005.2";

  llvm_bins = [
    "dwarfdump"
    "nm"
    "objdump"
    "size"
    "strings"
  ]
  ++ lib.optional useLLVMBitcodeStrip "bitcode-strip"
  ++ lib.optional useLLVMOtool "otool"
  ++ lib.optional useLLVMStrip "strip";

  # Only include the tools that LLVM doesn’t provide and that are present normally on Darwin.
  # The only exceptions are the following tools, which should be reevaluated when LLVM is bumped.
  # - install_name_tool (llvm-objcopy): unrecognized linker commands when building open source CF;
  # - libtool (llvm-libtool-darwin): not fully compatible when used with xcbuild; and
  # - lipo (llvm-lipo): crashes when running the LLVM test suite.
  cctools_bins = [
    "cmpdylib"
    "codesign_allocate"
    "ctf_insert"
    "install_name_tool"
    "ld"
    "libtool"
    "lipo"
    "nmedit"
    "pagestuff"
    "ranlib"
    "segedit"
    "vtool"
  ]
  ++ lib.optional (!useLLVMBitcodeStrip) "bitcode_strip"
  ++ lib.optional (!useLLVMOtool) "otool"
  ++ lib.optional (!useLLVMStrip) "strip";

  inherit (stdenv.cc) targetPrefix;

  linkManPages = pkg: source: target: lib.optionalString enableManpages ''
    sourcePath=${pkg}/share/man/man1/${source}.1.gz
    targetPath=$man/share/man/man1/${target}.1.gz

    if [ -f "$sourcePath" ]; then
      mkdir -p "$(dirname "$targetPath")"
      ln -s "$sourcePath" "$targetPath"
    fi
  '';
in
stdenv.mkDerivation {
  pname = "cctools-llvm";
  version = "${llvmVersion}-${cctoolsVersion}";

  nativeBuildInputs = [ makeWrapper ];

  # The `man` output has to be included unconditionally because darwin.binutils expects it.
  outputs = [ "out" "dev" "man" ];

  buildCommand = ''
    mkdir -p "$out/bin" "$man"
    ln -s ${lib.getDev cctools-port} "$dev"

    # Use the clang-integrated assembler instead of using `as` from cctools.
    makeWrapper "${lib.getBin llvmPackages.clang-unwrapped}/bin/clang" "$out/bin/${targetPrefix}as" \
      --add-flags "-x assembler -integrated-as -c"

    ln -s "${lib.getBin llvmPackages.bintools-unwrapped}/bin/llvm-ar" "$out/bin/${targetPrefix}ar"
    ${linkManPages llvmPackages.llvm-manpages "llvm-ar" "ar"}

    for tool in ${toString llvm_bins}; do
      cctoolsTool=''${tool/-/_}
      ln -s "${lib.getBin llvmPackages.llvm}/bin/llvm-$tool" "$out/bin/${targetPrefix}$cctoolsTool"
      ${linkManPages llvmPackages.llvm-manpages "llvm-$tool" "$cctoolsTool"}
    done

    for tool in ${toString cctools_bins}; do
      ln -s "${lib.getBin cctools-port}/bin/${targetPrefix}$tool" "$out/bin/${targetPrefix}$tool"
      ${linkManPages (lib.getMan cctools-port) "$tool" "$tool"}
    done

    ${linkManPages (lib.getMan cctools-port) "ld64" "ld64"}
    ${lib.optionalString (!useLLVMOtool)  # The actual man page for otool in cctools is llvm-otool
      linkManPages (lib.getMan cctools-port) "llvm-otool" "llvm-otool"}
  '';

  passthru = { inherit targetPrefix; };
}