return CHECK(parseCachePruningPolicy(ltoPolicy), "invalid LTO cache policy");
}
+// What caused a given library to be loaded. Only relevant for archives.
+// Note that this does not tell us *how* we should load the library, i.e.
+// whether we should do it lazily or eagerly (AKA force loading). The "how" is
+// decided within addFile().
+enum class LoadType {
+ CommandLine, // Library was passed as a regular CLI argument
+ CommandLineForce, // Library was passed via `-force_load`
+ LCLinkerOption, // Library was passed via LC_LINKER_OPTIONS
+};
+
struct ArchiveFileInfo {
ArchiveFile *file;
bool isCommandLineLoad;
static DenseMap<StringRef, ArchiveFileInfo> loadedArchives;
-static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive,
- bool isCommandLineLoad, bool isLazy = false,
- bool isExplicit = true, bool isBundleLoader = false) {
+static InputFile *addFile(StringRef path, LoadType loadType,
+ bool isLazy = false, bool isExplicit = true,
+ bool isBundleLoader = false) {
Optional<MemoryBufferRef> buffer = readFile(path);
if (!buffer)
return nullptr;
file_magic magic = identify_magic(mbref.getBuffer());
switch (magic) {
case file_magic::archive: {
+ bool isCommandLineLoad = loadType != LoadType::LCLinkerOption;
// Avoid loading archives twice. If the archives are being force-loaded,
// loading them twice would create duplicate symbol errors. In the
// non-force-loading case, this is just a minor performance optimization.
file = make<ArchiveFile>(std::move(archive));
} else {
file = entry->second.file;
- // If file is previously loaded via command line, or is loaded via
- // LC_LINKER_OPTION and being loaded via LC_LINKER_OPTION again,
- // using the cached archive should be enough
- if (entry->second.isCommandLineLoad ||
- entry->second.isCommandLineLoad == isCommandLineLoad)
+ // Command-line loads take precedence. If file is previously loaded via
+ // command line, or is loaded via LC_LINKER_OPTION and being loaded via
+ // LC_LINKER_OPTION again, using the cached archive is enough.
+ if (entry->second.isCommandLineLoad || !isCommandLineLoad)
return file;
}
+ bool isLCLinkerForceLoad = loadType == LoadType::LCLinkerOption &&
+ config->forceLoadSwift &&
+ path::filename(path).startswith("libswift");
if ((isCommandLineLoad && config->allLoad) ||
- forceLoadArchive == ForceLoad::Yes) {
+ loadType == LoadType::CommandLineForce || isLCLinkerForceLoad) {
if (Optional<MemoryBufferRef> buffer = readFile(path)) {
Error e = Error::success();
for (const object::Archive::Child &c : file->getArchive().children(e)) {
- StringRef reason =
- forceLoadArchive == ForceLoad::Yes ? "-force_load" : "-all_load";
+ StringRef reason;
+ switch (loadType) {
+ case LoadType::LCLinkerOption:
+ reason = "LC_LINKER_OPTION";
+ break;
+ case LoadType::CommandLineForce:
+ reason = "-force_load";
+ break;
+ case LoadType::CommandLine:
+ reason = "-all_load";
+ break;
+ }
if (Error e = file->fetch(c, reason))
error(toString(file) + ": " + reason +
" failed to load archive member: " + toString(std::move(e)));
}
static void addLibrary(StringRef name, bool isNeeded, bool isWeak,
- bool isReexport, bool isExplicit,
- ForceLoad forceLoadArchive,
- bool isCommandLineLoad = true) {
+ bool isReexport, bool isExplicit, LoadType loadType) {
if (Optional<StringRef> path = findLibrary(name)) {
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
- addFile(*path, forceLoadArchive, isCommandLineLoad,
- /*isLazy=*/false, isExplicit))) {
+ addFile(*path, loadType, /*isLazy=*/false, isExplicit))) {
if (isNeeded)
dylibFile->forceNeeded = true;
if (isWeak)
static DenseSet<StringRef> loadedObjectFrameworks;
static void addFramework(StringRef name, bool isNeeded, bool isWeak,
- bool isReexport, bool isExplicit,
- ForceLoad forceLoadArchive,
- bool isCommandLineLoad = true) {
+ bool isReexport, bool isExplicit, LoadType loadType) {
if (Optional<StringRef> path = findFramework(name)) {
if (loadedObjectFrameworks.contains(*path))
return;
- InputFile *file = addFile(*path, forceLoadArchive, isCommandLineLoad,
- /*isLazy=*/false, isExplicit, false);
+ InputFile *file =
+ addFile(*path, loadType, /*isLazy=*/false, isExplicit, false);
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(file)) {
if (isNeeded)
dylibFile->forceNeeded = true;
unsigned i = 0;
StringRef arg = argv[i];
if (arg.consume_front("-l")) {
- ForceLoad forceLoadArchive =
- config->forceLoadSwift && arg.startswith("swift") ? ForceLoad::Yes
- : ForceLoad::No;
addLibrary(arg, /*isNeeded=*/false, /*isWeak=*/false,
- /*isReexport=*/false, /*isExplicit=*/false, forceLoadArchive,
- /*isCommandLineLoad=*/false);
+ /*isReexport=*/false, /*isExplicit=*/false,
+ LoadType::LCLinkerOption);
} else if (arg == "-framework") {
StringRef name = argv[++i];
addFramework(name, /*isNeeded=*/false, /*isWeak=*/false,
- /*isReexport=*/false, /*isExplicit=*/false, ForceLoad::No,
- /*isCommandLineLoad=*/false);
+ /*isReexport=*/false, /*isExplicit=*/false,
+ LoadType::LCLinkerOption);
} else {
error(arg + " is not allowed in LC_LINKER_OPTION");
}
return;
MemoryBufferRef mbref = *buffer;
for (StringRef path : args::getLines(mbref))
- addFile(rerootPath(path), ForceLoad::Default, true, isLazy);
+ addFile(rerootPath(path), LoadType::CommandLine, isLazy);
}
// We expect sub-library names of the form "libfoo", which will match a dylib
switch (opt.getID()) {
case OPT_INPUT:
- addFile(rerootPath(arg->getValue()), ForceLoad::Default, true, isLazy);
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLine, isLazy);
break;
case OPT_needed_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
- addFile(rerootPath(arg->getValue()), ForceLoad::Default, true)))
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLine)))
dylibFile->forceNeeded = true;
break;
case OPT_reexport_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
- addFile(rerootPath(arg->getValue()), ForceLoad::Default, true))) {
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLine))) {
config->hasReexports = true;
dylibFile->reexport = true;
}
break;
case OPT_weak_library:
if (auto *dylibFile = dyn_cast_or_null<DylibFile>(
- addFile(rerootPath(arg->getValue()), ForceLoad::Default, true)))
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLine)))
dylibFile->forceWeakImport = true;
break;
case OPT_filelist:
addFileList(arg->getValue(), isLazy);
break;
case OPT_force_load:
- addFile(rerootPath(arg->getValue()), ForceLoad::Yes, true);
+ addFile(rerootPath(arg->getValue()), LoadType::CommandLineForce);
break;
case OPT_l:
case OPT_needed_l:
case OPT_weak_l:
addLibrary(arg->getValue(), opt.getID() == OPT_needed_l,
opt.getID() == OPT_weak_l, opt.getID() == OPT_reexport_l,
- /*isExplicit=*/true, ForceLoad::Default);
+ /*isExplicit=*/true, LoadType::CommandLine);
break;
case OPT_framework:
case OPT_needed_framework:
addFramework(arg->getValue(), opt.getID() == OPT_needed_framework,
opt.getID() == OPT_weak_framework,
opt.getID() == OPT_reexport_framework, /*isExplicit=*/true,
- ForceLoad::Default);
+ LoadType::CommandLine);
break;
case OPT_start_lib:
if (isLazy)
if (const Arg *arg = args.getLastArg(OPT_bundle_loader)) {
if (config->outputType != MH_BUNDLE)
error("-bundle_loader can only be used with MachO bundle output");
- addFile(arg->getValue(), ForceLoad::Default, true, /*isLazy=*/false,
- /*isExplicit=*/false,
- /*isBundleLoader=*/true);
+ addFile(arg->getValue(), LoadType::CommandLine, /*isLazy=*/false,
+ /*isExplicit=*/false, /*isBundleLoader=*/true);
}
if (const Arg *arg = args.getLastArg(OPT_umbrella)) {
if (config->outputType != MH_DYLIB)