1{
2 lib,
3 stdenv,
4 fetchFromGitHub,
5 cmake,
6 ninja,
7 python3,
8 zlib,
9}:
10
11let
12 # libtapi is only supported building against Apple’s LLVM fork pinned to a specific revision.
13 # It can’t be built against upstream LLVM because it uses APIs that are specific to Apple’s fork.
14 # See: https://github.com/apple-oss-distributions/tapi/blob/main/Readme.md
15
16 # Apple’s LLVM fork uses its own versioning scheme.
17 # See: https://en.wikipedia.org/wiki/Xcode#Toolchain_versions
18 # Note: Can’t use a sparse checkout because the Darwin stdenv bootstrap can’t depend on fetchgit.
19 appleLlvm = {
20 version = "16.0.0"; # As reported by upstream’s `tapi --version`.
21 rev = "3602748d4ec9947f0d1493511a8c34410909506e"; # Per the TAPI repo.
22 hash = "sha256-7o/JY/tcu4AeXCa7xhfjbuuV3/Cbf89AdoZOKrciJk0=";
23 };
24in
25stdenv.mkDerivation (finalAttrs: {
26 pname = "libtapi";
27 version = "1600.0.11.8";
28
29 outputs = [
30 "out"
31 "bin"
32 "dev"
33 ];
34
35 srcs = [
36 (fetchFromGitHub {
37 name = "tapi-src";
38 owner = "apple-oss-distributions";
39 repo = "tapi";
40 tag = "tapi-${finalAttrs.version}";
41 hash = "sha256-87AQZrCmZHv3lbfUnw0j17H4cP+GN5g0D6zhdT4P56Y=";
42 })
43 # libtapi can’t avoid pulling the whole repo even though it needs only a couple of folders because
44 # `fetchgit` can’t be used in the Darwin bootstrap.
45 (fetchFromGitHub {
46 name = "apple-llvm-src";
47 owner = "apple";
48 repo = "llvm-project";
49 inherit (appleLlvm) rev hash;
50 })
51 ];
52
53 patches = [
54 # Older versions of ld64 may not support `-no_exported_symbols`, so use it only
55 # when the linker supports it.
56 # Note: This can be dropped once the bootstrap tools are updated after the ld64 update.
57 ./0001-Check-for-no_exported_symbols-linker-support.patch
58 # Fix build on Linux. GCC is more picky than clang about the field order.
59 ./0003-Match-designator-order-with-declaration-order.patch
60 ];
61
62 postPatch = ''
63 # Enable building on non-Darwin platforms
64 substituteInPlace tapi/CMakeLists.txt \
65 --replace-fail 'message(FATAL_ERROR "Unsupported configuration.")' ""
66
67 # Remove the client limitation on linking to libtapi.dylib.
68 substituteInPlace tapi/tools/libtapi/CMakeLists.txt \
69 --replace-fail '-allowable_client ld' ""
70 # Replace hard-coded installation paths with standard ones.
71 declare -A installdirs=(
72 [bin]=BINDIR
73 [include]=INCLUDEDIR
74 [lib]=LIBDIR
75 [local/bin]=BINDIR
76 [local/share/man]=MANDIR
77 [share/man]=MANDIR
78 )
79 for dir in "''${!installdirs[@]}"; do
80 cmakevar=CMAKE_INSTALL_''${installdirs[$dir]}
81 for cmakelist in $(grep -rl "DESTINATION $dir" tapi); do
82 substituteInPlace "$cmakelist" \
83 --replace-fail "DESTINATION $dir" "DESTINATION \''${$cmakevar}"
84 done
85 done
86 ''
87 + lib.optionalString stdenv.hostPlatform.isLinux ''
88 # Remove Darwin-specific versioning flags.
89 substituteInPlace tapi/tools/libtapi/CMakeLists.txt \
90 --replace-fail '-current_version ''${DYLIB_VERSION} -compatibility_version 1' ""
91 '';
92
93 preUnpack = ''
94 mkdir source
95 '';
96
97 sourceRoot = "source";
98
99 postUnpack = ''
100 chmod -R u+w apple-llvm-src tapi-src
101 mv apple-llvm-src/{clang,cmake,llvm,utils} source
102 mv tapi-src source/tapi
103 '';
104
105 strictDeps = true;
106
107 buildInputs = [ zlib ]; # Upstream links against zlib in their distribution.
108
109 nativeBuildInputs = [
110 cmake
111 ninja
112 python3
113 ];
114
115 cmakeDir = "../llvm";
116
117 cmakeFlags = [
118 (lib.cmakeFeature "LLVM_ENABLE_PROJECTS" "clang;tapi")
119 (lib.cmakeFeature "LLVM_EXTERNAL_PROJECTS" "tapi")
120 (lib.cmakeBool "TAPI_INCLUDE_DOCS" true)
121 # Matches the version string format reported by upstream `tapi`.
122 (lib.cmakeFeature "TAPI_REPOSITORY_STRING" "tapi-${finalAttrs.version}")
123 (lib.cmakeFeature "TAPI_FULL_VERSION" appleLlvm.version)
124 # Match the versioning used by Apple’s LLVM fork (primarily used for .so versioning).
125 (lib.cmakeFeature "LLVM_VERSION_MAJOR" (lib.versions.major appleLlvm.version))
126 (lib.cmakeFeature "LLVM_VERSION_MINOR" (lib.versions.minor appleLlvm.version))
127 (lib.cmakeFeature "LLVM_VERSION_PATCH" (lib.versions.patch appleLlvm.version))
128 (lib.cmakeFeature "LLVM_VERSION_SUFFIX" "")
129 # Upstream `tapi` does not link against ncurses. Disable it explicitly to make sure
130 # it is not detected incorrectly from the bootstrap tools tarball.
131 (lib.cmakeBool "LLVM_ENABLE_TERMINFO" false)
132 # Disabling the benchmarks avoids a failure during the configure phase because
133 # the sparse checkout does not include the benchmarks.
134 (lib.cmakeBool "LLVM_INCLUDE_BENCHMARKS" false)
135 # tapi’s tests expect to target macOS 13.0 and build both x86_64 and universal
136 # binaries regardless of the host platform.
137 (lib.cmakeBool "LLVM_INCLUDE_TESTS" false)
138 (lib.cmakeBool "TAPI_INCLUDE_TESTS" false)
139 ];
140
141 ninjaFlags = [
142 "libtapi"
143 "tapi-sdkdb"
144 "tapi"
145 ];
146
147 installTargets = [
148 "install-libtapi"
149 "install-tapi-docs"
150 "install-tapi-headers"
151 "install-tapi-sdkdb"
152 "install-tapi"
153 ];
154
155 postInstall = ''
156 # The man page is installed for these, but they’re not included in the source release.
157 rm $bin/share/man/man1/tapi-analyze.1 $bin/share/man/man1/tapi-api-verify.1
158 '';
159
160 meta = {
161 description = "Replaces the Mach-O Dynamic Library Stub files in Apple's SDKs to reduce the size";
162 homepage = "https://github.com/apple-oss-distributions/tapi/";
163 license = lib.licenses.ncsa;
164 mainProgram = "tapi";
165 maintainers = with lib.maintainers; [
166 matthewbauer
167 reckenrode
168 ];
169 platforms = lib.platforms.unix;
170 };
171})