diff --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h --- a/lld/MachO/Driver.h +++ b/lld/MachO/Driver.h @@ -57,6 +57,17 @@ DylibFile *umbrella = nullptr, bool isBundleLoader = false); +// Search for all possible combinations of `{root}/{name}.{extension}`. +// If \p extensions are not specified, then just search for `{root}/{name}`. +llvm::Optional +findPathCombination(const llvm::Twine &name, + const std::vector &roots, + ArrayRef extensions = {""}); + +// If -syslibroot is specified, absolute paths to non-object files may be +// rerooted. +llvm::StringRef rerootPath(llvm::StringRef path); + llvm::Optional loadArchiveMember(MemoryBufferRef, uint32_t modTime, StringRef archiveName, bool objCOnly); diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -77,26 +77,6 @@ } } -// Search for all possible combinations of `{root}/{name}.{extension}`. -// If \p extensions are not specified, then just search for `{root}/{name}`. -static Optional -findPathCombination(const Twine &name, const std::vector &roots, - ArrayRef extensions = {""}) { - SmallString<261> base; - for (StringRef dir : roots) { - base = dir; - path::append(base, name); - for (StringRef ext : extensions) { - Twine location = base + ext; - if (fs::exists(location)) - return saver.save(location.str()); - else - depTracker->logFileNotFound(location); - } - } - return {}; -} - static Optional findLibrary(StringRef name) { if (config->searchDylibsFirst) { if (Optional path = findPathCombination( @@ -109,19 +89,6 @@ {".tbd", ".dylib", ".a"}); } -// If -syslibroot is specified, absolute paths to non-object files may be -// rerooted. -static StringRef rerootPath(StringRef path) { - if (!path::is_absolute(path, path::Style::posix) || path.endswith(".o")) - return path; - - if (Optional rerootedPath = - findPathCombination(path, config->systemLibraryRoots)) - return *rerootedPath; - - return path; -} - static Optional findFramework(StringRef name) { SmallString<260> symlink; StringRef suffix; @@ -244,7 +211,7 @@ std::vector v; Error err = Error::success(); - // Thin archives refer to .o files, so --reproduces needs the .o files too. + // Thin archives refer to .o files, so --reproduce needs the .o files too. bool addToTar = archive->isThin() && tar; for (const Archive::Child &c : archive->children(err)) { @@ -925,6 +892,13 @@ return true; } + config = make(); + symtab = make(); + target = createTargetInfo(args); + depTracker = + make(args.getLastArgValue(OPT_dependency_info)); + + config->systemLibraryRoots = getSystemLibraryRoots(args); if (const char *path = getReproduceOption(args)) { // Note that --reproduce is a debug option so you can ignore it // if you are trying to understand the whole picture of the code. @@ -939,13 +913,6 @@ } } - config = make(); - symtab = make(); - target = createTargetInfo(args); - - depTracker = - make(args.getLastArgValue(OPT_dependency_info, "")); - if (auto *arg = args.getLastArg(OPT_threads_eq)) { StringRef v(arg->getValue()); unsigned threads = 0; @@ -1035,7 +1002,6 @@ config->undefinedSymbolTreatment = getUndefinedSymbolTreatment(args); - config->systemLibraryRoots = getSystemLibraryRoots(args); config->librarySearchPaths = getLibrarySearchPaths(args, config->systemLibraryRoots); config->frameworkSearchPaths = diff --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp --- a/lld/MachO/DriverUtils.cpp +++ b/lld/MachO/DriverUtils.cpp @@ -118,6 +118,14 @@ return std::string(s); } +static std::string rewriteInputPath(StringRef s) { + // Don't bother rewriting "absolute" paths that are actually under the + // syslibroot; simply rewriting the syslibroot is sufficient. + if (rerootPath(s) == s && fs::exists(s)) + return relativeToRoot(s); + return std::string(s); +} + // Reconstructs command line arguments so that so that you can re-run // the same command with the same inputs. This is for --reproduce. std::string macho::createResponseFile(const InputArgList &args) { @@ -130,7 +138,7 @@ case OPT_reproduce: break; case OPT_INPUT: - os << quote(rewritePath(arg->getValue())) << "\n"; + os << quote(rewriteInputPath(arg->getValue())) << "\n"; break; case OPT_o: os << "-o " << quote(path::filename(arg->getValue())) << "\n"; @@ -138,13 +146,17 @@ case OPT_filelist: if (Optional buffer = readFile(arg->getValue())) for (StringRef path : args::getLines(*buffer)) - os << quote(rewritePath(path)) << "\n"; + os << quote(rewriteInputPath(path)) << "\n"; + break; + case OPT_force_load: + case OPT_weak_library: + os << arg->getSpelling() << " " + << quote(rewriteInputPath(arg->getValue())) << "\n"; break; case OPT_F: case OPT_L: case OPT_bundle_loader: case OPT_exported_symbols_list: - case OPT_force_load: case OPT_order_file: case OPT_rpath: case OPT_syslibroot: @@ -217,6 +229,36 @@ return file; } +Optional +macho::findPathCombination(const Twine &name, + const std::vector &roots, + ArrayRef extensions) { + SmallString<261> base; + for (StringRef dir : roots) { + base = dir; + path::append(base, name); + for (StringRef ext : extensions) { + Twine location = base + ext; + if (fs::exists(location)) + return saver.save(location.str()); + else + depTracker->logFileNotFound(location); + } + } + return {}; +} + +StringRef macho::rerootPath(StringRef path) { + if (!path::is_absolute(path, path::Style::posix) || path.endswith(".o")) + return path; + + if (Optional rerootedPath = + findPathCombination(path, config->systemLibraryRoots)) + return *rerootedPath; + + return path; +} + Optional macho::loadArchiveMember(MemoryBufferRef mb, uint32_t modTime, StringRef archiveName, diff --git a/lld/test/MachO/reroot-path.s b/lld/test/MachO/reroot-path.s --- a/lld/test/MachO/reroot-path.s +++ b/lld/test/MachO/reroot-path.s @@ -23,14 +23,30 @@ # RUN: %lld -dylib %t/bar.o -o %t/%:t/libbar.dylib ## Test our various file-loading flags to make sure all bases are covered. -# RUN: %lld -lSystem -syslibroot %t %t/foo.a %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" -# RUN: %lld -lSystem -syslibroot %t -force_load %t/foo.a -force_load %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" -# RUN: %lld -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" -# RUN: %lld -lSystem -syslibroot %t -weak_library %t/libfoo.dylib -weak_library %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: %lld --reproduce %t/repro1.tar -lSystem -syslibroot %t %t/foo.a %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: tar xf %t/repro1.tar -C %t +# RUN: cd %t/repro1; ld64.lld @response.txt | FileCheck %s -DDIR="%:t/%:t" + +# RUN: %lld --reproduce %t/repro2.tar -lSystem -syslibroot %t -force_load %t/foo.a -force_load %t/bar.a %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: tar xf %t/repro2.tar -C %t +# RUN: cd %t/repro2; ld64.lld @response.txt | FileCheck %s -DDIR="%:t/%:t" + +# RUN: %lld --reproduce %t/repro3.tar -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: tar xf %t/repro3.tar -C %t +# RUN: cd %t/repro3; ld64.lld @response.txt | FileCheck %s -DDIR="%:t/%:t" + +# RUN: %lld --reproduce %t/repro4.tar -lSystem -syslibroot %t -weak_library %t/libfoo.dylib -weak_library %t/libbar.dylib %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: tar xf %t/repro4.tar -C %t +# RUN: cd %t/repro4; ld64.lld @response.txt | FileCheck %s -DDIR="%:t/%:t" + # RUN: echo "%t/libfoo.dylib" > %t/filelist # RUN: echo "%t/libbar.dylib" >> %t/filelist -# RUN: %lld -lSystem -syslibroot %t -filelist %t/filelist %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" -# CHECK: [[DIR]]/{{(lib)?}}bar +# RUN: %lld --reproduce %t/repro5.tar -lSystem -syslibroot %t -filelist %t/filelist %t/test.o -o /dev/null -t | FileCheck %s -DDIR="%t/%:t" +# RUN: tar xf %t/repro5.tar -C %t +# RUN: cd %t/repro5; ld64.lld @response.txt | FileCheck %s -DDIR="%:t/%:t" + +## The {{^}} ensures that we only match relative paths if DIR is relative. +# CHECK: {{^}}[[DIR]]/{{(lib)?}}bar ## Paths to object files don't get rerooted. # RUN: mv %t/bar.o %t/%:t/bar.o @@ -42,8 +58,15 @@ ## rerooted path takes precedence over the original path. We will get an ## undefined symbol error since we aren't loading %t/libfoo.dylib. # RUN: cp %t/%:t/libbar.dylib %t/%:t/libfoo.dylib -# RUN: not %lld -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o \ -# RUN: -o /dev/null 2>&1 | FileCheck %s --check-prefix=UNDEF +# RUN: not %lld --reproduce %t/repro6.tar -lSystem -syslibroot %t %t/libfoo.dylib %t/libbar.dylib %t/test.o \ +# RUN: -o /dev/null -t 2> %t/error | FileCheck %s -DDIR="%t/%:t" --check-prefix=FOO +# RUN: FileCheck %s --check-prefix=UNDEF < %t/error + +# RUN: tar xf %t/repro6.tar -C %t +# RUN: cd %t/repro6; not ld64.lld @response.txt 2> %t/error | FileCheck %s -DDIR="%:t/%:t" --check-prefix=FOO +# RUN: FileCheck %s --check-prefix=UNDEF < %t/error + +# FOO: [[DIR]]/libfoo.dylib # UNDEF: error: undefined symbol: _foo #--- foo.s