Index: lld/trunk/COFF/Driver.h =================================================================== --- lld/trunk/COFF/Driver.h +++ lld/trunk/COFF/Driver.h @@ -43,8 +43,8 @@ class ArgParser { public: - // Concatenate LINK environment variable and given arguments and parse them. - llvm::opt::InputArgList parseLINK(std::vector args); + // Parses command line options. + llvm::opt::InputArgList parse(llvm::ArrayRef args); // Tokenizes a given string and then parses as command line options. llvm::opt::InputArgList parse(StringRef s) { return parse(tokenize(s)); } @@ -56,8 +56,8 @@ parseDirectives(StringRef s); private: - // Parses command line options. - llvm::opt::InputArgList parse(llvm::ArrayRef args); + // Concatenate LINK environment variable. + void addLINK(SmallVector &argv); std::vector tokenize(StringRef s); Index: lld/trunk/COFF/Driver.cpp =================================================================== --- lld/trunk/COFF/Driver.cpp +++ lld/trunk/COFF/Driver.cpp @@ -1094,7 +1094,7 @@ // Parse command line options. ArgParser parser; - opt::InputArgList args = parser.parseLINK(argsArr); + opt::InputArgList args = parser.parse(argsArr); // Parse and evaluate -mllvm options. std::vector v; @@ -1162,7 +1162,8 @@ searchPaths.push_back(""); for (auto *arg : args.filtered(OPT_libpath)) searchPaths.push_back(arg->getValue()); - addLibSearchPaths(); + if (!args.hasArg(OPT_lldignoreenv)) + addLibSearchPaths(); // Handle /ignore for (auto *arg : args.filtered(OPT_ignore)) { Index: lld/trunk/COFF/DriverUtils.cpp =================================================================== --- lld/trunk/COFF/DriverUtils.cpp +++ lld/trunk/COFF/DriverUtils.cpp @@ -808,13 +808,17 @@ // We need to get the quoting style for response files before parsing all // options so we parse here before and ignore all the options but - // --rsp-quoting. + // --rsp-quoting and /lldignoreenv. + // (This means --rsp-quoting can't be added through %LINK%.) opt::InputArgList args = table.ParseArgs(argv, missingIndex, missingCount); - // Expand response files (arguments in the form of @) - // and then parse the argument again. + + // Expand response files (arguments in the form of @) and insert + // flags from %LINK% and %_LINK_%, and then parse the argument again. SmallVector expandedArgv(argv.data(), argv.data() + argv.size()); + if (!args.hasArg(OPT_lldignoreenv)) + addLINK(expandedArgv); cl::ExpandResponseFiles(saver, getQuotingStyle(args), expandedArgv); args = table.ParseArgs(makeArrayRef(expandedArgv).drop_front(), missingIndex, missingCount); @@ -884,7 +888,7 @@ // link.exe has an interesting feature. If LINK or _LINK_ environment // variables exist, their contents are handled as command line strings. // So you can pass extra arguments using them. -opt::InputArgList ArgParser::parseLINK(std::vector argv) { +void ArgParser::addLINK(SmallVector &argv) { // Concatenate LINK env and command line arguments, and then parse them. if (Optional s = Process::GetEnv("LINK")) { std::vector v = tokenize(*s); @@ -894,7 +898,6 @@ std::vector v = tokenize(*s); argv.insert(std::next(argv.begin()), v.begin(), v.end()); } - return parse(argv); } std::vector ArgParser::tokenize(StringRef s) { Index: lld/trunk/COFF/Options.td =================================================================== --- lld/trunk/COFF/Options.td +++ lld/trunk/COFF/Options.td @@ -43,6 +43,8 @@ HelpText<"Act like lib.exe; must be first argument if present">; def libpath : P<"libpath", "Additional library search path">; def linkrepro : P<"linkrepro", "Dump linker invocation and input files for debugging">; +def lldignoreenv : F<"lldignoreenv">, + HelpText<"Ignore environment variables like %LIB%">; def lldltocache : P<"lldltocache", "Path to ThinLTO cached object file directory">; def lldltocachepolicy : P<"lldltocachepolicy", "Pruning policy for the ThinLTO cache">; def lldsavetemps : F<"lldsavetemps">, Index: lld/trunk/docs/ReleaseNotes.rst =================================================================== --- lld/trunk/docs/ReleaseNotes.rst +++ lld/trunk/docs/ReleaseNotes.rst @@ -32,6 +32,8 @@ * /linkrepro: now takes the filename of the tar archive it writes, instead of the name of a directory that a file called "repro.tar" is created in, matching the behavior of ELF lld. +* The new `/lldignoreenv` flag makes lld-link ignore environment variables + like `%LIB%`. * ... MinGW Improvements Index: lld/trunk/test/COFF/libpath.test =================================================================== --- lld/trunk/test/COFF/libpath.test +++ lld/trunk/test/COFF/libpath.test @@ -24,3 +24,16 @@ CHECK3: Reading {{.*}}a/std64.lib CHECK3-NOT: Reading {{.*}}b/std64.lib + +# RUN: env LIB=%t/a lld-link /out:%t.exe /entry:main /verbose \ +# RUN: std64.lib /subsystem:console %p/Inputs/hello64.obj \ +# RUN: 2> %t.log +# RUN: FileCheck -check-prefix=CHECK4 %s < %t.log + +CHECK4: a{{[/\\]}}std64.lib + +# This should fail because /lldignoreenv should make lld-link +# ignore the LIB env var. +# RUN: env LIB=%t/a not lld-link /out:%t.exe /entry:main /verbose \ +# RUN: std64.lib /subsystem:console %p/Inputs/hello64.obj \ +# RUN: /lldignoreenv Index: lld/trunk/test/COFF/linkenv.test =================================================================== --- lld/trunk/test/COFF/linkenv.test +++ lld/trunk/test/COFF/linkenv.test @@ -2,3 +2,8 @@ # RUN: env _LINK_=-help lld-link | FileCheck %s CHECK: OVERVIEW: LLVM Linker + +# RUN: env LINK=-help not lld-link /lldignoreenv 2>&1 | \ +# RUN: FileCheck --check-prefix=ERR %s + +ERR: error: no input files