1 /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*-
3 * Copyright (c) 2016 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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
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.
22 * @APPLE_LICENSE_HEADER_END@
26 #include <dispatch/dispatch.h>
29 #include <sys/types.h>
32 #include <sys/resource.h>
33 #include <mach/mach.h>
34 #include <mach/mach_time.h>
46 #include <sys/param.h>
47 #include <sys/sysctl.h>
48 #include <sys/resource.h>
60 #include "FileUtils.h"
61 #include "BuilderUtils.h"
63 #define CACHE_BUILDER_COPY_FILE_MODE COPYFILE_ALL
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
69 static dispatch_queue_t build_queue = dispatch_queue_create("com.apple.dyld.cache-builder.build", DISPATCH_QUEUE_CONCURRENT);
71 #define kDylibCachePrefix "/AppleInternal/Developer/DylibCaches/"
73 void createArtifact(Diagnostics& diags, dyld3::Manifest& manifest, const std::string& dylibCachePath, bool includeExecutables)
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);
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);
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);
87 std::set<dyld3::UUID> uuids;
88 std::map<std::string, std::string> copy_pairs;
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);
96 for (const auto& image : results.bundles) {
97 uuids.insert(image.first);
99 for (const auto& image : results.executables) {
100 uuids.insert(image.first);
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));
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());
120 copyfile_state_free(copy_state);
122 fprintf(stderr, "[Artifact] dylibs copied\n");
125 void addArtifactPaths(Diagnostics& diags, dyld3::Manifest& manifest)
127 manifest.setDylibOrderFile("./Metadata/dylibOrderFile.txt");
128 manifest.setDirtyDataOrderFile("./Metadata/dirtyDataOrderFile.txt");
129 manifest.setMetabomFile("./Metadata/metabom.bom");
131 for (auto& projects : manifest.projects()) {
132 manifest.addProjectSource(projects.first, "./Root", true);
136 int main(int argc, const char* argv[])
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)));
153 // parse command line options
154 for (int i = 1; i < argc; ++i) {
155 const char* arg = argv[i];
157 if (strcmp(arg, "-debug") == 0) {
159 diags = Diagnostics(true);
160 } else if (strcmp(arg, "-skip_writes") == 0) {
162 } else if (strcmp(arg, "-skip_builds") == 0) {
164 } else if (strcmp(arg, "-delete_writes") == 0) {
166 } else if (strcmp(arg, "-dylib_cache") == 0) {
167 dylibCacheDir = argv[++i];
168 } else if (strcmp(arg, "-preflight") == 0) {
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");
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;
184 diags.error("unknown option: %s", arg);
187 manifestPath = argv[i];
191 if (getenv("LGG_SKIP_CACHE_FUN") != nullptr) {
195 if (diags.hasError()) {
196 printf("%s\n", diags.errorMessage().c_str());
200 dispatch_async(dispatch_get_main_queue(), ^{
201 if (manifestPath.empty()) {
202 fprintf(stderr, "mainfest path argument is required\n");
206 (void)chdir(dirname(strdup(manifestPath.c_str())));
207 __block auto manifest = dyld3::Manifest(diags, manifestPath);
209 if (manifest.build().empty()) {
210 fprintf(stderr, "No version found in manifest\n");
214 fprintf(stderr, "Building Caches for %s\n", manifest.build().c_str());
216 if (masterDstRoot.empty()) {
217 fprintf(stderr, "-master_dst_root required path argument\n");
221 if (manifest.version() < 4) {
222 fprintf(stderr, "must specify valid manifest file\n");
226 struct rlimit rl = { OPEN_MAX, OPEN_MAX };
227 (void)setrlimit(RLIMIT_NOFILE, &rl);
229 manifest.calculateClosure();
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);
238 if (!dylibCacheDir.empty()) {
239 dispatch_group_async(buildGroup(), build_queue, ^{
240 createArtifact(diags, manifest, dylibCacheDir + "/AppleInternal/Developer/DylibCaches/" + manifest.build() + ".dlc/", false);
245 dispatch_group_async(buildGroup(), build_queue, ^{
246 makeBoms(manifest, masterDstRoot);
248 allBuildsSucceeded = build(diags, manifest, masterDstRoot, true, verbose, skipWrites,
249 agileChooseSHA256CdHash, true, false);
252 manifest.write(resultPath);
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");
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");
269 dispatch_group_wait(buildGroup(), DISPATCH_TIME_FOREVER);
270 time_t mytime = time(0);
271 fprintf(stderr, "Finished: %s", asctime(localtime(&mytime)));
273 if (preflight && !allBuildsSucceeded) {