mirror of
https://github.com/cemu-project/vcpkg.git
synced 2025-02-23 11:07:10 +01:00
[vcpkg] Use CreateProcess on Windows. Improve EnvVars manipulation and handling. (#9897)
* [vcpkg] Rewrite process spawning on windows to always use CreateProcess, enabling better environment handling * [vcpkg] Use environment cache to avoid calling vcvars multiple times * [vcpkg] Increase buffer size while computing hashes * [vcpkg] Remove unneeded cmd.exe wrapper process on all CreateProcess calls * [vcpkg] Fix .vcxproj{,.filters} * [vcpkg] Upgrade Ctrl-C state machine to handle multiple background processes. * [vcpkg] Fix regression while launching metrics: 'start' can't be passed directly to CreateProcessW * [vcpkg] Fix typo on non-Windows * [vcpkg] Fix various uses of >NUL across the code * [vcpkg] Fix various uses of >NUL across the code
This commit is contained in:
parent
b20c6d3b89
commit
f7fb56decd
@ -139,7 +139,7 @@ if (BUILD_TESTING)
|
||||
endif()
|
||||
|
||||
if(MSVC)
|
||||
get_target_property(_srcs vcpkg SOURCES)
|
||||
get_target_property(_srcs vcpkglib SOURCES)
|
||||
|
||||
if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*")
|
||||
set_property(SOURCE src/pch.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/pch.pch")
|
||||
@ -147,8 +147,8 @@ if(MSVC)
|
||||
endif()
|
||||
|
||||
set_source_files_properties(src/pch.cpp PROPERTIES COMPILE_FLAGS "/Ycpch.h")
|
||||
target_sources(vcpkg PRIVATE src/pch.cpp)
|
||||
target_compile_options(vcpkg PRIVATE /Yupch.h /FIpch.h /Zm200)
|
||||
target_sources(vcpkglib PRIVATE src/pch.cpp)
|
||||
target_compile_options(vcpkglib PRIVATE /Yupch.h /FIpch.h /Zm200)
|
||||
endif()
|
||||
|
||||
if (MINGW)
|
||||
|
@ -8,6 +8,9 @@ namespace vcpkg::Checks
|
||||
{
|
||||
void register_global_shutdown_handler(void (*func)());
|
||||
|
||||
// Note: for internal use
|
||||
[[noreturn]] void final_cleanup_and_exit(const int exit_code);
|
||||
|
||||
// Indicate that an internal error has occurred and exit the tool. This should be used when invariants have been
|
||||
// broken.
|
||||
[[noreturn]] void unreachable(const LineInfo& line_info);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <vcpkg/base/files.h>
|
||||
#include <vcpkg/base/zstringview.h>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@ -30,17 +31,34 @@ namespace vcpkg::System
|
||||
std::string output;
|
||||
};
|
||||
|
||||
int cmd_execute_clean(const ZStringView cmd_line,
|
||||
const std::unordered_map<std::string, std::string>& extra_env = {},
|
||||
const std::string& prepend_to_path = {});
|
||||
struct Environment
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
std::wstring m_env_data;
|
||||
#endif
|
||||
};
|
||||
|
||||
int cmd_execute(const ZStringView cmd_line);
|
||||
const Environment& get_clean_environment();
|
||||
Environment get_modified_clean_environment(const std::unordered_map<std::string, std::string>& extra_env,
|
||||
const std::string& prepend_to_path = {});
|
||||
|
||||
int cmd_execute(const ZStringView cmd_line, const Environment& env = {});
|
||||
int cmd_execute_clean(const ZStringView cmd_line);
|
||||
|
||||
#if defined(_WIN32)
|
||||
Environment cmd_execute_modify_env(const ZStringView cmd_line, const Environment& env = {});
|
||||
|
||||
void cmd_execute_no_wait(const StringView cmd_line);
|
||||
#endif
|
||||
|
||||
ExitCodeAndOutput cmd_execute_and_capture_output(const ZStringView cmd_line);
|
||||
ExitCodeAndOutput cmd_execute_and_capture_output(const ZStringView cmd_line, const Environment& env = {});
|
||||
|
||||
int cmd_execute_and_stream_lines(const ZStringView cmd_line,
|
||||
std::function<void(const std::string&)> per_line_cb,
|
||||
const Environment& env = {});
|
||||
|
||||
int cmd_execute_and_stream_data(const ZStringView cmd_line,
|
||||
std::function<void(StringView)> data_cb,
|
||||
const Environment& env = {});
|
||||
void register_console_ctrl_handler();
|
||||
}
|
||||
|
@ -15,11 +15,17 @@ namespace vcpkg
|
||||
g_shutdown_handler = func;
|
||||
}
|
||||
|
||||
[[noreturn]] static void cleanup_and_exit(const int exit_code)
|
||||
void Checks::final_cleanup_and_exit(const int exit_code)
|
||||
{
|
||||
static std::atomic<bool> have_entered{false};
|
||||
if (have_entered) std::terminate();
|
||||
have_entered = true;
|
||||
if (have_entered.exchange(true))
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
::TerminateProcess(::GetCurrentProcess(), exit_code);
|
||||
#else
|
||||
std::terminate();
|
||||
#endif
|
||||
}
|
||||
|
||||
if (g_shutdown_handler) g_shutdown_handler();
|
||||
|
||||
@ -38,14 +44,14 @@ namespace vcpkg
|
||||
#ifndef NDEBUG
|
||||
std::abort();
|
||||
#else
|
||||
cleanup_and_exit(EXIT_FAILURE);
|
||||
final_cleanup_and_exit(EXIT_FAILURE);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Checks::exit_with_code(const LineInfo& line_info, const int exit_code)
|
||||
{
|
||||
Debug::print(System::Color::error, line_info, '\n');
|
||||
cleanup_and_exit(exit_code);
|
||||
final_cleanup_and_exit(exit_code);
|
||||
}
|
||||
|
||||
void Checks::exit_with_message(const LineInfo& line_info, StringView error_message)
|
||||
|
@ -746,7 +746,7 @@ namespace vcpkg::Hash
|
||||
}
|
||||
|
||||
return do_hash(algo, [&file, &ec](Hasher& hasher) {
|
||||
constexpr std::size_t buffer_size = 4096;
|
||||
constexpr std::size_t buffer_size = 1024 * 32;
|
||||
auto buffer = std::make_unique<char[]>(buffer_size);
|
||||
for (;;)
|
||||
{
|
||||
|
@ -4,121 +4,14 @@
|
||||
#include <vcpkg/base/chrono.h>
|
||||
#include <vcpkg/base/system.debug.h>
|
||||
#include <vcpkg/base/system.h>
|
||||
#include <vcpkg/base/system.process.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#pragma comment(lib, "Advapi32")
|
||||
#endif
|
||||
|
||||
using namespace vcpkg::System;
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
namespace
|
||||
{
|
||||
struct CtrlCStateMachine
|
||||
{
|
||||
CtrlCStateMachine() : m_state(CtrlCState::normal) {}
|
||||
|
||||
void transition_to_spawn_process() noexcept
|
||||
{
|
||||
auto expected = CtrlCState::normal;
|
||||
auto transitioned = m_state.compare_exchange_strong(expected, CtrlCState::blocked_on_child);
|
||||
if (!transitioned)
|
||||
{
|
||||
// Ctrl-C was hit and is asynchronously executing on another thread
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
void transition_from_spawn_process() noexcept
|
||||
{
|
||||
auto expected = CtrlCState::blocked_on_child;
|
||||
auto transitioned = m_state.compare_exchange_strong(expected, CtrlCState::normal);
|
||||
if (!transitioned)
|
||||
{
|
||||
// Ctrl-C was hit while blocked on the child process, so exit immediately
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
void transition_handle_ctrl_c() noexcept
|
||||
{
|
||||
auto prev_state = m_state.exchange(CtrlCState::exit_requested);
|
||||
|
||||
if (prev_state == CtrlCState::normal)
|
||||
{
|
||||
// Not currently blocked on a child process and Ctrl-C has not been hit.
|
||||
Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
}
|
||||
else if (prev_state == CtrlCState::exit_requested)
|
||||
{
|
||||
// Ctrl-C was hit previously?
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are currently blocked on a child process. Upon return, transition_from_spawn_process() will be
|
||||
// called and exit.
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
enum class CtrlCState
|
||||
{
|
||||
normal,
|
||||
blocked_on_child,
|
||||
exit_requested,
|
||||
};
|
||||
|
||||
std::atomic<CtrlCState> m_state;
|
||||
};
|
||||
|
||||
static CtrlCStateMachine g_ctrl_c_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::path System::get_exe_path_of_current_process()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
wchar_t buf[_MAX_PATH];
|
||||
const int bytes = GetModuleFileNameW(nullptr, buf, _MAX_PATH);
|
||||
if (bytes == 0) std::abort();
|
||||
return fs::path(buf, buf + bytes);
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr const uint32_t buff_size = 1024 * 32;
|
||||
uint32_t size = buff_size;
|
||||
char buf[buff_size] = {};
|
||||
int result = _NSGetExecutablePath(buf, &size);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
|
||||
std::unique_ptr<char> canonicalPath(realpath(buf, NULL));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
|
||||
return fs::path(std::string(canonicalPath.get()));
|
||||
#elif defined(__FreeBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
char exePath[2048];
|
||||
size_t len = sizeof(exePath);
|
||||
auto rcode = sysctl(mib, 4, exePath, &len, NULL, 0);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, rcode == 0, "Could not determine current executable path.");
|
||||
Checks::check_exit(VCPKG_LINE_INFO, len > 0, "Could not determine current executable path.");
|
||||
return fs::path(exePath, exePath + len - 1);
|
||||
#else /* LINUX */
|
||||
std::array<char, 1024 * 4> buf;
|
||||
auto written = readlink("/proc/self/exe", buf.data(), buf.size());
|
||||
Checks::check_exit(VCPKG_LINE_INFO, written != -1, "Could not determine current executable path.");
|
||||
return fs::path(buf.data(), buf.data() + written);
|
||||
#endif
|
||||
}
|
||||
|
||||
Optional<CPUArchitecture> System::to_cpu_architecture(StringView arch)
|
||||
{
|
||||
if (Strings::case_insensitive_ascii_equals(arch, "x86")) return CPUArchitecture::X86;
|
||||
@ -179,338 +72,6 @@ namespace vcpkg
|
||||
return supported_architectures;
|
||||
}
|
||||
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const char* varvalue)
|
||||
: s(Strings::format(R"("-D%s=%s")", varname, varvalue))
|
||||
{
|
||||
}
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const std::string& varvalue)
|
||||
: CMakeVariable(varname, varvalue.c_str())
|
||||
{
|
||||
}
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const fs::path& path)
|
||||
: CMakeVariable(varname, path.generic_u8string())
|
||||
{
|
||||
}
|
||||
|
||||
std::string System::make_cmake_cmd(const fs::path& cmake_exe,
|
||||
const fs::path& cmake_script,
|
||||
const std::vector<CMakeVariable>& pass_variables)
|
||||
{
|
||||
const std::string cmd_cmake_pass_variables = Strings::join(" ", pass_variables, [](auto&& v) { return v.s; });
|
||||
return Strings::format(
|
||||
R"("%s" %s -P "%s")", cmake_exe.u8string(), cmd_cmake_pass_variables, cmake_script.generic_u8string());
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
static std::wstring compute_clean_environment(const std::unordered_map<std::string, std::string>& extra_env,
|
||||
const std::string& prepend_to_path)
|
||||
{
|
||||
static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO);
|
||||
static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)";
|
||||
std::string new_path = Strings::format(R"(Path=%s%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)",
|
||||
prepend_to_path,
|
||||
SYSTEM_32,
|
||||
SYSTEM_ROOT,
|
||||
SYSTEM_32,
|
||||
SYSTEM_32);
|
||||
|
||||
std::vector<std::wstring> env_wstrings = {
|
||||
L"ALLUSERSPROFILE",
|
||||
L"APPDATA",
|
||||
L"CommonProgramFiles",
|
||||
L"CommonProgramFiles(x86)",
|
||||
L"CommonProgramW6432",
|
||||
L"COMPUTERNAME",
|
||||
L"ComSpec",
|
||||
L"HOMEDRIVE",
|
||||
L"HOMEPATH",
|
||||
L"LOCALAPPDATA",
|
||||
L"LOGONSERVER",
|
||||
L"NUMBER_OF_PROCESSORS",
|
||||
L"OS",
|
||||
L"PATHEXT",
|
||||
L"PROCESSOR_ARCHITECTURE",
|
||||
L"PROCESSOR_ARCHITEW6432",
|
||||
L"PROCESSOR_IDENTIFIER",
|
||||
L"PROCESSOR_LEVEL",
|
||||
L"PROCESSOR_REVISION",
|
||||
L"ProgramData",
|
||||
L"ProgramFiles",
|
||||
L"ProgramFiles(x86)",
|
||||
L"ProgramW6432",
|
||||
L"PROMPT",
|
||||
L"PSModulePath",
|
||||
L"PUBLIC",
|
||||
L"SystemDrive",
|
||||
L"SystemRoot",
|
||||
L"TEMP",
|
||||
L"TMP",
|
||||
L"USERDNSDOMAIN",
|
||||
L"USERDOMAIN",
|
||||
L"USERDOMAIN_ROAMINGPROFILE",
|
||||
L"USERNAME",
|
||||
L"USERPROFILE",
|
||||
L"windir",
|
||||
// Enables proxy information to be passed to Curl, the underlying download library in cmake.exe
|
||||
L"http_proxy",
|
||||
L"https_proxy",
|
||||
// Enables find_package(CUDA) and enable_language(CUDA) in CMake
|
||||
L"CUDA_PATH",
|
||||
L"CUDA_PATH_V9_0",
|
||||
L"CUDA_PATH_V9_1",
|
||||
L"CUDA_PATH_V10_0",
|
||||
L"CUDA_PATH_V10_1",
|
||||
L"CUDA_TOOLKIT_ROOT_DIR",
|
||||
// Environmental variable generated automatically by CUDA after installation
|
||||
L"NVCUDASAMPLES_ROOT",
|
||||
// Enables find_package(Vulkan) in CMake. Environmental variable generated by Vulkan SDK installer
|
||||
L"VULKAN_SDK",
|
||||
// Enable targeted Android NDK
|
||||
L"ANDROID_NDK_HOME",
|
||||
};
|
||||
|
||||
const Optional<std::string> keep_vars = System::get_environment_variable("VCPKG_KEEP_ENV_VARS");
|
||||
const auto k = keep_vars.get();
|
||||
|
||||
if (k && !k->empty())
|
||||
{
|
||||
auto vars = Strings::split(*k, ";");
|
||||
|
||||
for (auto&& var : vars)
|
||||
{
|
||||
env_wstrings.push_back(Strings::to_utf16(var));
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring env_cstr;
|
||||
|
||||
for (auto&& env_wstring : env_wstrings)
|
||||
{
|
||||
const Optional<std::string> value = System::get_environment_variable(Strings::to_utf8(env_wstring.c_str()));
|
||||
const auto v = value.get();
|
||||
if (!v || v->empty()) continue;
|
||||
|
||||
env_cstr.append(env_wstring);
|
||||
env_cstr.push_back(L'=');
|
||||
env_cstr.append(Strings::to_utf16(*v));
|
||||
env_cstr.push_back(L'\0');
|
||||
}
|
||||
|
||||
if (extra_env.find("PATH") != extra_env.end())
|
||||
new_path += Strings::format(";%s", extra_env.find("PATH")->second);
|
||||
env_cstr.append(Strings::to_utf16(new_path));
|
||||
env_cstr.push_back(L'\0');
|
||||
env_cstr.append(L"VSLANG=1033");
|
||||
env_cstr.push_back(L'\0');
|
||||
|
||||
for (const auto& item : extra_env)
|
||||
{
|
||||
if (item.first == "PATH") continue;
|
||||
env_cstr.append(Strings::to_utf16(item.first));
|
||||
env_cstr.push_back(L'=');
|
||||
env_cstr.append(Strings::to_utf16(item.second));
|
||||
env_cstr.push_back(L'\0');
|
||||
}
|
||||
|
||||
return env_cstr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
/// <param name="maybe_environment">If non-null, an environment block to use for the new process. If null, the new
|
||||
/// process will inherit the current environment.</param>
|
||||
static void windows_create_process(const StringView cmd_line,
|
||||
const wchar_t* environment_block,
|
||||
PROCESS_INFORMATION& process_info,
|
||||
DWORD dwCreationFlags) noexcept
|
||||
{
|
||||
STARTUPINFOW startup_info;
|
||||
memset(&startup_info, 0, sizeof(STARTUPINFOW));
|
||||
startup_info.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
// Flush stdout before launching external process
|
||||
fflush(nullptr);
|
||||
|
||||
// Wrapping the command in a single set of quotes causes cmd.exe to correctly execute
|
||||
const std::string actual_cmd_line = Strings::format(R"###(cmd.exe /c "%s")###", cmd_line);
|
||||
Debug::print("CreateProcessW(", actual_cmd_line, ")\n");
|
||||
bool succeeded = TRUE == CreateProcessW(nullptr,
|
||||
Strings::to_utf16(actual_cmd_line).data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
FALSE,
|
||||
IDLE_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | dwCreationFlags,
|
||||
(void*)environment_block,
|
||||
nullptr,
|
||||
&startup_info,
|
||||
&process_info);
|
||||
|
||||
Checks::check_exit(VCPKG_LINE_INFO, succeeded, "Process creation failed with error code: %lu", GetLastError());
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
void System::cmd_execute_no_wait(StringView cmd_line)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
windows_create_process(cmd_line, nullptr, process_info, DETACHED_PROCESS);
|
||||
|
||||
CloseHandle(process_info.hThread);
|
||||
CloseHandle(process_info.hProcess);
|
||||
|
||||
Debug::print("CreateProcessW() took ", static_cast<int>(timer.microseconds()), " us\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
int System::cmd_execute_clean(const ZStringView cmd_line,
|
||||
const std::unordered_map<std::string, std::string>& extra_env,
|
||||
const std::string& prepend_to_path)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
#if defined(_WIN32)
|
||||
|
||||
PROCESS_INFORMATION process_info;
|
||||
memset(&process_info, 0, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
g_ctrl_c_state.transition_to_spawn_process();
|
||||
auto clean_env = compute_clean_environment(extra_env, prepend_to_path);
|
||||
windows_create_process(cmd_line, clean_env.data(), process_info, 0);
|
||||
|
||||
CloseHandle(process_info.hThread);
|
||||
|
||||
const DWORD result = WaitForSingleObject(process_info.hProcess, INFINITE);
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != WAIT_FAILED, "WaitForSingleObject failed");
|
||||
|
||||
DWORD exit_code = 0;
|
||||
GetExitCodeProcess(process_info.hProcess, &exit_code);
|
||||
|
||||
CloseHandle(process_info.hProcess);
|
||||
|
||||
Debug::print(
|
||||
"CreateProcessW() returned ", exit_code, " after ", static_cast<int>(timer.microseconds()), " us\n");
|
||||
return static_cast<int>(exit_code);
|
||||
#else
|
||||
// TODO: this should create a clean environment on Linux/macOS
|
||||
Util::unused(extra_env, prepend_to_path);
|
||||
Debug::print("system(", cmd_line, ")\n");
|
||||
fflush(nullptr);
|
||||
int rc = system(cmd_line.c_str());
|
||||
Debug::print("system() returned ", rc, " after ", static_cast<int>(timer.microseconds()), " us\n");
|
||||
return rc;
|
||||
#endif
|
||||
}
|
||||
|
||||
int System::cmd_execute(const ZStringView cmd_line)
|
||||
{
|
||||
// Flush stdout before launching external process
|
||||
fflush(nullptr);
|
||||
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
#if defined(_WIN32)
|
||||
// We are wrap the command line in quotes to cause cmd.exe to correctly process it
|
||||
auto actual_cmd_line = Strings::concat('"', cmd_line, '"');
|
||||
Debug::print("_wsystem(", actual_cmd_line, ")\n");
|
||||
g_ctrl_c_state.transition_to_spawn_process();
|
||||
const int exit_code = _wsystem(Strings::to_utf16(actual_cmd_line).c_str());
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
Debug::print("_wsystem() returned ",
|
||||
exit_code,
|
||||
" after ",
|
||||
Strings::format("%8d", static_cast<int>(timer.microseconds())),
|
||||
" us\n");
|
||||
#else
|
||||
Debug::print("_system(", cmd_line, ")\n");
|
||||
const int exit_code = system(cmd_line.c_str());
|
||||
Debug::print("_system() returned ",
|
||||
exit_code,
|
||||
" after ",
|
||||
Strings::format("%8d", static_cast<int>(timer.microseconds())),
|
||||
" us\n");
|
||||
#endif
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
ExitCodeAndOutput System::cmd_execute_and_capture_output(const ZStringView cmd_line)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
#if defined(_WIN32)
|
||||
const auto actual_cmd_line = Strings::format(R"###("%s 2>&1")###", cmd_line);
|
||||
|
||||
Debug::print("_wpopen(", actual_cmd_line, ")\n");
|
||||
std::wstring output;
|
||||
auto buf = std::make_unique<wchar_t[]>(1024 * 32);
|
||||
g_ctrl_c_state.transition_to_spawn_process();
|
||||
// Flush stdout before launching external process
|
||||
fflush(stdout);
|
||||
const auto pipe = _wpopen(Strings::to_utf16(actual_cmd_line).c_str(), L"r");
|
||||
if (pipe == nullptr)
|
||||
{
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
return {1, Strings::to_utf8(output.c_str())};
|
||||
}
|
||||
while (fgetws(buf.get(), 1024 * 32, pipe))
|
||||
{
|
||||
output.append(buf.get());
|
||||
}
|
||||
if (!feof(pipe))
|
||||
{
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
return {1, Strings::to_utf8(output.c_str())};
|
||||
}
|
||||
|
||||
const auto ec = _pclose(pipe);
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
|
||||
// On Win7, output from powershell calls contain a utf-8 byte order mark in the utf-16 stream, so we strip it
|
||||
// out if it is present. 0xEF,0xBB,0xBF is the UTF-8 byte-order mark
|
||||
const wchar_t* a = output.c_str();
|
||||
while (output.size() >= 3 && a[0] == 0xEF && a[1] == 0xBB && a[2] == 0xBF)
|
||||
{
|
||||
output.erase(0, 3);
|
||||
}
|
||||
|
||||
Debug::print("_pclose() returned ",
|
||||
ec,
|
||||
" after ",
|
||||
Strings::format("%8d", static_cast<int>(timer.microseconds())),
|
||||
" us\n");
|
||||
return {ec, Strings::to_utf8(output.c_str())};
|
||||
#else
|
||||
const auto actual_cmd_line = Strings::format(R"###(%s 2>&1)###", cmd_line);
|
||||
|
||||
Debug::print("popen(", actual_cmd_line, ")\n");
|
||||
std::string output;
|
||||
char buf[1024];
|
||||
// Flush stdout before launching external process
|
||||
fflush(stdout);
|
||||
const auto pipe = popen(actual_cmd_line.c_str(), "r");
|
||||
if (pipe == nullptr)
|
||||
{
|
||||
return {1, output};
|
||||
}
|
||||
while (fgets(buf, 1024, pipe))
|
||||
{
|
||||
output.append(buf);
|
||||
}
|
||||
if (!feof(pipe))
|
||||
{
|
||||
return {1, output};
|
||||
}
|
||||
|
||||
const auto ec = pclose(pipe);
|
||||
|
||||
Debug::print("_pclose() returned ", ec, " after ", Strings::format("%8d", (int)timer.microseconds()), " us\n");
|
||||
|
||||
return {ec, output};
|
||||
#endif
|
||||
}
|
||||
|
||||
Optional<std::string> System::get_environment_variable(ZStringView varname) noexcept
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
@ -609,24 +170,6 @@ namespace vcpkg
|
||||
return PATH;
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
static BOOL ctrl_handler(DWORD fdw_ctrl_type)
|
||||
{
|
||||
switch (fdw_ctrl_type)
|
||||
{
|
||||
case CTRL_C_EVENT: g_ctrl_c_state.transition_handle_ctrl_c(); return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void System::register_console_ctrl_handler()
|
||||
{
|
||||
SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(ctrl_handler), TRUE);
|
||||
}
|
||||
#else
|
||||
void System::register_console_ctrl_handler() {}
|
||||
#endif
|
||||
|
||||
int System::get_num_logical_cores() { return std::thread::hardware_concurrency(); }
|
||||
}
|
||||
|
||||
|
611
toolsrc/src/vcpkg/base/system.process.cpp
Normal file
611
toolsrc/src/vcpkg/base/system.process.cpp
Normal file
@ -0,0 +1,611 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/checks.h>
|
||||
#include <vcpkg/base/chrono.h>
|
||||
#include <vcpkg/base/system.debug.h>
|
||||
#include <vcpkg/base/system.h>
|
||||
#include <vcpkg/base/system.process.h>
|
||||
#include <vcpkg/base/util.h>
|
||||
|
||||
#include <ctime>
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
|
||||
#if defined(__FreeBSD__)
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
#pragma comment(lib, "Advapi32")
|
||||
#endif
|
||||
|
||||
using namespace vcpkg::System;
|
||||
|
||||
namespace vcpkg
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
namespace
|
||||
{
|
||||
struct CtrlCStateMachine
|
||||
{
|
||||
CtrlCStateMachine() : m_number_of_external_processes(0) {}
|
||||
|
||||
void transition_to_spawn_process() noexcept
|
||||
{
|
||||
int cur = 0;
|
||||
while (!m_number_of_external_processes.compare_exchange_strong(cur, cur + 1))
|
||||
{
|
||||
if (cur < 0)
|
||||
{
|
||||
// Ctrl-C was hit and is asynchronously executing on another thread.
|
||||
// Some other processes are outstanding.
|
||||
// Sleep forever -- the other process will complete and exit the program
|
||||
while (true)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
System::print2("Waiting for child processes to exit...\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
void transition_from_spawn_process() noexcept
|
||||
{
|
||||
auto previous = m_number_of_external_processes.fetch_add(-1);
|
||||
if (previous == INT_MIN + 1)
|
||||
{
|
||||
// Ctrl-C was hit while blocked on the child process
|
||||
// This is the last external process to complete
|
||||
// Therefore, exit
|
||||
Checks::final_cleanup_and_exit(1);
|
||||
}
|
||||
else if (previous < 0)
|
||||
{
|
||||
// Ctrl-C was hit while blocked on the child process
|
||||
// Some other processes are outstanding.
|
||||
// Sleep forever -- the other process will complete and exit the program
|
||||
while (true)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::seconds(10));
|
||||
System::print2("Waiting for child processes to exit...\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
void transition_handle_ctrl_c() noexcept
|
||||
{
|
||||
int old_value = 0;
|
||||
while (!m_number_of_external_processes.compare_exchange_strong(old_value, old_value + INT_MIN))
|
||||
{
|
||||
if (old_value < 0)
|
||||
{
|
||||
// Repeat calls to Ctrl-C -- a previous one succeeded.
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (old_value == 0)
|
||||
{
|
||||
// Not currently blocked on a child process
|
||||
Checks::final_cleanup_and_exit(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// We are currently blocked on a child process. Upon return, transition_from_spawn_process()
|
||||
// will be called and exit.
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<int> m_number_of_external_processes;
|
||||
};
|
||||
|
||||
static CtrlCStateMachine g_ctrl_c_state;
|
||||
}
|
||||
#endif
|
||||
|
||||
fs::path System::get_exe_path_of_current_process()
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
wchar_t buf[_MAX_PATH];
|
||||
const int bytes = GetModuleFileNameW(nullptr, buf, _MAX_PATH);
|
||||
if (bytes == 0) std::abort();
|
||||
return fs::path(buf, buf + bytes);
|
||||
#elif defined(__APPLE__)
|
||||
static constexpr const uint32_t buff_size = 1024 * 32;
|
||||
uint32_t size = buff_size;
|
||||
char buf[buff_size] = {};
|
||||
int result = _NSGetExecutablePath(buf, &size);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
|
||||
std::unique_ptr<char> canonicalPath(realpath(buf, NULL));
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != -1, "Could not determine current executable path.");
|
||||
return fs::path(std::string(canonicalPath.get()));
|
||||
#elif defined(__FreeBSD__)
|
||||
int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
|
||||
char exePath[2048];
|
||||
size_t len = sizeof(exePath);
|
||||
auto rcode = sysctl(mib, 4, exePath, &len, NULL, 0);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, rcode == 0, "Could not determine current executable path.");
|
||||
Checks::check_exit(VCPKG_LINE_INFO, len > 0, "Could not determine current executable path.");
|
||||
return fs::path(exePath, exePath + len - 1);
|
||||
#else /* LINUX */
|
||||
std::array<char, 1024 * 4> buf;
|
||||
auto written = readlink("/proc/self/exe", buf.data(), buf.size());
|
||||
Checks::check_exit(VCPKG_LINE_INFO, written != -1, "Could not determine current executable path.");
|
||||
return fs::path(buf.data(), buf.data() + written);
|
||||
#endif
|
||||
}
|
||||
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const char* varvalue)
|
||||
: s(Strings::format(R"("-D%s=%s")", varname, varvalue))
|
||||
{
|
||||
}
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const std::string& varvalue)
|
||||
: CMakeVariable(varname, varvalue.c_str())
|
||||
{
|
||||
}
|
||||
System::CMakeVariable::CMakeVariable(const StringView varname, const fs::path& path)
|
||||
: CMakeVariable(varname, path.generic_u8string())
|
||||
{
|
||||
}
|
||||
|
||||
std::string System::make_cmake_cmd(const fs::path& cmake_exe,
|
||||
const fs::path& cmake_script,
|
||||
const std::vector<CMakeVariable>& pass_variables)
|
||||
{
|
||||
const std::string cmd_cmake_pass_variables = Strings::join(" ", pass_variables, [](auto&& v) { return v.s; });
|
||||
return Strings::format(
|
||||
R"("%s" %s -P "%s")", cmake_exe.u8string(), cmd_cmake_pass_variables, cmake_script.generic_u8string());
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
Environment System::get_modified_clean_environment(const std::unordered_map<std::string, std::string>& extra_env,
|
||||
const std::string& prepend_to_path)
|
||||
{
|
||||
static const std::string SYSTEM_ROOT = get_environment_variable("SystemRoot").value_or_exit(VCPKG_LINE_INFO);
|
||||
static const std::string SYSTEM_32 = SYSTEM_ROOT + R"(\system32)";
|
||||
std::string new_path = Strings::format(R"(Path=%s%s;%s;%s\Wbem;%s\WindowsPowerShell\v1.0\)",
|
||||
prepend_to_path,
|
||||
SYSTEM_32,
|
||||
SYSTEM_ROOT,
|
||||
SYSTEM_32,
|
||||
SYSTEM_32);
|
||||
|
||||
std::vector<std::wstring> env_wstrings = {
|
||||
L"ALLUSERSPROFILE",
|
||||
L"APPDATA",
|
||||
L"CommonProgramFiles",
|
||||
L"CommonProgramFiles(x86)",
|
||||
L"CommonProgramW6432",
|
||||
L"COMPUTERNAME",
|
||||
L"ComSpec",
|
||||
L"HOMEDRIVE",
|
||||
L"HOMEPATH",
|
||||
L"LOCALAPPDATA",
|
||||
L"LOGONSERVER",
|
||||
L"NUMBER_OF_PROCESSORS",
|
||||
L"OS",
|
||||
L"PATHEXT",
|
||||
L"PROCESSOR_ARCHITECTURE",
|
||||
L"PROCESSOR_ARCHITEW6432",
|
||||
L"PROCESSOR_IDENTIFIER",
|
||||
L"PROCESSOR_LEVEL",
|
||||
L"PROCESSOR_REVISION",
|
||||
L"ProgramData",
|
||||
L"ProgramFiles",
|
||||
L"ProgramFiles(x86)",
|
||||
L"ProgramW6432",
|
||||
L"PROMPT",
|
||||
L"PSModulePath",
|
||||
L"PUBLIC",
|
||||
L"SystemDrive",
|
||||
L"SystemRoot",
|
||||
L"TEMP",
|
||||
L"TMP",
|
||||
L"USERDNSDOMAIN",
|
||||
L"USERDOMAIN",
|
||||
L"USERDOMAIN_ROAMINGPROFILE",
|
||||
L"USERNAME",
|
||||
L"USERPROFILE",
|
||||
L"windir",
|
||||
// Enables proxy information to be passed to Curl, the underlying download library in cmake.exe
|
||||
L"http_proxy",
|
||||
L"https_proxy",
|
||||
// Enables find_package(CUDA) and enable_language(CUDA) in CMake
|
||||
L"CUDA_PATH",
|
||||
L"CUDA_PATH_V9_0",
|
||||
L"CUDA_PATH_V9_1",
|
||||
L"CUDA_PATH_V10_0",
|
||||
L"CUDA_PATH_V10_1",
|
||||
L"CUDA_TOOLKIT_ROOT_DIR",
|
||||
// Environmental variable generated automatically by CUDA after installation
|
||||
L"NVCUDASAMPLES_ROOT",
|
||||
// Enables find_package(Vulkan) in CMake. Environmental variable generated by Vulkan SDK installer
|
||||
L"VULKAN_SDK",
|
||||
// Enable targeted Android NDK
|
||||
L"ANDROID_NDK_HOME",
|
||||
};
|
||||
|
||||
const Optional<std::string> keep_vars = System::get_environment_variable("VCPKG_KEEP_ENV_VARS");
|
||||
const auto k = keep_vars.get();
|
||||
|
||||
if (k && !k->empty())
|
||||
{
|
||||
auto vars = Strings::split(*k, ";");
|
||||
|
||||
for (auto&& var : vars)
|
||||
{
|
||||
env_wstrings.push_back(Strings::to_utf16(var));
|
||||
}
|
||||
}
|
||||
|
||||
std::wstring env_cstr;
|
||||
|
||||
for (auto&& env_wstring : env_wstrings)
|
||||
{
|
||||
const Optional<std::string> value = System::get_environment_variable(Strings::to_utf8(env_wstring.c_str()));
|
||||
const auto v = value.get();
|
||||
if (!v || v->empty()) continue;
|
||||
|
||||
env_cstr.append(env_wstring);
|
||||
env_cstr.push_back(L'=');
|
||||
env_cstr.append(Strings::to_utf16(*v));
|
||||
env_cstr.push_back(L'\0');
|
||||
}
|
||||
|
||||
if (extra_env.find("PATH") != extra_env.end())
|
||||
new_path += Strings::format(";%s", extra_env.find("PATH")->second);
|
||||
env_cstr.append(Strings::to_utf16(new_path));
|
||||
env_cstr.push_back(L'\0');
|
||||
env_cstr.append(L"VSLANG=1033");
|
||||
env_cstr.push_back(L'\0');
|
||||
|
||||
for (const auto& item : extra_env)
|
||||
{
|
||||
if (item.first == "PATH") continue;
|
||||
env_cstr.append(Strings::to_utf16(item.first));
|
||||
env_cstr.push_back(L'=');
|
||||
env_cstr.append(Strings::to_utf16(item.second));
|
||||
env_cstr.push_back(L'\0');
|
||||
}
|
||||
|
||||
return {env_cstr};
|
||||
}
|
||||
#else
|
||||
Environment System::get_modified_clean_environment(const std::unordered_map<std::string, std::string>&,
|
||||
const std::string&)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
#endif
|
||||
const Environment& System::get_clean_environment()
|
||||
{
|
||||
static const Environment clean_env = get_modified_clean_environment({});
|
||||
return clean_env;
|
||||
}
|
||||
|
||||
int System::cmd_execute_clean(const ZStringView cmd_line) { return cmd_execute(cmd_line, get_clean_environment()); }
|
||||
|
||||
#if defined(_WIN32)
|
||||
struct ProcessInfo
|
||||
{
|
||||
constexpr ProcessInfo() : proc_info{} {}
|
||||
|
||||
unsigned int wait_and_close_handles()
|
||||
{
|
||||
CloseHandle(proc_info.hThread);
|
||||
|
||||
const DWORD result = WaitForSingleObject(proc_info.hProcess, INFINITE);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, result != WAIT_FAILED, "WaitForSingleObject failed");
|
||||
|
||||
DWORD exit_code = 0;
|
||||
GetExitCodeProcess(proc_info.hProcess, &exit_code);
|
||||
|
||||
CloseHandle(proc_info.hProcess);
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
void close_handles()
|
||||
{
|
||||
CloseHandle(proc_info.hThread);
|
||||
CloseHandle(proc_info.hProcess);
|
||||
}
|
||||
|
||||
PROCESS_INFORMATION proc_info;
|
||||
};
|
||||
|
||||
/// <param name="maybe_environment">If non-null, an environment block to use for the new process. If null, the
|
||||
/// new process will inherit the current environment.</param>
|
||||
static ExpectedT<ProcessInfo, unsigned long> windows_create_process(const StringView cmd_line,
|
||||
const Environment& env,
|
||||
DWORD dwCreationFlags,
|
||||
STARTUPINFOW& startup_info) noexcept
|
||||
{
|
||||
ProcessInfo process_info;
|
||||
Debug::print("CreateProcessW(", cmd_line, ")\n");
|
||||
|
||||
// Flush stdout before launching external process
|
||||
fflush(nullptr);
|
||||
bool succeeded = TRUE == CreateProcessW(nullptr,
|
||||
Strings::to_utf16(cmd_line).data(),
|
||||
nullptr,
|
||||
nullptr,
|
||||
TRUE,
|
||||
IDLE_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT | dwCreationFlags,
|
||||
(void*)(env.m_env_data.empty() ? nullptr : env.m_env_data.data()),
|
||||
nullptr,
|
||||
&startup_info,
|
||||
&process_info.proc_info);
|
||||
if (succeeded)
|
||||
return process_info;
|
||||
else
|
||||
return GetLastError();
|
||||
}
|
||||
|
||||
static ExpectedT<ProcessInfo, unsigned long> windows_create_process(const StringView cmd_line,
|
||||
const Environment& env,
|
||||
DWORD dwCreationFlags) noexcept
|
||||
{
|
||||
STARTUPINFOW startup_info;
|
||||
memset(&startup_info, 0, sizeof(STARTUPINFOW));
|
||||
startup_info.cb = sizeof(STARTUPINFOW);
|
||||
|
||||
return windows_create_process(cmd_line, env, dwCreationFlags, startup_info);
|
||||
}
|
||||
|
||||
struct ProcessInfoAndPipes
|
||||
{
|
||||
ProcessInfo proc_info;
|
||||
HANDLE child_stdin = 0;
|
||||
HANDLE child_stdout = 0;
|
||||
|
||||
template<class Function>
|
||||
int wait_and_stream_output(Function&& f)
|
||||
{
|
||||
CloseHandle(child_stdin);
|
||||
|
||||
unsigned long bytes_read = 0;
|
||||
static constexpr int buffer_size = 1024 * 32;
|
||||
auto buf = std::make_unique<char[]>(buffer_size);
|
||||
while (ReadFile(child_stdout, (void*)buf.get(), buffer_size, &bytes_read, nullptr) && bytes_read > 0)
|
||||
{
|
||||
f(StringView{buf.get(), static_cast<size_t>(bytes_read)});
|
||||
}
|
||||
|
||||
CloseHandle(child_stdout);
|
||||
|
||||
return proc_info.wait_and_close_handles();
|
||||
}
|
||||
};
|
||||
|
||||
static ExpectedT<ProcessInfoAndPipes, unsigned long> windows_create_process_redirect(const StringView cmd_line,
|
||||
const Environment& env,
|
||||
DWORD dwCreationFlags) noexcept
|
||||
{
|
||||
ProcessInfoAndPipes ret;
|
||||
|
||||
STARTUPINFOW startup_info;
|
||||
memset(&startup_info, 0, sizeof(STARTUPINFOW));
|
||||
startup_info.cb = sizeof(STARTUPINFOW);
|
||||
startup_info.dwFlags |= STARTF_USESTDHANDLES;
|
||||
|
||||
SECURITY_ATTRIBUTES saAttr;
|
||||
memset(&saAttr, 0, sizeof(SECURITY_ATTRIBUTES));
|
||||
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
|
||||
saAttr.bInheritHandle = TRUE;
|
||||
saAttr.lpSecurityDescriptor = NULL;
|
||||
|
||||
// Create a pipe for the child process's STDOUT.
|
||||
if (!CreatePipe(&ret.child_stdout, &startup_info.hStdOutput, &saAttr, 0)) Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
// Ensure the read handle to the pipe for STDOUT is not inherited.
|
||||
if (!SetHandleInformation(ret.child_stdout, HANDLE_FLAG_INHERIT, 0)) Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
// Create a pipe for the child process's STDIN.
|
||||
if (!CreatePipe(&startup_info.hStdInput, &ret.child_stdin, &saAttr, 0)) Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
// Ensure the write handle to the pipe for STDIN is not inherited.
|
||||
if (!SetHandleInformation(ret.child_stdin, HANDLE_FLAG_INHERIT, 0)) Checks::exit_fail(VCPKG_LINE_INFO);
|
||||
startup_info.hStdError = startup_info.hStdOutput;
|
||||
|
||||
auto maybe_proc_info = windows_create_process(cmd_line, env, dwCreationFlags, startup_info);
|
||||
|
||||
CloseHandle(startup_info.hStdInput);
|
||||
CloseHandle(startup_info.hStdOutput);
|
||||
|
||||
if (auto proc_info = maybe_proc_info.get())
|
||||
{
|
||||
ret.proc_info = std::move(*proc_info);
|
||||
return std::move(ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
return maybe_proc_info.error();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32)
|
||||
void System::cmd_execute_no_wait(StringView cmd_line)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
auto process_info = windows_create_process(cmd_line, {}, DETACHED_PROCESS);
|
||||
if (auto p = process_info.get())
|
||||
{
|
||||
p->close_handles();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug::print("cmd_execute_no_wait() failed with error code ", process_info.error(), "\n");
|
||||
}
|
||||
|
||||
Debug::print("cmd_execute_no_wait() took ", static_cast<int>(timer.microseconds()), " us\n");
|
||||
}
|
||||
|
||||
Environment System::cmd_execute_modify_env(const ZStringView cmd_line, const Environment& env)
|
||||
{
|
||||
static StringLiteral magic_string = "cdARN4xjKueKScMy9C6H";
|
||||
|
||||
auto actual_cmd_line = Strings::concat(cmd_line, " & echo ", magic_string, "& set");
|
||||
|
||||
auto rc_output = cmd_execute_and_capture_output(actual_cmd_line, env);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, rc_output.exit_code == 0);
|
||||
auto it = Strings::search(rc_output.output, Strings::concat(magic_string, "\r\n"));
|
||||
const auto e = static_cast<const char*>(rc_output.output.data()) + rc_output.output.size();
|
||||
Checks::check_exit(VCPKG_LINE_INFO, it != e);
|
||||
it += magic_string.size() + 2;
|
||||
|
||||
std::wstring out_env;
|
||||
|
||||
while (1)
|
||||
{
|
||||
auto eq = std::find(it, e, '=');
|
||||
if (eq == e) break;
|
||||
StringView varname(it, eq);
|
||||
auto nl = std::find(eq + 1, e, '\r');
|
||||
if (nl == e) break;
|
||||
StringView value(eq + 1, nl);
|
||||
|
||||
out_env.append(Strings::to_utf16(Strings::concat(varname, '=', value)));
|
||||
out_env.push_back(L'\0');
|
||||
|
||||
it = nl + 1;
|
||||
if (it != e && *it == '\n') ++it;
|
||||
}
|
||||
|
||||
return {std::move(out_env)};
|
||||
}
|
||||
#endif
|
||||
|
||||
int System::cmd_execute(const ZStringView cmd_line, const Environment& env)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
#if defined(_WIN32)
|
||||
using vcpkg::g_ctrl_c_state;
|
||||
g_ctrl_c_state.transition_to_spawn_process();
|
||||
auto proc_info = windows_create_process(cmd_line, env, NULL);
|
||||
auto long_exit_code = [&]() -> unsigned long {
|
||||
if (auto p = proc_info.get())
|
||||
return p->wait_and_close_handles();
|
||||
else
|
||||
return proc_info.error();
|
||||
}();
|
||||
if (long_exit_code > INT_MAX) long_exit_code = INT_MAX;
|
||||
int exit_code = static_cast<int>(long_exit_code);
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
|
||||
Debug::print(
|
||||
"cmd_execute() returned ", exit_code, " after ", static_cast<unsigned int>(timer.microseconds()), " us\n");
|
||||
#else
|
||||
Debug::print("system(", cmd_line, ")\n");
|
||||
fflush(nullptr);
|
||||
int exit_code = system(cmd_line.c_str());
|
||||
Debug::print(
|
||||
"system() returned ", exit_code, " after ", static_cast<unsigned int>(timer.microseconds()), " us\n");
|
||||
#endif
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
int System::cmd_execute_and_stream_lines(const ZStringView cmd_line,
|
||||
std::function<void(const std::string&)> per_line_cb,
|
||||
const Environment& env)
|
||||
{
|
||||
std::string buf;
|
||||
|
||||
auto rc = cmd_execute_and_stream_data(
|
||||
cmd_line,
|
||||
[&](StringView sv) {
|
||||
auto prev_size = buf.size();
|
||||
Strings::append(buf, sv);
|
||||
|
||||
auto it = std::find(buf.begin() + prev_size, buf.end(), '\n');
|
||||
while (it != buf.end())
|
||||
{
|
||||
std::string s(buf.begin(), it);
|
||||
per_line_cb(s);
|
||||
buf.erase(buf.begin(), it + 1);
|
||||
it = std::find(buf.begin(), buf.end(), '\n');
|
||||
}
|
||||
},
|
||||
env);
|
||||
|
||||
per_line_cb(buf);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int System::cmd_execute_and_stream_data(const ZStringView cmd_line,
|
||||
std::function<void(StringView)> data_cb,
|
||||
const Environment& env)
|
||||
{
|
||||
auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
#if defined(_WIN32)
|
||||
using vcpkg::g_ctrl_c_state;
|
||||
|
||||
g_ctrl_c_state.transition_to_spawn_process();
|
||||
auto maybe_proc_info = windows_create_process_redirect(cmd_line, env, NULL);
|
||||
auto exit_code = [&]() -> unsigned long {
|
||||
if (auto p = maybe_proc_info.get())
|
||||
return p->wait_and_stream_output(data_cb);
|
||||
else
|
||||
return maybe_proc_info.error();
|
||||
}();
|
||||
g_ctrl_c_state.transition_from_spawn_process();
|
||||
#else
|
||||
const auto actual_cmd_line = Strings::format(R"###(%s 2>&1)###", cmd_line);
|
||||
|
||||
Debug::print("popen(", actual_cmd_line, ")\n");
|
||||
// Flush stdout before launching external process
|
||||
fflush(stdout);
|
||||
const auto pipe = popen(actual_cmd_line.c_str(), "r");
|
||||
if (pipe == nullptr)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
char buf[1024];
|
||||
while (fgets(buf, 1024, pipe))
|
||||
{
|
||||
data_cb(StringView{buf, strlen(buf)});
|
||||
}
|
||||
|
||||
if (!feof(pipe))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
const auto exit_code = pclose(pipe);
|
||||
#endif
|
||||
Debug::print("cmd_execute_and_stream_data() returned ",
|
||||
exit_code,
|
||||
" after ",
|
||||
Strings::format("%8d", static_cast<int>(timer.microseconds())),
|
||||
" us\n");
|
||||
|
||||
return exit_code;
|
||||
}
|
||||
|
||||
ExitCodeAndOutput System::cmd_execute_and_capture_output(const ZStringView cmd_line, const Environment& env)
|
||||
{
|
||||
std::string output;
|
||||
auto rc = cmd_execute_and_stream_data(
|
||||
cmd_line, [&](StringView sv) { Strings::append(output, sv); }, env);
|
||||
return {rc, std::move(output)};
|
||||
}
|
||||
|
||||
#if defined(_WIN32)
|
||||
static BOOL ctrl_handler(DWORD fdw_ctrl_type)
|
||||
{
|
||||
switch (fdw_ctrl_type)
|
||||
{
|
||||
case CTRL_C_EVENT: g_ctrl_c_state.transition_handle_ctrl_c(); return TRUE;
|
||||
default: return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void System::register_console_ctrl_handler()
|
||||
{
|
||||
SetConsoleCtrlHandler(reinterpret_cast<PHANDLER_ROUTINE>(ctrl_handler), TRUE);
|
||||
}
|
||||
#else
|
||||
void System::register_console_ctrl_handler() {}
|
||||
#endif
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include "pch.h"
|
||||
|
||||
#include <vcpkg/base/cache.h>
|
||||
#include <vcpkg/base/checks.h>
|
||||
#include <vcpkg/base/chrono.h>
|
||||
#include <vcpkg/base/enums.h>
|
||||
@ -266,21 +267,24 @@ namespace vcpkg::Build
|
||||
}));
|
||||
}
|
||||
|
||||
static auto make_env_passthrough(const PreBuildInfo& pre_build_info) -> std::unordered_map<std::string, std::string>
|
||||
static const std::unordered_map<std::string, std::string>& make_env_passthrough(const PreBuildInfo& pre_build_info)
|
||||
{
|
||||
std::unordered_map<std::string, std::string> env;
|
||||
static Cache<std::vector<std::string>, std::unordered_map<std::string, std::string>> envs;
|
||||
return envs.get_lazy(pre_build_info.passthrough_env_vars, [&]() {
|
||||
std::unordered_map<std::string, std::string> env;
|
||||
|
||||
for (auto&& env_var : pre_build_info.passthrough_env_vars)
|
||||
{
|
||||
auto env_val = System::get_environment_variable(env_var);
|
||||
|
||||
if (env_val)
|
||||
for (auto&& env_var : pre_build_info.passthrough_env_vars)
|
||||
{
|
||||
env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
auto env_val = System::get_environment_variable(env_var);
|
||||
|
||||
return env;
|
||||
if (env_val)
|
||||
{
|
||||
env[env_var] = env_val.value_or_exit(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
||||
return env;
|
||||
});
|
||||
}
|
||||
|
||||
std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset)
|
||||
@ -297,7 +301,7 @@ namespace vcpkg::Build
|
||||
const auto arch = to_vcvarsall_toolchain(pre_build_info.target_architecture, toolset);
|
||||
const auto target = to_vcvarsall_target(pre_build_info.cmake_system_name);
|
||||
|
||||
return Strings::format(R"("%s" %s %s %s %s 2>&1 <NUL)",
|
||||
return Strings::format(R"(cmd /c ""%s" %s %s %s %s 2>&1 <NUL")",
|
||||
toolset.vcvarsall.u8string(),
|
||||
Strings::join(" ", toolset.vcvarsall_options),
|
||||
arch,
|
||||
@ -419,32 +423,6 @@ namespace vcpkg::Build
|
||||
return variables;
|
||||
}
|
||||
|
||||
static std::string make_build_cmd(const VcpkgPaths& paths,
|
||||
const PreBuildInfo& pre_build_info,
|
||||
const BuildPackageConfig& config,
|
||||
Triplet triplet)
|
||||
{
|
||||
const Toolset& toolset = paths.get_toolset(pre_build_info);
|
||||
const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
|
||||
std::vector<System::CMakeVariable> variables = get_cmake_vars(paths, config, triplet, toolset);
|
||||
|
||||
const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables);
|
||||
|
||||
std::string command = make_build_env_cmd(pre_build_info, toolset);
|
||||
if (!command.empty())
|
||||
{
|
||||
#ifdef _WIN32
|
||||
command.append(" & ");
|
||||
#else
|
||||
command.append(" && ");
|
||||
#endif
|
||||
}
|
||||
|
||||
command.append(cmd_launch_cmake);
|
||||
|
||||
return command;
|
||||
}
|
||||
|
||||
static std::string get_triplet_abi(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, Triplet triplet)
|
||||
{
|
||||
static std::map<fs::path, std::string> s_hash_cache;
|
||||
@ -536,14 +514,29 @@ namespace vcpkg::Build
|
||||
|
||||
const auto timer = Chrono::ElapsedTimer::create_started();
|
||||
|
||||
std::string command = make_build_cmd(paths, pre_build_info, config, triplet);
|
||||
std::unordered_map<std::string, std::string> env = make_env_passthrough(pre_build_info);
|
||||
|
||||
auto command =
|
||||
System::make_cmake_cmd(paths.get_tool_exe(Tools::CMAKE),
|
||||
paths.ports_cmake,
|
||||
get_cmake_vars(paths, config, triplet, paths.get_toolset(pre_build_info)));
|
||||
#if defined(_WIN32)
|
||||
const int return_code =
|
||||
System::cmd_execute_clean(command, env, powershell_exe_path.parent_path().u8string() + ";");
|
||||
std::string build_env_cmd = make_build_env_cmd(pre_build_info, paths.get_toolset(pre_build_info));
|
||||
|
||||
const std::unordered_map<std::string, std::string>& base_env = make_env_passthrough(pre_build_info);
|
||||
static Cache<std::pair<const std::unordered_map<std::string, std::string>*, std::string>, System::Environment>
|
||||
build_env_cache;
|
||||
|
||||
const auto& env = build_env_cache.get_lazy({&base_env, build_env_cmd}, [&]() {
|
||||
auto clean_env =
|
||||
System::get_modified_clean_environment(base_env, powershell_exe_path.parent_path().u8string() + ";");
|
||||
if (build_env_cmd.empty())
|
||||
return clean_env;
|
||||
else
|
||||
return System::cmd_execute_modify_env(build_env_cmd, clean_env);
|
||||
});
|
||||
|
||||
const int return_code = System::cmd_execute(command, env);
|
||||
#else
|
||||
const int return_code = System::cmd_execute_clean(command, env);
|
||||
const int return_code = System::cmd_execute_clean(command);
|
||||
#endif
|
||||
// With the exception of empty packages, builds in "Download Mode" always result in failure.
|
||||
if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES)
|
||||
@ -757,7 +750,9 @@ namespace vcpkg::Build
|
||||
return nullopt;
|
||||
}
|
||||
|
||||
static int decompress_archive(const VcpkgPaths& paths, const PackageSpec& spec, const fs::path& archive_path)
|
||||
static System::ExitCodeAndOutput decompress_archive(const VcpkgPaths& paths,
|
||||
const PackageSpec& spec,
|
||||
const fs::path& archive_path)
|
||||
{
|
||||
auto& fs = paths.get_filesystem();
|
||||
|
||||
@ -770,14 +765,12 @@ namespace vcpkg::Build
|
||||
|
||||
#if defined(_WIN32)
|
||||
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||
|
||||
int result = System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string()));
|
||||
auto cmd = Strings::format(
|
||||
R"("%s" x "%s" -o"%s" -y)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string());
|
||||
#else
|
||||
int result = System::cmd_execute_clean(
|
||||
Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
|
||||
auto cmd = Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string());
|
||||
#endif
|
||||
return result;
|
||||
return System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
|
||||
}
|
||||
|
||||
// Compress the source directory into the destination file.
|
||||
@ -793,8 +786,10 @@ namespace vcpkg::Build
|
||||
#if defined(_WIN32)
|
||||
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||
|
||||
System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" a "%s" "%s\*" >nul)", seven_zip_exe.u8string(), destination.u8string(), source.u8string()));
|
||||
System::cmd_execute_and_capture_output(
|
||||
Strings::format(
|
||||
R"("%s" a "%s" "%s\*")", seven_zip_exe.u8string(), destination.u8string(), source.u8string()),
|
||||
System::get_clean_environment());
|
||||
#else
|
||||
System::cmd_execute_clean(
|
||||
Strings::format(R"(cd '%s' && zip --quiet -r '%s' *)", source.u8string(), destination.u8string()));
|
||||
@ -873,7 +868,7 @@ namespace vcpkg::Build
|
||||
{
|
||||
System::print2("Using cached binary package: ", archive_path.u8string(), "\n");
|
||||
|
||||
int archive_result = decompress_archive(paths, spec, archive_path);
|
||||
int archive_result = decompress_archive(paths, spec, archive_path).exit_code;
|
||||
|
||||
if (archive_result != 0)
|
||||
{
|
||||
|
@ -169,19 +169,19 @@ namespace vcpkg::Commands::Edit
|
||||
candidate_paths.insert(candidate_paths.end(), from_registry.cbegin(), from_registry.cend());
|
||||
|
||||
const auto txt_default = System::get_registry_string(HKEY_CLASSES_ROOT, R"(.txt\ShellNew)", "ItemName");
|
||||
if(const auto entry = txt_default.get())
|
||||
if (const auto entry = txt_default.get())
|
||||
{
|
||||
#ifdef UNICODE
|
||||
#ifdef UNICODE
|
||||
LPWSTR dst = new wchar_t[MAX_PATH];
|
||||
ExpandEnvironmentStrings(Strings::to_utf16(*entry).c_str(), dst, MAX_PATH);
|
||||
auto full_path = Strings::to_utf8(dst);
|
||||
#else
|
||||
#else
|
||||
LPSTR dst = new char[MAX_PATH];
|
||||
ExpandEnvironmentStrings(entry->c_str(), dst, MAX_PATH);
|
||||
auto full_path = std::string(dst);
|
||||
#endif
|
||||
#endif
|
||||
auto begin = full_path.find_first_not_of('@');
|
||||
candidate_paths.push_back(fs::u8path(full_path.substr(begin, full_path.find_first_of(',')-begin)));
|
||||
candidate_paths.push_back(fs::u8path(full_path.substr(begin, full_path.find_first_of(',') - begin)));
|
||||
}
|
||||
#elif defined(__APPLE__)
|
||||
candidate_paths.push_back(
|
||||
@ -191,17 +191,20 @@ namespace vcpkg::Commands::Edit
|
||||
candidate_paths.push_back(fs::path{"/usr/share/code/bin/code"});
|
||||
candidate_paths.push_back(fs::path{"/usr/bin/code"});
|
||||
|
||||
if(System::cmd_execute("command -v xdg-mime") == 0)
|
||||
if (System::cmd_execute("command -v xdg-mime") == 0)
|
||||
{
|
||||
auto mime_qry = Strings::format(R"(xdg-mime query default text/plain)");
|
||||
auto execute_result = System::cmd_execute_and_capture_output(mime_qry);
|
||||
if(execute_result.exit_code == 0 && !execute_result.output.empty())
|
||||
if (execute_result.exit_code == 0 && !execute_result.output.empty())
|
||||
{
|
||||
mime_qry = Strings::format(R"(command -v %s)", execute_result.output.substr(0, execute_result.output.find('.')));
|
||||
mime_qry = Strings::format(R"(command -v %s)",
|
||||
execute_result.output.substr(0, execute_result.output.find('.')));
|
||||
execute_result = System::cmd_execute_and_capture_output(mime_qry);
|
||||
if(execute_result.exit_code == 0 && !execute_result.output.empty())
|
||||
if (execute_result.exit_code == 0 && !execute_result.output.empty())
|
||||
{
|
||||
execute_result.output.erase(std::remove(std::begin(execute_result.output), std::end(execute_result.output), '\n'), std::end(execute_result.output));
|
||||
execute_result.output.erase(
|
||||
std::remove(std::begin(execute_result.output), std::end(execute_result.output), '\n'),
|
||||
std::end(execute_result.output));
|
||||
candidate_paths.push_back(fs::path{execute_result.output});
|
||||
}
|
||||
}
|
||||
@ -230,7 +233,7 @@ namespace vcpkg::Commands::Edit
|
||||
#ifdef _WIN32
|
||||
if (editor_exe == "Code.exe" || editor_exe == "Code - Insiders.exe")
|
||||
{
|
||||
System::cmd_execute_no_wait(cmd_line + " <NUL");
|
||||
System::cmd_execute_no_wait(Strings::concat("cmd /c \"", cmd_line, " <NUL\""));
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
#endif
|
||||
|
@ -78,7 +78,7 @@ namespace vcpkg::Commands::Env
|
||||
args.command_arguments.empty() ? "cmd" : Strings::format("cmd /c %s", args.command_arguments.at(0));
|
||||
|
||||
const std::string cmd = Strings::format("%s%s", env_cmd_prefix, env_cmd_suffix);
|
||||
System::cmd_execute_clean(cmd, extra_env);
|
||||
System::cmd_execute(cmd, System::get_modified_clean_environment(extra_env));
|
||||
Checks::exit_success(VCPKG_LINE_INFO);
|
||||
}
|
||||
}
|
||||
|
@ -370,12 +370,13 @@ namespace vcpkg::Export::IFW
|
||||
repository_dir.generic_u8string(),
|
||||
failure_point.string());
|
||||
|
||||
const auto cmd_line = Strings::format(R"("%s" --packages "%s" "%s" > nul)",
|
||||
const auto cmd_line = Strings::format(R"("%s" --packages "%s" "%s")",
|
||||
repogen_exe.u8string(),
|
||||
packages_dir.u8string(),
|
||||
repository_dir.u8string());
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
const int exit_code =
|
||||
System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
|
||||
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW repository generating failed");
|
||||
|
||||
System::printf(
|
||||
@ -397,7 +398,7 @@ namespace vcpkg::Export::IFW
|
||||
std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or("");
|
||||
if (!ifw_repo_url.empty())
|
||||
{
|
||||
cmd_line = Strings::format(R"("%s" --online-only --config "%s" --repository "%s" "%s" > nul)",
|
||||
cmd_line = Strings::format(R"("%s" --online-only --config "%s" --repository "%s" "%s")",
|
||||
binarycreator_exe.u8string(),
|
||||
config_file.u8string(),
|
||||
repository_dir.u8string(),
|
||||
@ -405,14 +406,15 @@ namespace vcpkg::Export::IFW
|
||||
}
|
||||
else
|
||||
{
|
||||
cmd_line = Strings::format(R"("%s" --config "%s" --packages "%s" "%s" > nul)",
|
||||
cmd_line = Strings::format(R"("%s" --config "%s" --packages "%s" "%s")",
|
||||
binarycreator_exe.u8string(),
|
||||
config_file.u8string(),
|
||||
packages_dir.u8string(),
|
||||
installer_file.u8string());
|
||||
}
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
const int exit_code =
|
||||
System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
|
||||
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW installer generating failed");
|
||||
|
||||
System::printf(
|
||||
|
@ -180,7 +180,7 @@ namespace vcpkg::Commands::Integrate
|
||||
if (fs.exists(old_system_wide_targets_file))
|
||||
{
|
||||
const std::string param =
|
||||
Strings::format(R"(/c DEL "%s" /Q > nul)", old_system_wide_targets_file.string());
|
||||
Strings::format(R"(/c "DEL "%s" /Q > nul")", old_system_wide_targets_file.string());
|
||||
const ElevationPromptChoice user_choice = elevated_cmd_execute(param);
|
||||
switch (user_choice)
|
||||
{
|
||||
@ -211,7 +211,7 @@ namespace vcpkg::Commands::Integrate
|
||||
const fs::path sys_src_path = tmp_dir / "vcpkg.system.targets";
|
||||
fs.write_contents(sys_src_path, create_system_targets_shortcut(), VCPKG_LINE_INFO);
|
||||
|
||||
const std::string param = Strings::format(R"(/c mkdir "%s" & copy "%s" "%s" /Y > nul)",
|
||||
const std::string param = Strings::format(R"(/c "mkdir "%s" & copy "%s" "%s" /Y > nul")",
|
||||
SYSTEM_WIDE_TARGETS_FILE.parent_path().string(),
|
||||
sys_src_path.string(),
|
||||
SYSTEM_WIDE_TARGETS_FILE.string());
|
||||
@ -347,12 +347,13 @@ CMake projects should use: "-DCMAKE_TOOLCHAIN_FILE=%s"
|
||||
nuspec_file_path, create_nuspec_file_contents(paths.root, nuget_id, nupkg_version), VCPKG_LINE_INFO);
|
||||
|
||||
// Using all forward slashes for the command line
|
||||
const std::string cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" > nul)",
|
||||
const std::string cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s")",
|
||||
nuget_exe.u8string(),
|
||||
buildsystems_dir.u8string(),
|
||||
nuspec_file_path.u8string());
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
const int exit_code =
|
||||
System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
|
||||
|
||||
const fs::path nuget_package = buildsystems_dir / Strings::format("%s.%s.nupkg", nuget_id, nupkg_version);
|
||||
Checks::check_exit(
|
||||
|
@ -90,16 +90,16 @@ namespace vcpkg::Commands::PortsDiff
|
||||
const auto checkout_this_dir =
|
||||
Strings::format(R"(.\%s)", ports_dir_name_as_string); // Must be relative to the root of the repository
|
||||
|
||||
const std::string cmd =
|
||||
Strings::format(R"("%s" --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s & "%s" reset >NUL)",
|
||||
git_exe.u8string(),
|
||||
dot_git_dir.u8string(),
|
||||
temp_checkout_path.u8string(),
|
||||
git_commit_id,
|
||||
checkout_this_dir,
|
||||
".vcpkg-root",
|
||||
git_exe.u8string());
|
||||
System::cmd_execute_clean(cmd);
|
||||
const std::string cmd = Strings::format(R"("%s" --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s)",
|
||||
git_exe.u8string(),
|
||||
dot_git_dir.u8string(),
|
||||
temp_checkout_path.u8string(),
|
||||
git_commit_id,
|
||||
checkout_this_dir,
|
||||
".vcpkg-root");
|
||||
System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
|
||||
System::cmd_execute_and_capture_output(Strings::format(R"("%s" reset)", git_exe.u8string()),
|
||||
System::get_clean_environment());
|
||||
const auto all_ports =
|
||||
Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
|
||||
std::map<std::string, VersionT> names_and_versions;
|
||||
|
@ -218,12 +218,13 @@ if (Test-Path $installedDir)
|
||||
const fs::path chocolatey_uninstall_file_path = per_package_dir_path / "tools" / "chocolateyUninstall.ps1";
|
||||
fs.write_contents(chocolatey_uninstall_file_path, chocolatey_uninstall_content, VCPKG_LINE_INFO);
|
||||
|
||||
const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes > nul)",
|
||||
const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes)",
|
||||
nuget_exe.u8string(),
|
||||
exported_dir_path.u8string(),
|
||||
nuspec_file_path.u8string());
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
const int exit_code =
|
||||
System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
|
||||
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: NuGet package creation failed");
|
||||
}
|
||||
}
|
||||
|
@ -151,12 +151,13 @@ namespace vcpkg::Export
|
||||
fs.write_contents(nuspec_file_path, nuspec_file_content, VCPKG_LINE_INFO);
|
||||
|
||||
// -NoDefaultExcludes is needed for ".vcpkg-root"
|
||||
const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes > nul)",
|
||||
const auto cmd_line = Strings::format(R"("%s" pack -OutputDirectory "%s" "%s" -NoDefaultExcludes)",
|
||||
nuget_exe.u8string(),
|
||||
output_dir.u8string(),
|
||||
nuspec_file_path.u8string());
|
||||
|
||||
const int exit_code = System::cmd_execute_clean(cmd_line);
|
||||
const int exit_code =
|
||||
System::cmd_execute_and_capture_output(cmd_line, System::get_clean_environment()).exit_code;
|
||||
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: NuGet package creation failed");
|
||||
|
||||
const fs::path output_path = output_dir / (nuget_id + "." + nuget_version + ".nupkg");
|
||||
|
@ -441,7 +441,7 @@ namespace vcpkg::Metrics
|
||||
if (ec) return;
|
||||
|
||||
#if defined(_WIN32)
|
||||
const std::string cmd_line = Strings::format("start \"vcpkgmetricsuploader.exe\" \"%s\" \"%s\"",
|
||||
const std::string cmd_line = Strings::format("cmd /c \"start \"vcpkgmetricsuploader.exe\" \"%s\" \"%s\"\"",
|
||||
temp_folder_path_exe.u8string(),
|
||||
vcpkg_metrics_txt_path.u8string());
|
||||
System::cmd_execute_no_wait(cmd_line);
|
||||
|
@ -227,6 +227,7 @@
|
||||
<ClCompile Include="..\src\vcpkg\base\stringview.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\base\system.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\base\system.print.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\base\system.process.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\binaryparagraph.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\build.cpp" />
|
||||
<ClCompile Include="..\src\vcpkg\cmakevars.cpp" />
|
||||
|
@ -228,6 +228,9 @@
|
||||
<ClCompile Include="..\src\vcpkg\portfileprovider.cpp">
|
||||
<Filter>Source Files\vcpkg</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\vcpkg\base\system.process.cpp">
|
||||
<Filter>Source Files\vcpkg\base</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\include\pch.h">
|
||||
|
Loading…
x
Reference in New Issue
Block a user