Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(246)

Unified Diff: tools/win/split_link/split_link.cc

Issue 15067010: split_link tool, config, and scripts for windows build (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « tools/win/split_link/install_split_link.py ('k') | tools/win/split_link/split_link.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: tools/win/split_link/split_link.cc
diff --git a/tools/win/split_link/split_link.cc b/tools/win/split_link/split_link.cc
new file mode 100644
index 0000000000000000000000000000000000000000..639f1c55eac771b38db5f146c3e910206c390c9a
--- /dev/null
+++ b/tools/win/split_link/split_link.cc
@@ -0,0 +1,257 @@
+// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <windows.h>
+#include <shlwapi.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <algorithm>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#ifndef SPLIT_LINK_SCRIPT_PATH
+#error SPLIT_LINK_SCRIPT_PATH must be defined as the path to "split_link.py".
+#endif
+
+#ifndef PYTHON_PATH
+#error PYTHON_PATH must be defined to be the path to the python binary.
+#endif
+
+#define WIDEN2(x) L ## x
+#define WIDEN(x) WIDEN2(x)
+#define WPYTHON_PATH WIDEN(PYTHON_PATH)
+#define WSPLIT_LINK_SCRIPT_PATH WIDEN(SPLIT_LINK_SCRIPT_PATH)
+
+using namespace std;
+
+// Don't use stderr for errors because VS has large buffers on them, leading
+// to confusing error output.
+static void Fatal(const wchar_t* msg) {
+ wprintf(L"split_link fatal error: %s\n", msg);
+ exit(1);
+}
+
+static wstring ErrorMessageToString(DWORD err) {
+ wchar_t* msg_buf = NULL;
+ DWORD rc = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ reinterpret_cast<LPTSTR>(&msg_buf),
+ 0,
+ NULL);
+ if (!rc)
+ return L"unknown error";
+ wstring ret(msg_buf);
+ LocalFree(msg_buf);
+ return ret;
+}
+
+static void ArgvQuote(const std::wstring& argument,
+ std::wstring* command_line) {
+ // Don't quote unless we actually need to.
+ if (!argument.empty() &&
+ argument.find_first_of(L" \t\n\v\"") == argument.npos) {
+ command_line->append(argument);
+ } else {
+ command_line->push_back(L'"');
+ for (std::wstring::const_iterator it = argument.begin();; ++it) {
+ int num_backslashes = 0;
+ while (it != argument.end() && *it == L'\\') {
+ ++it;
+ ++num_backslashes;
+ }
+ if (it == argument.end()) {
+ // Escape all backslashes, but let the terminating double quotation
+ // mark we add below be interpreted as a metacharacter.
+ command_line->append(num_backslashes * 2, L'\\');
+ break;
+ } else if (*it == L'"') {
+ // Escape all backslashes and the following double quotation mark.
+ command_line->append(num_backslashes * 2 + 1, L'\\');
+ command_line->push_back(*it);
+ } else {
+ // Backslashes aren't special here.
+ command_line->append(num_backslashes, L'\\');
+ command_line->push_back(*it);
+ }
+ }
+ command_line->push_back(L'"');
+ }
+}
+
+// Does the opposite of CommandLineToArgvW. Suitable for CreateProcess, but
+// not for cmd.exe. |args| should include the program name as argv[0].
+// See http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx
+static wstring BuildCommandLine(const vector<wstring>& args) {
+ std::wstring result;
+ for (size_t i = 0; i < args.size(); ++i) {
+ ArgvQuote(args[i], &result);
+ if (i < args.size() - 1) {
+ result += L" ";
+ }
+ }
+ return result;
+}
+
+static void RunLinker(const vector<wstring>& prefix, const wchar_t* msg) {
+ if (msg) {
+ wprintf(L"split_link failed (%s), trying to fallback to standard link.\n",
+ msg);
+ wprintf(L"Original command line: %s\n", GetCommandLine());
+ fflush(stdout);
+ }
+
+ STARTUPINFO startup_info = { sizeof(STARTUPINFO) };
+ PROCESS_INFORMATION process_info;
+ DWORD exit_code;
+
+ GetStartupInfo(&startup_info);
+
+ if (getenv("SPLIT_LINK_DEBUG")) {
+ wprintf(L" original command line '%s'\n", GetCommandLine());
+ fflush(stdout);
+ }
+
+ int num_args;
+ LPWSTR* args = CommandLineToArgvW(GetCommandLine(), &num_args);
+ if (!args)
+ Fatal(L"Couldn't parse command line.");
+ vector<wstring> argv;
+ argv.insert(argv.end(), prefix.begin(), prefix.end());
+ for (int i = 1; i < num_args; ++i) // Skip old argv[0].
+ argv.push_back(args[i]);
+ LocalFree(args);
+
+ wstring cmd = BuildCommandLine(argv);
+
+ if (getenv("SPLIT_LINK_DEBUG")) {
+ wprintf(L" running '%s'\n", cmd.c_str());
+ fflush(stdout);
+ }
+ if (!CreateProcess(NULL,
+ reinterpret_cast<LPWSTR>(const_cast<wchar_t *>(
+ cmd.c_str())),
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &startup_info, &process_info)) {
+ wstring error = ErrorMessageToString(GetLastError());
+ Fatal(error.c_str());
+ }
+ CloseHandle(process_info.hThread);
+ WaitForSingleObject(process_info.hProcess, INFINITE);
+ GetExitCodeProcess(process_info.hProcess, &exit_code);
+ CloseHandle(process_info.hProcess);
+ exit(exit_code);
+}
+
+static void Fallback(const wchar_t* msg) {
+ wchar_t original_link[1024];
+ DWORD type;
+ DWORD size = sizeof(original_link);
+ if (SHGetValue(HKEY_CURRENT_USER,
+ L"Software\\Chromium\\split_link_installed",
+ NULL,
+ &type,
+ original_link,
+ &size) != ERROR_SUCCESS || type != REG_SZ) {
+ Fatal(L"Couldn't retrieve linker location from "
+ L"HKCU\\Software\\Chromium\\split_link_installed.");
+ }
+ if (getenv("SPLIT_LINK_DEBUG")) {
+ wprintf(L" got original linker '%s'\n", original_link);
+ fflush(stdout);
+ }
+ vector<wstring> link_binary;
+ link_binary.push_back(original_link);
+ RunLinker(link_binary, msg);
+}
+
+static void Fallback() {
+ Fallback(NULL);
+}
+
+static unsigned char* SlurpFile(const wchar_t* path, size_t* length) {
+ HANDLE file = CreateFile(
+ path, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, NULL);
+ if (file == INVALID_HANDLE_VALUE)
+ Fallback(L"couldn't open file");
+ LARGE_INTEGER file_size;
+ if (!GetFileSizeEx(file, &file_size))
+ Fallback(L"couldn't get file size");
+ *length = static_cast<size_t>(file_size.QuadPart);
+ unsigned char* buffer = static_cast<unsigned char*>(malloc(*length));
+ if (!ReadFile(file, buffer, *length, NULL, NULL))
+ Fallback(L"couldn't read file");
+ return buffer;
+}
+
+static bool SplitLinkRequested(const wchar_t* rsp_path) {
+ size_t length;
+ unsigned char* data = SlurpFile(rsp_path, &length);
+ bool flag_found = false;
+ if (data[0] == 0xff && data[1] == 0xfe) {
+ // UTF-16LE
+ wstring wide(reinterpret_cast<wchar_t*>(&data[2]),
+ length / sizeof(wchar_t) - 1);
+ flag_found = wide.find(L"/splitlink") != wide.npos;
+ } else {
+ string narrow(reinterpret_cast<char*>(data), length);
+ flag_found = narrow.find("/splitlink") != narrow.npos;
+ }
+ free(data);
+ return flag_found;
+}
+
+// If /splitlink is on the command line, delegate to split_link.py, otherwise
+// fallback to standard linker.
+int wmain(int argc, wchar_t** argv) {
+ int rsp_file_index = -1;
+
+ if (argc < 2)
+ Fallback();
+
+ for (int i = 1; i < argc; ++i) {
+ if (argv[i][0] == L'@') {
+ rsp_file_index = i;
+ break;
+ }
+ }
+
+ if (rsp_file_index == -1)
+ Fallback(L"couldn't find a response file in argv");
+
+ if (getenv("SPLIT_LINK_DEBUG")) {
+ wstring backup_copy(&argv[rsp_file_index][1]);
+ backup_copy += L".copy";
+ wchar_t buf[1024];
+ swprintf(buf,
+ sizeof(buf),
+ L"copy %s %s",
+ &argv[rsp_file_index][1],
+ backup_copy.c_str());
+ if (_wsystem(buf) == 0)
+ wprintf(L"Saved original rsp as %s\n", backup_copy.c_str());
+ else
+ wprintf(L"'%s' failed.", buf);
+ }
+
+ if (SplitLinkRequested(&argv[rsp_file_index][1])) {
+ vector<wstring> link_binary;
+ link_binary.push_back(WPYTHON_PATH);
+ link_binary.push_back(WSPLIT_LINK_SCRIPT_PATH);
+ RunLinker(link_binary, NULL);
+ }
+
+ // Otherwise, run regular linker silently.
+ Fallback();
+}
« no previous file with comments | « tools/win/split_link/install_split_link.py ('k') | tools/win/split_link/split_link.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698