<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">Cool!  Some thoughts below.</div><div class="gmail_quote"><br></div><div class="gmail_quote">On Wed, Oct 23, 2013 at 6:39 PM, Rui Ueyama <span dir="ltr"><<a href="mailto:ruiu@google.com" target="_blank">ruiu@google.com</a>></span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">+// Quote double quotes and backslashes in the given string, so that we can embed<br>

+// the string into a resource script file.<br>
+std::string quoteXml(StringRef str) {<br>
+  std::string ret;<br>
+  ret.reserve(str.size() * 2);<br>
+  StringRef line;<br>
+  for (;;) {<br>
+    if (str.empty())<br>
+      return std::move(ret);<br>
+    llvm::tie(line, str) = str.split("\n");<br>
+    if (!line.empty())<br>
+      continue;<br>
+    ret.append("\"");<br>
+    const char *p = line.data();<br>
+    for (int i = 0, size = line.size(); i < size; ++i) {<br>
+      switch (p[i]) {<br>
+      case '\"':<br>
+      case '\\':<br>
+        ret.append("\\");<br>
+        // fallthrough<br>
+      default:<br>
+        ret.append(1, p[i]);<br>
+      }<br>
+    }<br>
+    ret.append("\"\n");<br>
+  }<br>
+}<br></blockquote><div><br></div><div>Micro-optimization nit: use push_back over append for single character things because it won't contain a loop.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

