]> git.saurik.com Git - apple/dyld.git/blob - dyld3/shared-cache/multi_dyld_shared_cache_builder.mm
49e58a2e4c6320fc4cb19d1ca04cb3f0c9d7c32e
[apple/dyld.git] / dyld3 / shared-cache / multi_dyld_shared_cache_builder.mm
1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
2 *
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
12 * file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include <Bom/Bom.h>
26 #include <dispatch/dispatch.h>
27 #include <copyfile.h>
28
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <sys/mman.h>
32 #include <sys/resource.h>
33 #include <mach/mach.h>
34 #include <mach/mach_time.h>
35 #include <limits.h>
36 #include <stdarg.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <math.h>
40 #include <fcntl.h>
41 #include <dlfcn.h>
42 #include <signal.h>
43 #include <errno.h>
44 #include <sys/uio.h>
45 #include <unistd.h>
46 #include <sys/param.h>
47 #include <sys/sysctl.h>
48 #include <sys/resource.h>
49 #include <dirent.h>
50 #include <libgen.h>
51 #include <pthread.h>
52
53 #include <vector>
54 #include <array>
55 #include <set>
56 #include <map>
57 #include <algorithm>
58
59 #include "Manifest.h"
60 #include "FileUtils.h"
61 #include "BuilderUtils.h"
62
63 #define CACHE_BUILDER_COPY_FILE_MODE COPYFILE_ALL
64
65 #if !__has_feature(objc_arc)
66 #error The use of libdispatch in this files requires it to be compiled with ARC in order to avoid leaks
67 #endif
68
69 static dispatch_queue_t build_queue = dispatch_queue_create("com.apple.dyld.cache-builder.build", DISPATCH_QUEUE_CONCURRENT);
70
71 #define kDylibCachePrefix "/AppleInternal/Developer/DylibCaches/"
72
73 void createArtifact(Diagnostics& diags, dyld3::Manifest& manifest, const std::string& dylibCachePath, bool includeExecutables)
74 {
75 auto copy_state = copyfile_state_alloc();
76 mkpath_np((dylibCachePath + "/Metadata").c_str(), 0755);
77 (void)copyfile(manifest.metabomFile().c_str(), (dylibCachePath + "/Metadata/metabom.bom").c_str(), copy_state, CACHE_BUILDER_COPY_FILE_MODE);
78
79 if (!manifest.dylibOrderFile().empty()) {
80 (void)copyfile(realPath(manifest.dylibOrderFile()).c_str(), (dylibCachePath + "/Metadata/dylibOrderFile.txt").c_str(), copy_state, CACHE_BUILDER_COPY_FILE_MODE);
81 }
82
83 if (!manifest.dirtyDataOrderFile().empty()) {
84 (void)copyfile(realPath(manifest.dirtyDataOrderFile()).c_str(), (dylibCachePath + "/Metadata/dirtyDataOrderFile.txt").c_str(), copy_state, CACHE_BUILDER_COPY_FILE_MODE);
85 }
86
87 std::set<dyld3::UUID> uuids;
88 std::map<std::string, std::string> copy_pairs;
89
90 manifest.forEachConfiguration([&manifest, &uuids](const std::string& config) {
91 manifest.configuration(config).forEachArchitecture([&manifest, &config, &uuids](const std::string& arch) {
92 auto results = manifest.configuration(config).architecture(arch).results;
93 for (const auto& image : results.dylibs) {
94 uuids.insert(image.first);
95 }
96 for (const auto& image : results.bundles) {
97 uuids.insert(image.first);
98 }
99 for (const auto& image : results.executables) {
100 uuids.insert(image.first);
101 }
102 });
103 });
104
105 for (auto& uuid : uuids) {
106 auto buildPath = manifest.buildPathForUUID(uuid);
107 auto installPath = manifest.runtimePathForUUID(uuid);
108 assert(!buildPath.empty() && !installPath.empty());
109 copy_pairs.insert(std::make_pair(installPath, buildPath));
110 }
111
112 for (const auto& copy_pair : copy_pairs) {
113 std::string from = realPath(copy_pair.second);
114 std::string to = dylibCachePath + "/Root/" + copy_pair.first;
115 mkpath_np(dirPath(to).c_str(), 0755);
116 int err = copyfile(from.c_str(), to.c_str(), copy_state, CACHE_BUILDER_COPY_FILE_MODE);
117 diags.verbose("COPYING (%d) %s -> %s\n", err, from.c_str(), to.c_str());
118
119 }
120 copyfile_state_free(copy_state);
121
122 fprintf(stderr, "[Artifact] dylibs copied\n");
123 }
124
125 void addArtifactPaths(Diagnostics& diags, dyld3::Manifest& manifest)
126 {
127 manifest.setDylibOrderFile("./Metadata/dylibOrderFile.txt");
128 manifest.setDirtyDataOrderFile("./Metadata/dirtyDataOrderFile.txt");
129 manifest.setMetabomFile("./Metadata/metabom.bom");
130
131 for (auto& projects : manifest.projects()) {
132 manifest.addProjectSource(projects.first, "./Root", true);
133 }
134 }
135
136 int main(int argc, const char* argv[])
137 {
138 @autoreleasepool {
139 __block Diagnostics diags;
140 bool verbose = false;
141 std::string masterDstRoot;
142 std::string dylibCacheDir;
143 std::string resultPath;
144 std::string manifestPath;
145 bool preflight = false;
146 __block bool allBuildsSucceeded = true;
147 bool skipWrites = false;
148 bool skipBuilds = false;
149 bool agileChooseSHA256CdHash = false;
150 time_t mytime = time(0);
151 fprintf(stderr, "Started: %s", asctime(localtime(&mytime)));
152
153 // parse command line options
154 for (int i = 1; i < argc; ++i) {
155 const char* arg = argv[i];
156 if (arg[0] == '-') {
157 if (strcmp(arg, "-debug") == 0) {
158 verbose = true;
159 diags = Diagnostics(true);
160 } else if (strcmp(arg, "-skip_writes") == 0) {
161 skipWrites = true;
162 } else if (strcmp(arg, "-skip_builds") == 0) {
163 skipBuilds = true;
164 } else if (strcmp(arg, "-delete_writes") == 0) {
165 skipWrites = true;
166 } else if (strcmp(arg, "-dylib_cache") == 0) {
167 dylibCacheDir = argv[++i];
168 } else if (strcmp(arg, "-preflight") == 0) {
169 preflight = true;
170 skipWrites = true;
171 } else if (strcmp(arg, "-master_dst_root") == 0) {
172 masterDstRoot = argv[++i];
173 if (masterDstRoot.empty()) {
174 diags.error("-master_dst_root missing path argument");
175 }
176 } else if (strcmp(arg, "-results") == 0) {
177 resultPath = argv[++i];
178 } else if (strcmp(arg, "-plist") == 0) {
179 manifestPath = argv[++i];
180 } else if (strcmp(arg, "-agile_choose_sha256_cdhash") == 0) {
181 agileChooseSHA256CdHash = true;
182 } else {
183 // usage();
184 diags.error("unknown option: %s", arg);
185 }
186 } else {
187 manifestPath = argv[i];
188 }
189 }
190
191 if (getenv("LGG_SKIP_CACHE_FUN") != nullptr) {
192 skipBuilds = true;
193 }
194
195 if (diags.hasError()) {
196 printf("%s\n", diags.errorMessage().c_str());
197 exit(-1);
198 }
199
200 dispatch_async(dispatch_get_main_queue(), ^{
201 if (manifestPath.empty()) {
202 fprintf(stderr, "mainfest path argument is required\n");
203 exit(-1);
204 }
205
206 (void)chdir(dirname(strdup(manifestPath.c_str())));
207 __block auto manifest = dyld3::Manifest(diags, manifestPath);
208
209 if (manifest.build().empty()) {
210 fprintf(stderr, "No version found in manifest\n");
211 exit(-1);
212 }
213
214 fprintf(stderr, "Building Caches for %s\n", manifest.build().c_str());
215
216 if (masterDstRoot.empty()) {
217 fprintf(stderr, "-master_dst_root required path argument\n");
218 exit(-1);
219 }
220
221 if (manifest.version() < 4) {
222 fprintf(stderr, "must specify valid manifest file\n");
223 exit(-1);
224 }
225
226 struct rlimit rl = { OPEN_MAX, OPEN_MAX };
227 (void)setrlimit(RLIMIT_NOFILE, &rl);
228
229 manifest.calculateClosure();
230
231 if (!skipWrites && !skipBuilds) {
232 (void)mkpath_np((masterDstRoot + "/Boms/").c_str(), 0755);
233 dispatch_group_async(buildGroup(), build_queue, ^{
234 createArtifact(diags, manifest, masterDstRoot + "/Artifact.dlc/", true);
235 });
236 }
237
238 if (!dylibCacheDir.empty()) {
239 dispatch_group_async(buildGroup(), build_queue, ^{
240 createArtifact(diags, manifest, dylibCacheDir + "/AppleInternal/Developer/DylibCaches/" + manifest.build() + ".dlc/", false);
241 });
242 }
243
244 if (!skipBuilds) {
245 dispatch_group_async(buildGroup(), build_queue, ^{
246 makeBoms(manifest, masterDstRoot);
247 });
248 allBuildsSucceeded = build(diags, manifest, masterDstRoot, true, verbose, skipWrites,
249 agileChooseSHA256CdHash, true, false);
250 }
251
252 manifest.write(resultPath);
253
254 addArtifactPaths(diags, manifest);
255 if (!dylibCacheDir.empty()) {
256 manifest.write(dylibCacheDir + "/AppleInternal/Developer/DylibCaches/" + manifest.build() + ".dlc/Manifest.plist");
257 manifest.writeJSON(dylibCacheDir + "/AppleInternal/Developer/DylibCaches/" + manifest.build() + ".dlc/Manifest.json");
258 }
259
260 if (!skipWrites) {
261 mkpath_np((masterDstRoot + "/Artifact.dlc").c_str(), 0755);
262 auto copy_state = copyfile_state_alloc();
263 (void)copyfile(realPath(manifestPath).c_str(), (masterDstRoot + "/Artifact.dlc/BNIManifest.plist").c_str(), copy_state, COPYFILE_ALL);
264 copyfile_state_free(copy_state);
265 manifest.write(masterDstRoot + "/Artifact.dlc/Manifest.plist");
266 manifest.writeJSON(masterDstRoot + "/Artifact.dlc/Manifest.json");
267 }
268
269 dispatch_group_wait(buildGroup(), DISPATCH_TIME_FOREVER);
270 time_t mytime = time(0);
271 fprintf(stderr, "Finished: %s", asctime(localtime(&mytime)));
272
273 if (preflight && !allBuildsSucceeded) {
274 exit(-1);
275 }
276
277 exit(0);
278 });
279 }
280 dispatch_main();
281 return 0;
282 }