X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/b1f7435d66a93f03b77932b3a9ad8a83ce5e1ebc..ec29ba20dfd4abc0cb74366b39dda06af136e073:/src/ld/InputFiles.cpp diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index c0b5cdb..ab31d4a 100644 --- a/src/ld/InputFiles.cpp +++ b/src/ld/InputFiles.cpp @@ -1,3 +1,4 @@ + /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-* * * Copyright (c) 2009-2011 Apple Inc. All rights reserved. @@ -49,8 +50,6 @@ #include #include #include -#include -#include #include #include @@ -59,9 +58,11 @@ #include "InputFiles.h" #include "macho_relocatable_file.h" #include "macho_dylib_file.h" +#include "textstub_dylib_file.hpp" #include "archive_file.h" #include "lto_file.h" #include "opaque_section_file.h" +#include "MachOFileAbstraction.hpp" #include "Snapshot.h" const bool _s_logPThreads = false; @@ -182,7 +183,11 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len) const char* result = mach_o::relocatable::archName(p); if ( result != NULL ) return result; - + + result = mach_o::dylib::archName(p); + if ( result != NULL ) + return result; + result = lto::archName(p, len); if ( result != NULL ) return result; @@ -194,7 +199,7 @@ const char* InputFiles::fileArch(const uint8_t* p, unsigned len) strcpy(unsupported, "unsupported file format ("); for (unsigned i=0; i info.fileLen ) { - throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", + // file size was read awhile ago. If file is being written, wait a second to see if big enough now + sleep(1); + uint64_t newFileLen = info.fileLen; + struct stat statBuffer; + if ( stat(info.path, &statBuffer) == 0 ) { + newFileLen = statBuffer.st_size; + } + if ( fileOffset+len > newFileLen ) { + throwf("truncated fat file. Slice from %u to %llu is past end of file with length %llu", fileOffset, fileOffset+len, info.fileLen); + } } // if requested architecture is page aligned within fat file, then remap just that portion of file if ( (fileOffset & 0x00000FFF) == 0 ) { @@ -275,8 +289,22 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib objOpts.architecture = _options.architecture(); objOpts.objSubtypeMustMatch = !_options.allowSubArchitectureMismatches(); objOpts.logAllFiles = _options.logAllFiles(); - objOpts.convertUnwindInfo = _options.needsUnwindInfoSection(); + objOpts.warnUnwindConversionProblems = _options.needsUnwindInfoSection(); + objOpts.keepDwarfUnwind = _options.keepDwarfUnwind(); + objOpts.forceDwarfConversion= (_options.outputKind() == Options::kDyld); + objOpts.neverConvertDwarf = !_options.needsUnwindInfoSection(); + objOpts.verboseOptimizationHints = _options.verboseOptimizationHints(); + objOpts.armUsesZeroCostExceptions = _options.armUsesZeroCostExceptions(); + objOpts.simulator = _options.targetIOSSimulator(); + objOpts.ignoreMismatchPlatform = ((_options.outputKind() == Options::kPreload) || (_options.outputKind() == Options::kStaticExecutable)); objOpts.subType = _options.subArchitecture(); + objOpts.platform = _options.platform(); + objOpts.minOSVersion = _options.minOSversion(); + objOpts.srcKind = ld::relocatable::File::kSourceObj; + objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData; + objOpts.usingBitcode = _options.bundleBitcode(); + objOpts.maxDefaultCommonAlignment = _options.maxDefaultCommonAlign(); + ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts); if ( objResult != NULL ) { OSAtomicAdd64(len, &_totalObjectSize); @@ -285,17 +313,36 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } // see if it is an llvm object file - objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles()); + objResult = lto::parse(p, len, info.path, info.modTime, info.ordinal, _options.architecture(), _options.subArchitecture(), _options.logAllFiles(), _options.verboseOptimizationHints()); if ( objResult != NULL ) { OSAtomicAdd64(len, &_totalObjectSize); OSAtomicIncrement32(&_totalObjectLoaded); return objResult; } - - // see if it is a dynamic library - ld::dylib::File* dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib); - if ( dylibResult != NULL ) { - return dylibResult; + + // see if it is a dynamic library (or text-based dynamic library) + ld::dylib::File* dylibResult; + bool dylibsNotAllowed = false; + switch ( _options.outputKind() ) { + case Options::kDynamicExecutable: + case Options::kDynamicLibrary: + case Options::kDynamicBundle: + dylibResult = mach_o::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib); + if ( dylibResult != NULL ) { + return dylibResult; + } + dylibResult = textstub::dylib::parse(p, len, info.path, info.modTime, _options, info.ordinal, info.options.fBundleLoader, indirectDylib); + if ( dylibResult != NULL ) { + return dylibResult; + } + break; + case Options::kStaticExecutable: + case Options::kDyld: + case Options::kPreload: + case Options::kObjectFile: + case Options::kKextBundle: + dylibsNotAllowed = true; + break; } // see if it is a static library @@ -307,6 +354,15 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib archOpts.objcABI2 = _options.objCABIVersion2POverride(); archOpts.verboseLoad = _options.whyLoad(); archOpts.logAllFiles = _options.logAllFiles(); + // Set ObjSource Kind, libclang_rt is compiler static library + const char* libName = strrchr(info.path, '/'); + if ( (libName != NULL) && (strncmp(libName, "/libclang_rt", 12) == 0) ) + archOpts.objOpts.srcKind = ld::relocatable::File::kSourceCompilerArchive; + else + archOpts.objOpts.srcKind = ld::relocatable::File::kSourceArchive; + archOpts.objOpts.treateBitcodeAsData = _options.bitcodeKind() == Options::kBitcodeAsData; + archOpts.objOpts.usingBitcode = _options.bundleBitcode(); + ld::archive::File* archiveResult = ::archive::parse(p, len, info.path, info.modTime, info.ordinal, archOpts); if ( archiveResult != NULL ) { OSAtomicAdd64(len, &_totalArchiveSize); @@ -342,6 +398,13 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } } + if ( dylibsNotAllowed ) { + cpu_type_t dummy1; + cpu_type_t dummy2; + if ( mach_o::dylib::isDylibFile(p, &dummy1, &dummy2) ) + throw "ignoring unexpected dylib file"; + } + // error handling if ( ((fat_header*)p)->magic == OSSwapBigToHostInt32(FAT_MAGIC) ) { throwf("missing required architecture %s in file %s (%u slices)", _options.architectureName(), info.path, sliceCount); @@ -367,12 +430,31 @@ void InputFiles::logDylib(ld::File* file, bool indirect) logTraceInfo("[Logging for XBS] Used upward dynamic library: %s\n", fullPath); } else { - if ( indirect ) + if ( indirect ) logTraceInfo("[Logging for XBS] Used indirect dynamic library: %s\n", fullPath); - else + else logTraceInfo("[Logging for XBS] Used dynamic library: %s\n", fullPath); } } + + if ( _options.dumpDependencyInfo() ) { + const ld::dylib::File* dylib = dynamic_cast(file); + if ( file == _bundleLoader ) { + _options.dumpDependency(Options::depBundleLoader, file->path()); + } + else if ( (dylib != NULL ) && dylib->willBeUpwardDylib() ) { + if ( indirect ) + _options.dumpDependency(Options::depUpwardIndirectDylib, file->path()); + else + _options.dumpDependency(Options::depUpwardDirectDylib, file->path()); + } + else { + if ( indirect ) + _options.dumpDependency(Options::depIndirectDylib, file->path()); + else + _options.dumpDependency(Options::depDirectDylib, file->path()); + } + } } void InputFiles::logArchive(ld::File* file) const @@ -398,7 +480,7 @@ void InputFiles::logTraceInfo(const char* format, ...) const if ( trace_file_path != NULL ) { trace_file = open(trace_file_path, O_WRONLY | O_APPEND | O_CREAT, 0666); if ( trace_file == -1 ) - throwf("Could not open or create trace file: %s", trace_file_path); + throwf("Could not open or create trace file (errno=%d): %s", errno, trace_file_path); } else { trace_file = fileno(stderr); @@ -422,6 +504,7 @@ void InputFiles::logTraceInfo(const char* format, ...) const } } + ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* fromPath) { //fprintf(stderr, "findDylib(%s, %s)\n", installPath, fromPath); @@ -437,6 +520,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from Options::FileInfo info = _options.findFile(dit->useInstead); _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); info.ordinal = _indirectDylibOrdinal; + info.options.fIndirectDylib = true; ld::File* reader = this->makeFile(info, true); ld::dylib::File* dylibReader = dynamic_cast(reader); if ( dylibReader != NULL ) { @@ -469,6 +553,7 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from Options::FileInfo info = _options.findFileUsingPaths(installPath); _indirectDylibOrdinal = _indirectDylibOrdinal.nextIndirectDylibOrdinal(); info.ordinal = _indirectDylibOrdinal; + info.options.fIndirectDylib = true; try { ld::File* reader = this->makeFile(info, true); ld::dylib::File* dylibReader = dynamic_cast(reader); @@ -483,24 +568,131 @@ ld::dylib::File* InputFiles::findDylib(const char* installPath, const char* from throwf("indirect dylib at %s is not a dylib", info.path); } catch (const char* msg) { - throwf("in %s, %s", info.path, msg); + throwf("in '%s', %s", info.path, msg); } } } - -void InputFiles::createIndirectDylibs() -{ - _allDirectDylibsLoaded = true; - _indirectDylibOrdinal = ld::File::Ordinal::indirectDylibBase(); - - // mark all dylibs initially specified as required and check if they can be used +// mark all dylibs initially specified as required, and check if they can be used +void InputFiles::markExplicitlyLinkedDylibs() +{ for (InstallNameToDylib::iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); it++) { it->second->setExplicitlyLinked(); this->checkDylibClientRestrictions(it->second); } - +} + +bool InputFiles::frameworkAlreadyLoaded(const char* path, const char* frameworkName) +{ + for (ld::File* file : _inputFiles) { + if ( strcmp(path, file->path()) == 0 ) + return true; + } + for (ld::dylib::File* dylibx : _allDylibs) { + const char* fname = dylibx->frameworkName(); + if ( fname == NULL ) + continue; + if ( strcmp(frameworkName, fname) == 0 ) + return true; + } + return false; +} + +bool InputFiles::libraryAlreadyLoaded(const char* path) +{ + for (ld::File* file : _inputFiles) { + if ( strcmp(path, file->path()) == 0 ) + return true; + } + for (ld::dylib::File* dylib : _allDylibs) { + if ( strcmp(path, dylib->path()) == 0 ) + return true; + } + for (const LibraryInfo& libInfo : _searchLibraries) { + if ( strcmp(path, libInfo.archive()->path()) == 0 ) + return true; + } + + return false; +} + + +void InputFiles::addLinkerOptionLibraries(ld::Internal& state, ld::File::AtomHandler& handler) +{ + if ( _options.outputKind() == Options::kObjectFile ) + return; + + // process frameworks specified in .o linker options + for (CStringSet::const_iterator it = state.linkerOptionFrameworks.begin(); it != state.linkerOptionFrameworks.end(); ++it) { + const char* frameworkName = *it; + if ( state.linkerOptionFrameworksProcessed.count(frameworkName) ) + continue; + Options::FileInfo info = _options.findFramework(frameworkName); + if ( ! this->frameworkAlreadyLoaded(info.path, frameworkName) ) { + info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); + try { + ld::File* reader = this->makeFile(info, true); + ld::dylib::File* dylibReader = dynamic_cast(reader); + if ( dylibReader != NULL ) { + if ( ! dylibReader->installPathVersionSpecific() ) { + dylibReader->forEachAtom(handler); + dylibReader->setImplicitlyLinked(); + this->addDylib(dylibReader, info); + } + } + else { + throwf("framework linker option at %s is not a dylib", info.path); + } + } + catch (const char* msg) { + warning("Auto-Linking supplied '%s', %s", info.path, msg); + } + } + state.linkerOptionFrameworksProcessed.insert(frameworkName); + } + // process libraries specified in .o linker options + for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) { + const char* libName = *it; + if ( state.linkerOptionLibrariesProcessed.count(libName) ) + continue; + Options::FileInfo info = _options.findLibrary(libName); + if ( ! this->libraryAlreadyLoaded(info.path) ) { + info.ordinal = _linkerOptionOrdinal.nextLinkerOptionOrdinal(); + try { + // -force_load_swift_libs + info.options.fForceLoad = _options.forceLoadSwiftLibs() && (strncmp(libName, "swift", 5) == 0); + ld::File* reader = this->makeFile(info, true); + ld::dylib::File* dylibReader = dynamic_cast(reader); + ld::archive::File* archiveReader = dynamic_cast(reader); + if ( dylibReader != NULL ) { + dylibReader->forEachAtom(handler); + dylibReader->setImplicitlyLinked(); + this->addDylib(dylibReader, info); + } + else if ( archiveReader != NULL ) { + _searchLibraries.push_back(LibraryInfo(archiveReader)); + if ( _options.dumpDependencyInfo() ) + _options.dumpDependency(Options::depArchive, archiveReader->path()); + // -force_load_swift_libs + if (info.options.fForceLoad) { + archiveReader->forEachAtom(handler); + } + } + else { + throwf("linker option dylib at %s is not a dylib", info.path); + } + } + catch (const char* msg) { + warning("Auto-Linking supplied '%s', %s", info.path, msg); + } + } + state.linkerOptionLibrariesProcessed.insert(libName); + } +} + +void InputFiles::createIndirectDylibs() +{ // keep processing dylibs until no more dylibs are added unsigned long lastMapSize = 0; std::set dylibsProcessed; @@ -541,9 +733,11 @@ void InputFiles::createIndirectDylibs() void InputFiles::createOpaqueFileSections() { - // extra command line section always at end + // extra command line sections always at end for (Options::ExtraSection::const_iterator it=_options.extraSectionsBegin(); it != _options.extraSectionsEnd(); ++it) { _inputFiles.push_back(opaque_section::parse(it->segmentName, it->sectionName, it->path, it->data, it->dataLen)); + if ( _options.dumpDependencyInfo() ) + _options.dumpDependency(Options::depSection, it->path); } } @@ -636,20 +830,27 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName) _inferredArch = true; // scan all input files, looking for a thin .o file. // the first one found is presumably the architecture to link - uint8_t buffer[sizeof(mach_header_64)]; + uint8_t buffer[4096]; const std::vector& files = opts.getInputFiles(); for (std::vector::const_iterator it = files.begin(); it != files.end(); ++it) { int fd = ::open(it->path, O_RDONLY, 0); if ( fd != -1 ) { - ssize_t amount = read(fd, buffer, sizeof(buffer)); - ::close(fd); - if ( amount >= (ssize_t)sizeof(buffer) ) { - cpu_type_t type; - cpu_subtype_t subtype; - if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype) ) { - opts.setArchitecture(type, subtype); - *archName = opts.architectureName(); - return; + struct stat stat_buf; + if ( fstat(fd, &stat_buf) != -1) { + ssize_t readAmount = stat_buf.st_size; + if ( 4096 < readAmount ) + readAmount = 4096; + ssize_t amount = read(fd, buffer, readAmount); + ::close(fd); + if ( amount >= readAmount ) { + cpu_type_t type; + cpu_subtype_t subtype; + Options::Platform platform; + if ( mach_o::relocatable::isObjectFile(buffer, &type, &subtype, &platform) ) { + opts.setArchitecture(type, subtype, platform); + *archName = opts.architectureName(); + return; + } } } } @@ -658,11 +859,11 @@ void InputFiles::inferArchitecture(Options& opts, const char** archName) // no thin .o files found, so default to same architecture this tool was built as warning("-arch not specified"); #if __i386__ - opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL); + opts.setArchitecture(CPU_TYPE_I386, CPU_SUBTYPE_X86_ALL, Options::kPlatformOSX); #elif __x86_64__ - opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL); + opts.setArchitecture(CPU_TYPE_X86_64, CPU_SUBTYPE_X86_64_ALL, Options::kPlatformOSX); #elif __arm__ - opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6); + opts.setArchitecture(CPU_TYPE_ARM, CPU_SUBTYPE_ARM_V6, Options::kPlatformOSX); #else #error unknown default architecture #endif @@ -674,8 +875,10 @@ InputFiles::InputFiles(Options& opts, const char** archName) : _totalObjectSize(0), _totalArchiveSize(0), _totalObjectLoaded(0), _totalArchivesLoaded(0), _totalDylibsLoaded(0), _options(opts), _bundleLoader(NULL), - _allDirectDylibsLoaded(false), _inferredArch(false), _fileMonitor(-1), - _exception(NULL) + _inferredArch(false), + _exception(NULL), + _indirectDylibOrdinal(ld::File::Ordinal::indirectDylibBase()), + _linkerOptionOrdinal(ld::File::Ordinal::linkeOptionBase()) { // fStartCreateReadersTime = mach_absolute_time(); if ( opts.architecture() == 0 ) { @@ -783,7 +986,8 @@ void InputFiles::parseWorkerThread() { if (_s_logPThreads) printf("parsing index %u\n", slot); try { file = makeFile(entry, false); - } catch (const char *msg) { + } + catch (const char *msg) { if ( (strstr(msg, "architecture") != NULL) && !_options.errorOnOtherArchFiles() ) { if ( _options.ignoreOtherArchInputFiles() ) { // ignore, because this is about an architecture not in use @@ -791,8 +995,12 @@ void InputFiles::parseWorkerThread() { else { warning("ignoring file %s, %s", entry.path, msg); } - } else { - exception = msg; + } + else if ( strstr(msg, "ignoring unexpected") != NULL ) { + warning("%s, %s", entry.path, msg); + } + else { + asprintf((char**)&exception, "%s file '%s'", msg, entry.path); } file = new IgnoredFile(entry.path, entry.modTime, entry.ordinal, ld::File::Other); } @@ -804,7 +1012,8 @@ void InputFiles::parseWorkerThread() { // We are about to die, so set to zero to stop other threads from doing unneeded work. _remainingInputFiles = 0; _exception = exception; - } else { + } + else { _inputFiles[slot] = file; if (_neededFileSlot == slot) pthread_cond_signal(&_newFileAvailable); @@ -869,20 +1078,23 @@ ld::File* InputFiles::addDylib(ld::dylib::File* reader, const Options::FileInfo& } // remove warning for Same install name for CoreServices and CFNetwork? //if ( !dylibOnCommandLineTwice && !isSymlink ) - // warning("dylibs with same install name: %s and %s", pos->second->path(), reader->path()); + // warning("dylibs with same install name: %p %s and %p %s", pos->second, pos->second->path(), reader, reader->path()); } } else if ( info.options.fBundleLoader ) _bundleLoader = reader; // log direct readers - if ( !_allDirectDylibsLoaded ) + if ( ! info.options.fIndirectDylib ) this->logDylib(reader, false); // update stats _totalDylibsLoaded++; - _searchLibraries.push_back(LibraryInfo(reader)); + // just add direct libraries to search-first list + if ( ! info.options.fIndirectDylib ) + _searchLibraries.push_back(LibraryInfo(reader)); + return reader; } @@ -918,7 +1130,7 @@ void InputFiles::waitForInputFiles() if (it == fileMap.end()) throwf("pipelined linking error - not in file list: %s\n", path_buf); Options::FileInfo* inputInfo = (Options::FileInfo*)it->second; - if (!inputInfo->checkFileExists()) + if (!inputInfo->checkFileExists(_options)) throwf("pipelined linking error - file does not exist: %s\n", inputInfo->path); pthread_mutex_lock(&_parseLock); if (_idleWorkers) @@ -946,7 +1158,7 @@ void InputFiles::waitForInputFiles(InputFiles *inputFiles) { #endif -void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) +void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler, ld::Internal& state) { // add all direct object, archives, and dylibs const std::vector& files = _options.getInputFiles(); @@ -986,6 +1198,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) { ld::relocatable::File* reloc = (ld::relocatable::File*)file; _options.snapshot().recordObjectFile(reloc->path()); + if ( _options.dumpDependencyInfo() ) + _options.dumpDependency(Options::depObjectFile, reloc->path()); } break; case ld::File::Dylib: @@ -1001,6 +1215,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) if ( (info.options.fForceLoad || _options.fullyLoadArchives()) && _options.traceArchives() ) logArchive(archive); _searchLibraries.push_back(LibraryInfo(archive)); + if ( _options.dumpDependencyInfo() ) + _options.dumpDependency(Options::depArchive, archive->path()); } break; case ld::File::Other: @@ -1014,6 +1230,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) file->forEachAtom(handler); } + markExplicitlyLinkedDylibs(); + addLinkerOptionLibraries(state, handler); createIndirectDylibs(); createOpaqueFileSections(); @@ -1070,11 +1288,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searchArchives, bool dataSymbolOnly, ld::File::AtomHandler& handler) const { // Check each input library. - std::vector::const_iterator libIterator = _searchLibraries.begin(); - - - while (libIterator != _searchLibraries.end()) { - LibraryInfo lib = *libIterator; + for (std::vector::const_iterator it=_searchLibraries.begin(); it != _searchLibraries.end(); ++it) { + LibraryInfo lib = *it; if (lib.isDylib()) { if (searchDylibs) { ld::dylib::File *dylibFile = lib.dylib(); @@ -1098,7 +1313,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc logArchive(archiveFile); _options.snapshot().recordArchive(archiveFile->path()); // found data definition in static library, done - return true; + return true; } } else { @@ -1112,7 +1327,6 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc } } } - libIterator++; } // search indirect dylibs @@ -1149,7 +1363,7 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc bool InputFiles::searchWeakDefInDylib(const char* name) const { - // search all relevant dylibs to see if any of a weak-def with this name + // search all relevant dylibs to see if any have a weak-def with this name for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { ld::dylib::File* dylibFile = it->second; if ( dylibFile->implicitlyLinked() || dylibFile->explicitlyLinked() ) { @@ -1166,6 +1380,14 @@ static bool vectorContains(const std::vector& vec, ld::dylib:: return std::find(vec.begin(), vec.end(), key) != vec.end(); } +struct DylibByInstallNameSorter +{ + bool operator()(const ld::dylib::File* left, const ld::dylib::File* right) + { + return (strcmp(left->installPath(), right->installPath()) < 0); + } +}; + void InputFiles::dylibs(ld::Internal& state) { bool dylibsOK = false; @@ -1200,20 +1422,24 @@ void InputFiles::dylibs(ld::Internal& state) } // add implicitly linked dylibs if ( _options.nameSpace() == Options::kTwoLevelNameSpace ) { + std::vector implicitDylibs; for (InstallNameToDylib::const_iterator it=_installPathToDylibs.begin(); it != _installPathToDylibs.end(); ++it) { ld::dylib::File* dylibFile = it->second; if ( dylibFile->implicitlyLinked() && dylibsOK ) { - if ( ! vectorContains(state.dylibs, dylibFile) ) { - state.dylibs.push_back(dylibFile); + if ( ! vectorContains(implicitDylibs, dylibFile) ) { + implicitDylibs.push_back(dylibFile); } } } + // make implicit dylib order be deterministic by sorting by install_name + std::sort(implicitDylibs.begin(), implicitDylibs.end(), DylibByInstallNameSorter()); + state.dylibs.insert(state.dylibs.end(), implicitDylibs.begin(), implicitDylibs.end()); } //fprintf(stderr, "all dylibs:\n"); //for(std::vector::iterator it=state.dylibs.begin(); it != state.dylibs.end(); ++it) { // const ld::dylib::File* dylib = *it; - // fprintf(stderr, " %p %s\n", dylib, dylib->path()); + // fprintf(stderr, " %p impl=%d %s\n", dylib, dylib->implicitlyLinked(), dylib->path()); //} // and -bundle_loader @@ -1228,4 +1454,3 @@ void InputFiles::dylibs(ld::Internal& state) } // namespace tool } // namespace ld -