+<br>
+// Create a resource file (.res file) containing the manifest XML. This is done<br>
+// in two steps:<br>
+//<br>
+//  1. Create a resource script file containing the XML as a literal string.<br>
+//  2. Run RC.EXE command to compile the script file to a resource file.<br>
+//<br>
+// The temporary file created in step 1 will be deleted on exit from this<br>
+// function. The file created in step 2 will have the same lifetime as the<br>
+// PECOFFLinkingContext.<br>
+bool createManifestResourceFile(PECOFFLinkingContext &ctx,<br>
+                                raw_ostream &diagnostics,<br>
+                                std::string &resFile) {<br>
+  // Create a temporary file for the resource script file.<br>
+  SmallString<128> rcFileSmallString;<br>
+  if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {<br>
+    diagnostics << "Cannot create a temporary file\n";<br>
+    return false;<br>
+  }<br>
+  StringRef rcFile(rcFileSmallString.str());<br>
+  llvm::FileRemover rcFileRemover((Twine(rcFile)));<br>
+<br>
+  // Open the temporary file for writing.<br>
+  std::string errorInfo;<br>
+  llvm::raw_fd_ostream out(rcFile.data(), errorInfo);<br>
+  if (!errorInfo.empty()) {<br>
+    diagnostics << "Failed to open " << ctx.getManifestOutputPath() << ": "<br>
+                << errorInfo << "\n";<br>
+    return false;<br>
+  }<br>
+<br>
+  // Write resource script to the RC file.<br>
+  out << "#define LANG_ENGLISH 9\n"<br>
+      << "#define SUBLANG_DEFAULT 1\n"<br>
+      << "#define APP_MANIFEST " << ctx.getManifestId() << "\n"<br>
+      << "#define RT_MANIFEST 24\n"<br>
+      << "LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT\n"<br>
+      << "APP_MANIFEST RT_MANIFEST {\n"<br>
+      << quoteXml(createManifestXml(ctx))<br></blockquote><div><br></div><div>If this is the only use, then quoteXml should probably take out as a parameter and stream to it, rather than building up a temporary std::string.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+      << "}\n";<br>
+  out.close();<br>
+<br>
+  // Create output resource file.<br>
+  SmallString<128> resFileSmallString;<br>
+  if (llvm::sys::fs::createTemporaryFile("tmp", "res", resFileSmallString)) {<br>
+    diagnostics << "Cannot create a temporary file";<br>
+    return false;<br>
+  }<br>
+  resFile = resFileSmallString.str();<br>
+<br>
+  // Register the resource file path so that the file will be deleted when the<br>
+  // context's destructor is called.<br>
+  ctx.registerTemporaryFile(resFile);<br>
+<br>
+  // Run RC.EXE /fo tmp.res tmp.rc<br>
+  std::string program = "rc.exe";<br>
+  std::string programPath = llvm::sys::FindProgramByName(program);<br>
+  if (programPath.empty()) {<br>
+    diagnostics << "Unable to find " << program << " in PATH\n";<br>
+    return false;<br>
+  }<br>
+  std::vector<const char *> args;<br>
+  args.push_back(programPath.c_str());<br>
+  args.push_back("/fo");<br>
+  args.push_back(resFile.c_str());<br>
+  args.push_back(rcFile.data());<br></blockquote><div><br></div><div>Are you sure this will be null-terminated? Seems like you do:</div><div><br></div><div>+  SmallString<128> rcFileSmallString;<br>+  if (llvm::sys::fs::createTemporaryFile("tmp", "rc", rcFileSmallString)) {<br>
</div><div>...</div><div>+  StringRef rcFile(rcFileSmallString.str());<br></div><div>...</div><div>+  args.push_back(rcFile.data());<br></div><div><br></div><div>I was able to prove that the temp file comes back null-terminated due to internal implementation details of the Windows UTF16ToUTF8 helper function, but it seems like you should null terminate here.</div>
<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">
+  args.push_back(nullptr);<br>
+<br>
+  if (llvm::sys::ExecuteAndWait(programPath.c_str(), &args[0]) != 0) {<br>
+    llvm::errs() << program << " failed\n";<br></blockquote><div><br></div><div>llvm::errs() or diagnostics?</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">

+    return false;<br>
+  }<br>
+  return true;<br>
+}<br>
+<br>
+// Create a side-by-side manifest file. The side-by-side manifest file is a<br>
+// separate XML file having ".manifest" extension. It will be created in the<br>
+// same directory as the resulting executable.<br>
+bool createSideBySideManifestFile(PECOFFLinkingContext &ctx,<br>
+                                  raw_ostream &diagnostics) {<br>
+  std::string errorInfo;<br>
+  llvm::raw_fd_ostream out(ctx.getManifestOutputPath().data(), errorInfo);<br>
+  if (!errorInfo.empty()) {<br>
+    diagnostics << "Failed to open " << ctx.getManifestOutputPath() << ": "<br>
+                << errorInfo << "\n";<br>
+    return false;<br>
+  }<br>
+  out << createManifestXml(ctx);<br>
   return true;<br>
 }<br>
<br>
+// Create the a side-by-side manifest file, or create a resource file for the<br>
+// manifest file and add it to the input graph.<br>
+//<br>
+// The manifest file will convey some information to the linker, such as whether<br>
+// the binary needs to run as Administrator or not. Instead of being placed in<br>
+// the PE/COFF header, it's in XML format for some reason -- I guess it's<br>
+// probably because it's invented in the early dot-com era.<br>
+bool createManifest(PECOFFLinkingContext &ctx, raw_ostream &diagnostics) {<br>
+  if (ctx.getEmbedManifest()) {<br>
+    std::string resourceFilePath;<br>
+    if (!createManifestResourceFile(ctx, diagnostics, resourceFilePath))<br>
+      return false;<br>
+    std::unique_ptr<InputElement> inputElement(<br>
+        new PECOFFFileNode(ctx, resourceFilePath));<br>
+    ctx.inputGraph().addInputElement(std::move(inputElement));<br>
+    return true;<br>
+  }<br>
+  return createSideBySideManifestFile(ctx, diagnostics);<br>
+}<br>
+<br>
 // Handle /failifmismatch option.<br>
 bool handleFailIfMismatchOption(StringRef option,<br>
                                 std::map<StringRef, StringRef> &mustMatch,<br>
@@ -265,6 +402,10 @@ bool handleFailIfMismatchOption(StringRe<br>
   return false;<br>
 }<br>
<br>
+//<br>
+// Environment variable<br>
+//<br>
+<br>
 // Process "LINK" environment variable. If defined, the value of the variable<br>
 // should be processed as command line arguments.<br>
 std::vector<const char *> processLinkEnv(PECOFFLinkingContext &context,<br>
@@ -344,6 +485,10 @@ parseArgs(int argc, const char *argv[],<br>
<br>
 } // namespace<br>
<br>
+//<br>
+// Main driver<br>
+//<br>
+<br>
 ErrorOr<StringRef> PECOFFFileNode::getPath(const LinkingContext &) const {<br>
   if (_path.endswith(".lib"))<br>
     return _ctx.searchLibraryFile(_path);<br>
@@ -365,6 +510,12 @@ bool WinLinkDriver::linkPECOFF(int argc,<br>
   processLibEnv(context);<br>
   if (!parse(newargv.size() - 1, &newargv[0], context, diagnostics))<br>
     return false;<br>
+<br>
+  // Create the file if needed.<br>
+  if (context.getCreateManifest())<br>
+    if (!createManifest(context, diagnostics))<br>
+      return false;<br>
+<br>
   return link(context, diagnostics);<br>
 }<br>
<br>
@@ -714,11 +865,6 @@ WinLinkDriver::parse(int argc, const cha<br>
   for (auto &e : inputElements)<br>
     ctx.inputGraph().addInputElement(std::move(e));<br>
<br>
-  // Create the side-by-side manifest file if needed.<br>
-  if (!isReadingDirectiveSection && ctx.getCreateManifest())<br>
-    if (!createManifestFile(ctx, diagnostics))<br>
-      return false;<br>
-<br>
   // Validate the combination of options used.<br>
   return ctx.validate(diagnostics);<br>
 }<br>
<br>
<br>
_______________________________________________<br>
llvm-commits mailing list<br>
<a href="mailto:llvm-commits@cs.uiuc.edu">llvm-commits@cs.uiuc.edu</a><br>
<a href="http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits" target="_blank">http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits</a><br>
</blockquote></div><br></div></div>