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@
25 #include <dispatch/dispatch.h>
26 #include <Security/Security.h>
27 #include <Security/SecCodeSigner.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>
59 #include "MultiCacheBuilder.h"
62 #include "mega-dylib-utils.h"
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.build", DISPATCH_QUEUE_CONCURRENT);
70 static dispatch_group_t build_group = dispatch_group_create();
71 static dispatch_semaphore_t writeLimitingSemaphore = dispatch_semaphore_create(1);
73 bool copyFile(const std::string& from, const std::string& to)
75 const uint8_t* p = (uint8_t*)(-1);
79 std::tie(p, stat_buf, rp) = fileCache.cacheLoad(from);
80 if (p == (uint8_t*)(-1))
83 dispatch_group_enter(build_group);
84 mkpath_np(dirpath(to).c_str(), 0755);
86 dispatch_semaphore_wait(writeLimitingSemaphore, DISPATCH_TIME_FOREVER);
87 int fd = open(to.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0644);
89 ssize_t writtenSize = pwrite(fd, p, stat_buf.st_size, 0);
90 if (writtenSize != stat_buf.st_size)
91 terminate("write() failure creating cache file, errno=%d (%s)", errno, strerror(errno));
94 verboseLog("Wrote out: %s", to.c_str());
96 terminate("can't create file '%s', errnor=%d (%s)", to.c_str(), errno, strerror(errno));
98 dispatch_semaphore_signal(writeLimitingSemaphore);
99 dispatch_group_leave(build_group);
104 #define kDylibCachePrefix "/AppleInternal/Developer/DylibCaches/"
106 void createArtifact(Manifest& manifest, const std::string& dylibCachePath, bool includeExecutables)
108 mkpath_np(dylibCachePath.c_str(), 0755);
109 (void)copyFile(manifest.dylibOrderFile, dylibCachePath + "Metadata/dylibOrderFile.txt");
110 (void)copyFile(manifest.dirtyDataOrderFile, dylibCachePath + "Metadata/dirtyDataOrderFile.txt");
111 (void)copyFile(manifest.metabomFile, dylibCachePath + "Metadata/metabom.bom");
113 std::set<std::string> copied;
115 for (auto archFiles : manifest.architectureFiles) {
116 for (auto& file : archFiles.second.dylibs) {
117 std::string installname = file.first;
118 if (copied.count(installname) > 0) {
121 (void)copyFile(file.second.proxy->path, normalize_absolute_file_path(dylibCachePath + "/Root/" + file.first));
122 copied.insert(installname);
124 if (includeExecutables) {
125 for (auto& file : archFiles.second.executables) {
126 std::string installname = file.first;
127 if (copied.count(installname) > 0) {
130 (void)copyFile(file.second.proxy->path, normalize_absolute_file_path(dylibCachePath + "/Root/" + file.first));
131 copied.insert(installname);
136 log("Artifact dylibs copied");
139 void addArtifactPaths(Manifest &manifest) {
140 manifest.dylibOrderFile = "./Metadata/dylibOrderFile.txt";
141 manifest.dirtyDataOrderFile = "./Metadata/dirtyDataOrderFile.txt";
142 manifest.metabomFile = "./Metadata/metabom.bom";
144 for ( auto& projects : manifest.projects ) {
145 if ( projects.second.sources[0] != "./Root/" ) {
146 projects.second.sources.insert( projects.second.sources.begin(), "./Root/" );
151 int main (int argc, const char * argv[]) {
153 auto defaultCtx = std::make_shared<LoggingContext>("");
154 setLoggingContext(defaultCtx);
157 std::string masterDstRoot;
158 std::string dylibCacheDir;
159 std::string resultPath;
160 bool skipWrites = false;
161 bool skipBuilds = false;
162 bool preflight = false;
163 std::string manifestPath;
165 time_t mytime = time(0);
166 log("Started: %s", asctime(localtime(&mytime)));
168 // parse command line options
169 for (int i = 1; i < argc; ++i) {
170 const char* arg = argv[i];
172 if (strcmp(arg, "-debug") == 0) {
174 } else if (strcmp(arg, "-skip_writes") == 0) {
176 } else if (strcmp(arg, "-skip_builds") == 0) {
178 } else if (strcmp(arg, "-delete_writes") == 0) {
180 } else if (strcmp(arg, "-dylib_cache") == 0) {
181 dylibCacheDir = argv[++i];
182 } else if (strcmp(arg, "-preflight") == 0) {
185 } else if (strcmp(arg, "-master_dst_root") == 0) {
186 masterDstRoot = argv[++i];
187 if (masterDstRoot.empty()) {
188 terminate("-master_dst_root missing path argument");
190 } else if (strcmp(arg, "-results") == 0) {
191 resultPath = argv[++i];
192 } else if (strcmp(arg, "-plist") == 0) {
193 manifestPath = argv[++i];
194 (void)chdir(dirname(strdup(manifestPath.c_str())));
195 manifest = Manifest(manifestPath);
198 terminate("unknown option: %s", arg);
201 manifestPath = argv[i];
203 (void)chdir(dirname(strdup(argv[i])));
207 if ( getenv( "LGG_SKIP_CACHE_FUN" ) != nullptr ) {
211 if (manifest.build.empty()) {
212 terminate("No version found in manifest");
214 log("Building Caches for %s", manifest.build.c_str());
216 if ( masterDstRoot.empty() ) {
217 terminate("-master_dst_root required path argument");
220 if (manifest.manifest_version < 4) {
221 terminate("must specify valid manifest file");
224 struct rlimit rl = {OPEN_MAX, OPEN_MAX};
225 (void)setrlimit(RLIMIT_NOFILE, &rl);
228 (void)mkpath_np((masterDstRoot + "/Boms/").c_str(), 0755);
231 if (manifest.dylibOrderFile.empty()) {
232 manifest.dylibOrderFile = toolDir() + "/dylib-order.txt";
235 if (manifest.dirtyDataOrderFile.empty()) {
236 manifest.dirtyDataOrderFile = toolDir() + "/dirty-data-segments-order.txt";
239 auto dylibCacheCtx = std::make_shared<LoggingContext>("DylibCache");
240 setLoggingContext(dylibCacheCtx);
243 cacheBuilderDispatchGroupAsync(build_group, build_queue, [&] {
244 createArtifact(manifest, masterDstRoot + "/Artifact.dlc/", true);
247 if (!dylibCacheDir.empty()) {
248 cacheBuilderDispatchGroupAsync(build_group, build_queue, [&] {
249 createArtifact(manifest, dylibCacheDir + "/AppleInternal/Developer/DylibCaches/" + manifest.build + ".dlc/", false);
253 setLoggingContext(defaultCtx);
255 manifest.calculateClosure(false);
256 std::shared_ptr<MultiCacheBuilder> builder = std::make_shared<MultiCacheBuilder>(manifest, true, skipWrites, false, skipBuilds);
257 dispatch_group_async(build_group, build_queue, [&] { builder->buildCaches(masterDstRoot); });
258 dispatch_group_wait(build_group, DISPATCH_TIME_FOREVER);
261 setLoggingContext(dylibCacheCtx);
262 addArtifactPaths(manifest);
263 setLoggingContext(defaultCtx);
265 if (!resultPath.empty()) {
266 manifest.write(resultPath);
269 setLoggingContext(dylibCacheCtx);
270 copyFile(manifestPath, masterDstRoot + "/Artifact.dlc/BNIManifest.plist");
271 manifest.write(masterDstRoot + "/Artifact.dlc/Manifest.plist");
273 if (!dylibCacheDir.empty()) {
274 manifest.write(dylibCacheDir + kDylibCachePrefix + manifest.build + ".dlc/Manifest.plist");
276 setLoggingContext(defaultCtx);