X-Git-Url: https://git.saurik.com/apple/ld64.git/blobdiff_plain/ebf6f43431fe84b7b17822014a6d1f0169516e93..ba348e2165668ae0f4af8b349fc4a6d0910950ed:/src/ld/InputFiles.cpp diff --git a/src/ld/InputFiles.cpp b/src/ld/InputFiles.cpp index 766b17c..30c0875 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 @@ -62,6 +61,7 @@ #include "archive_file.h" #include "lto_file.h" #include "opaque_section_file.h" +#include "MachOFileAbstraction.hpp" #include "Snapshot.h" const bool _s_logPThreads = false; @@ -80,16 +80,15 @@ public: class DSOHandleAtom : public ld::Atom { public: DSOHandleAtom(const char* nm, ld::Atom::Scope sc, - ld::Atom::SymbolTableInclusion inc, bool preload=false) - : ld::Atom(preload ? _s_section_preload : _s_section, - ld::Atom::definitionRegular, ld::Atom::combineNever, + ld::Atom::SymbolTableInclusion inc, ld::Section& sect=_s_section) + : ld::Atom(sect, ld::Atom::definitionRegular, + (sect == _s_section_text) ? ld::Atom::combineByName : ld::Atom::combineNever, + // make "weak def" so that link succeeds even if app defines __dso_handle sc, ld::Atom::typeUnclassified, inc, true, false, false, ld::Atom::Alignment(1)), _name(nm) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } - virtual const char* name() const { return _name; } + virtual const char* name() const { return _name; } virtual uint64_t size() const { return 0; } virtual uint64_t objectAddress() const { return 0; } virtual void copyRawContent(uint8_t buffer[]) const @@ -100,6 +99,7 @@ public: static ld::Section _s_section; static ld::Section _s_section_preload; + static ld::Section _s_section_text; static DSOHandleAtom _s_atomAll; static DSOHandleAtom _s_atomExecutable; static DSOHandleAtom _s_atomDylib; @@ -107,18 +107,21 @@ public: static DSOHandleAtom _s_atomDyld; static DSOHandleAtom _s_atomObjectFile; static DSOHandleAtom _s_atomPreload; + static DSOHandleAtom _s_atomPreloadDSO; private: const char* _name; }; ld::Section DSOHandleAtom::_s_section("__TEXT", "__mach_header", ld::Section::typeMachHeader, true); ld::Section DSOHandleAtom::_s_section_preload("__HEADER", "__mach_header", ld::Section::typeMachHeader, true); +ld::Section DSOHandleAtom::_s_section_text("__TEXT", "__text", ld::Section::typeCode, false); DSOHandleAtom DSOHandleAtom::_s_atomAll("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomExecutable("__mh_execute_header", ld::Atom::scopeGlobal, ld::Atom::symbolTableInAndNeverStrip); DSOHandleAtom DSOHandleAtom::_s_atomDylib("__mh_dylib_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomBundle("__mh_bundle_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomDyld("__mh_dylinker_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); DSOHandleAtom DSOHandleAtom::_s_atomObjectFile("__mh_object_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn); -DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, true); +DSOHandleAtom DSOHandleAtom::_s_atomPreload("__mh_preload_header", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_preload); +DSOHandleAtom DSOHandleAtom::_s_atomPreloadDSO("___dso_handle", ld::Atom::scopeLinkageUnit, ld::Atom::symbolTableNotIn, _s_section_text); @@ -131,8 +134,6 @@ public: _size(sz) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } virtual const char* name() const { return "page zero"; } virtual uint64_t size() const { return _size; } virtual uint64_t objectAddress() const { return 0; } @@ -159,8 +160,6 @@ public: _size(sz) {} virtual ld::File* file() const { return NULL; } - virtual bool translationUnitSource(const char** dir, const char** ) const - { return false; } virtual const char* name() const { return "custom stack"; } virtual uint64_t size() const { return _size; } virtual uint64_t objectAddress() const { return 0; } @@ -183,7 +182,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; @@ -195,7 +198,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 ) { @@ -276,7 +288,12 @@ 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.subType = _options.subArchitecture(); ld::relocatable::File* objResult = mach_o::relocatable::parse(p, len, info.path, info.modTime, info.ordinal, objOpts); if ( objResult != NULL ) { @@ -286,7 +303,7 @@ 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, _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); @@ -294,11 +311,27 @@ ld::File* InputFiles::makeFile(const Options::FileInfo& info, bool indirectDylib } // 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; + 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; + } + 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 ::archive::ParserOptions archOpts; archOpts.objOpts = objOpts; @@ -343,6 +376,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); @@ -368,12 +408,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 @@ -399,7 +458,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); @@ -423,6 +482,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); @@ -438,6 +498,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 ) { @@ -470,6 +531,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); @@ -484,24 +546,98 @@ 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::libraryAlreadyLoaded(const char* path) +{ + for (std::vector::const_iterator it = _inputFiles.begin(); it != _inputFiles.end(); ++it) { + if ( strcmp(path, (*it)->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; + Options::FileInfo info = _options.findFramework(frameworkName); + if ( ! this->libraryAlreadyLoaded(info.path) ) { + 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->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); + } + } + } + // process libraries specified in .o linker options + for (CStringSet::const_iterator it = state.linkerOptionLibraries.begin(); it != state.linkerOptionLibraries.end(); ++it) { + const char* libName = *it; + 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->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); + } + } + } +} + +void InputFiles::createIndirectDylibs() +{ // keep processing dylibs until no more dylibs are added unsigned long lastMapSize = 0; std::set dylibsProcessed; @@ -542,9 +678,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); } } @@ -675,8 +813,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 ) { @@ -784,7 +924,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 @@ -792,8 +933,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); } @@ -805,7 +950,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); @@ -870,20 +1016,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; } @@ -919,7 +1068,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) @@ -947,7 +1096,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(); @@ -987,6 +1136,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: @@ -1002,6 +1153,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: @@ -1015,6 +1168,8 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) file->forEachAtom(handler); } + markExplicitlyLinkedDylibs(); + addLinkerOptionLibraries(state, handler); createIndirectDylibs(); createOpaqueFileSections(); @@ -1053,7 +1208,9 @@ void InputFiles::forEachInitialAtom(ld::File::AtomHandler& handler) case Options::kPreload: // add implicit __mh_preload_header label handler.doAtom(DSOHandleAtom::_s_atomPreload); - handler.doAtom(DSOHandleAtom::_s_atomAll); + // add implicit __dso_handle label, but put it in __text section because + // with -preload the mach_header is no in the address space. + handler.doAtom(DSOHandleAtom::_s_atomPreloadDSO); break; case Options::kObjectFile: handler.doAtom(DSOHandleAtom::_s_atomObjectFile); @@ -1069,11 +1226,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(); @@ -1097,7 +1251,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 { @@ -1111,7 +1265,6 @@ bool InputFiles::searchLibraries(const char* name, bool searchDylibs, bool searc } } } - libIterator++; } // search indirect dylibs @@ -1148,7 +1301,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() ) { @@ -1165,6 +1318,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; @@ -1199,14 +1360,18 @@ 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"); @@ -1227,4 +1392,3 @@ void InputFiles::dylibs(ld::Internal& state) } // namespace tool } // namespace ld -