Index: lld/COFF/Config.h =================================================================== --- lld/COFF/Config.h +++ lld/COFF/Config.h @@ -10,6 +10,7 @@ #define LLD_COFF_CONFIG_H #include "llvm/ADT/MapVector.h" +#include "llvm/ADT/SetVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Object/COFF.h" @@ -91,7 +92,7 @@ // Global configuration. struct Configuration { - enum ManifestKind { SideBySide, Embed, No }; + enum ManifestKind { Default, SideBySide, Embed, No }; bool is64() { return machine == AMD64 || machine == ARM64; } llvm::COFF::MachineTypes machine = IMAGE_FILE_MACHINE_UNKNOWN; @@ -178,9 +179,9 @@ std::map section; // Options for manifest files. - ManifestKind manifest = No; + ManifestKind manifest = Default; int manifestID = 1; - StringRef manifestDependency; + llvm::SetVector manifestDependencies; bool manifestUAC = true; std::vector manifestInput; StringRef manifestLevel = "'asInvoker'"; Index: lld/COFF/Driver.cpp =================================================================== --- lld/COFF/Driver.cpp +++ lld/COFF/Driver.cpp @@ -383,6 +383,7 @@ for (StringRef inc : directives.includes) addUndefined(inc); + // https://docs.microsoft.com/en-us/cpp/preprocessor/comment-c-cpp?view=msvc-160 for (auto *arg : directives.args) { switch (arg->getOption().getID()) { case OPT_aligncomm: @@ -404,6 +405,9 @@ case OPT_incl: addUndefined(arg->getValue()); break; + case OPT_manifestdependency: + config->manifestDependencies.insert(arg->getValue()); + break; case OPT_merge: parseMerge(arg->getValue()); break; @@ -1705,12 +1709,9 @@ for (auto *arg : args.filtered(OPT_aligncomm)) parseAligncomm(arg->getValue()); - // Handle /manifestdependency. This enables /manifest unless /manifest:no is - // also passed. - if (auto *arg = args.getLastArg(OPT_manifestdependency)) { - config->manifestDependency = arg->getValue(); - config->manifest = Configuration::SideBySide; - } + // Handle /manifestdependency. + for (auto *arg : args.filtered(OPT_manifestdependency)) + config->manifestDependencies.insert(arg->getValue()); // Handle /manifest and /manifest: if (auto *arg = args.getLastArg(OPT_manifest, OPT_manifest_colon)) { @@ -1873,10 +1874,6 @@ if (Optional path = findLib(arg->getValue())) enqueuePath(*path, false, false); - // Windows specific -- Create a resource file containing a manifest file. - if (config->manifest == Configuration::Embed) - addBuffer(createManifestRes(), false, false); - // Read all input files given via the command line. run(); @@ -2230,8 +2227,14 @@ c->setAlignment(std::max(c->getAlignment(), alignment)); } - // Windows specific -- Create a side-by-side manifest file. - if (config->manifest == Configuration::SideBySide) + // Windows specific -- Create an embedded or side-by-side manifest. + // /manifestdependency: enables /manifest unless an explicit /manifest:no is + // also passed. + if (config->manifest == Configuration::Embed) + addBuffer(createManifestRes(), false, false); + else if (config->manifest == Configuration::SideBySide || + (config->manifest == Configuration::Default && + !config->manifestDependencies.empty())) createSideBySideManifest(); // Handle /order. We want to do this at this moment because we Index: lld/COFF/DriverUtils.cpp =================================================================== --- lld/COFF/DriverUtils.cpp +++ lld/COFF/DriverUtils.cpp @@ -385,10 +385,10 @@ << " \n" << " \n"; } - if (!config->manifestDependency.empty()) { + for (auto manifestDependency : config->manifestDependencies) { os << " \n" << " \n" - << " manifestDependency << " />\n" + << " \n" << " \n" << " \n"; } Index: lld/test/COFF/manifest.test =================================================================== --- lld/test/COFF/manifest.test +++ lld/test/COFF/manifest.test @@ -78,3 +78,92 @@ NOUACNODEP: NOUACNODEP: + +# Several /manifestdependency: flags are naively dedup'd. +# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: /manifestdependency:"foo='bar'" \ +# RUN: /manifestdependency:"foo='bar'" \ +# RUN: /manifestdependency:"baz='quux'" \ +# RUN: %t.obj +# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest + +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: +SEVERALDEPS: + +# /manifestdependency: flags can be in .drectve sections. +# RUN: yaml2obj %p/Inputs/manifestdependency-drectve.yaml -o %t.dir.obj +# RUN: rm %t.exe.manifest +# RUN: lld-link /out:%t.exe /entry:main \ +# RUN: %t.obj %t.dir.obj +# RUN: FileCheck -check-prefix=SEVERALDEPS %s < %t.exe.manifest + +# /manifestdependency: flags in .drectve sections are ignored with an +# explicit /manifest:no. +# RUN: rm %t.exe.manifest +# RUN: lld-link /out:%t.exe /entry:main /manifest:no \ +# RUN: %t.obj %t.dir.obj +# RUN: test ! -e %t.exe.manifest + +# Test that /manifestdependency: flags in .drectve sections work +# with /manifest:embed too. +# RUN: lld-link /out:%t.exe /entry:main /manifest:embed \ +# RUN: %t.obj %t.dir.obj +# RUN: test ! -e %t.exe.manifest +# RUN: llvm-readobj --coff-resources %t.exe \ +# RUN: | FileCheck --check-prefix EMBED %s + +EMBED: Data ( +EMBED: 0000: 3C3F786D 6C207665 7273696F 6E3D2231 |.. . . . . | +EMBED: 0100: 203C2F72 65717565 73746564 50726976 | . . . . . | +EMBED: 0160: 20202020 3C617373 656D626C 79496465 | . . . . <| +EMBED: 01C0: 64657065 6E64656E 74417373 656D626C |dependentAssembl| +EMBED: 01D0: 793E0A20 20202020 203C6173 73656D62 |y>. . . ..| +EMBED: )