bool TailMerge;
bool Relocatable = true;
bool ForceMultiple = false;
+ bool ForceMultipleRes = false;
bool ForceUnresolved = false;
bool Debug = false;
bool DebugDwarf = false;
if (Args.hasArg(OPT_force, OPT_force_multiple))
Config->ForceMultiple = true;
+ // Handle /force or /force:multipleres
+ if (Args.hasArg(OPT_force, OPT_force_multipleres))
+ Config->ForceMultipleRes = true;
+
// Handle /debug
DebugKind Debug = parseDebugKind(Args);
if (Debug == DebugKind::Full || Debug == DebugKind::Dwarf ||
object::WindowsResource *RF = dyn_cast<object::WindowsResource>(Bin.get());
if (!RF)
fatal("cannot compile non-resource file as resource");
- if (auto EC = Parser.parse(RF))
+
+ std::vector<std::string> Duplicates;
+ if (auto EC = Parser.parse(RF, Duplicates))
fatal(toString(std::move(EC)));
+
+ for (const auto &DupeDiag : Duplicates)
+ if (Config->ForceMultipleRes)
+ warn(DupeDiag);
+ else
+ error(DupeDiag);
}
Expected<std::unique_ptr<MemoryBuffer>> E =
HelpText<"Allow undefined symbols when creating executables">;
def force_multiple : F<"force:multiple">,
HelpText<"Allow multiply defined symbols when creating executables">;
+def force_multipleres : F<"force:multipleres">,
+ HelpText<"Allow multiply defined resources when creating executables">;
defm WX : B<"WX", "Treat warnings as errors", "Don't treat warnings as errors">;
defm allowbind : B<"allowbind", "Enable DLL binding (default)",
* lld-link now correctly reports duplicate symbol errors when several res
input files define resources with the same type, name, and language.
+ This can be demoted to a warning using ``/force:multipleres``.
* Having more than two ``/natvis:`` now works correctly; it used to not
work for larger binaries before.
--- /dev/null
+// Check that lld-link rejects duplicate resources, unless
+// /force or /force:multipleres is passed.
+// The input was generated with the following command, using the original Windows
+// rc.exe:
+// > rc /fo id.res /nologo id.rc
+// > rc /fo name.res /nologo name.rc
+
+RUN: rm -rf %t.dir
+RUN: mkdir %t.dir
+RUN: cp %S/Inputs/id.res %t.dir/id1.res
+RUN: cp %S/Inputs/id.res %t.dir/id2.res
+
+RUN: not lld-link /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \
+RUN: FileCheck -check-prefix=ERR %s
+ERR: error: duplicate resource: type STRINGTABLE (ID 6)/name ID 3/language 1033, in {{.*}}id1.res and in {{.*}}id2.res
+
+RUN: lld-link /force /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \
+RUN: FileCheck -check-prefix=WARN %s
+RUN: lld-link /force:multipleres /machine:x64 /nodefaultlib /noentry /dll %t.dir/id1.res %t.dir/id2.res 2>&1 | \
+RUN: FileCheck -check-prefix=WARN %s
+WARN: warning: duplicate resource: type STRINGTABLE (ID 6)/name ID 3/language 1033, in {{.*}}id1.res and in {{.*}}id2.res
public:
class TreeNode;
WindowsResourceParser();
- Error parse(WindowsResource *WR);
+ Error parse(WindowsResource *WR, std::vector<std::string> &Duplicates);
void printTree(raw_ostream &OS) const;
const TreeNode &getTree() const { return Root; }
const ArrayRef<std::vector<uint8_t>> getData() const { return Data; }
return convertUTF16ToUTF8String(makeArrayRef(EndianCorrectedSrc), Out);
}
-static Error makeDuplicateResourceError(const ResourceEntryRef &Entry,
- StringRef File1, StringRef File2) {
+static std::string makeDuplicateResourceError(
+ const ResourceEntryRef &Entry, StringRef File1, StringRef File2) {
std::string Ret;
raw_string_ostream OS(Ret);
OS << "/language " << Entry.getLanguage() << ", in " << File1 << " and in "
<< File2;
- return make_error<GenericBinaryError>(OS.str(), object_error::parse_failed);
+ return OS.str();
}
-Error WindowsResourceParser::parse(WindowsResource *WR) {
+Error WindowsResourceParser::parse(WindowsResource *WR,
+ std::vector<std::string> &Duplicates) {
auto EntryOrErr = WR->getHeadEntry();
if (!EntryOrErr) {
auto E = EntryOrErr.takeError();
bool IsNewNode = Root.addEntry(Entry, InputFilenames.size(),
IsNewTypeString, IsNewNameString, Node);
InputFilenames.push_back(WR->getFileName());
- if (!IsNewNode)
- return makeDuplicateResourceError(Entry, InputFilenames[Node->Origin],
- WR->getFileName());
+ if (!IsNewNode) {
+ Duplicates.push_back(makeDuplicateResourceError(
+ Entry, InputFilenames[Node->Origin], WR->getFileName()));
+ }
if (IsNewTypeString)
StringTable.push_back(Entry.getTypeString());
outs() << "Number of resources: " << EntryNumber << "\n";
}
- error(Parser.parse(RF));
+ std::vector<std::string> Duplicates;
+ error(Parser.parse(RF, Duplicates));
+ for (const auto& DupeDiag : Duplicates)
+ reportError(DupeDiag);
}
if (Verbose) {