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()
|
endif()
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
get_target_property(_srcs vcpkg SOURCES)
|
get_target_property(_srcs vcpkglib SOURCES)
|
||||||
|
|
||||||
if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*")
|
if(NOT CMAKE_GENERATOR MATCHES "Visual Studio .*")
|
||||||
set_property(SOURCE src/pch.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/pch.pch")
|
set_property(SOURCE src/pch.cpp APPEND PROPERTY OBJECT_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/pch.pch")
|
||||||
@ -147,8 +147,8 @@ if(MSVC)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
set_source_files_properties(src/pch.cpp PROPERTIES COMPILE_FLAGS "/Ycpch.h")
|
set_source_files_properties(src/pch.cpp PROPERTIES COMPILE_FLAGS "/Ycpch.h")
|
||||||
target_sources(vcpkg PRIVATE src/pch.cpp)
|
target_sources(vcpkglib PRIVATE src/pch.cpp)
|
||||||
target_compile_options(vcpkg PRIVATE /Yupch.h /FIpch.h /Zm200)
|
target_compile_options(vcpkglib PRIVATE /Yupch.h /FIpch.h /Zm200)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (MINGW)
|
if (MINGW)
|
||||||
|
@ -8,6 +8,9 @@ namespace vcpkg::Checks
|
|||||||
{
|
{
|
||||||
void register_global_shutdown_handler(void (*func)());
|
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
|
// Indicate that an internal error has occurred and exit the tool. This should be used when invariants have been
|
||||||
// broken.
|
// broken.
|
||||||
[[noreturn]] void unreachable(const LineInfo& line_info);
|
[[noreturn]] void unreachable(const LineInfo& line_info);
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <vcpkg/base/files.h>
|
#include <vcpkg/base/files.h>
|
||||||
#include <vcpkg/base/zstringview.h>
|
#include <vcpkg/base/zstringview.h>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -30,17 +31,34 @@ namespace vcpkg::System
|
|||||||
std::string output;
|
std::string output;
|
||||||
};
|
};
|
||||||
|
|
||||||
int cmd_execute_clean(const ZStringView cmd_line,
|
struct Environment
|
||||||
const std::unordered_map<std::string, std::string>& extra_env = {},
|
{
|
||||||
const std::string& prepend_to_path = {});
|
#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)
|
#if defined(_WIN32)
|
||||||
|
Environment cmd_execute_modify_env(const ZStringView cmd_line, const Environment& env = {});
|
||||||
|
|
||||||
void cmd_execute_no_wait(const StringView cmd_line);
|
void cmd_execute_no_wait(const StringView cmd_line);
|
||||||
#endif
|
#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();
|
void register_console_ctrl_handler();
|
||||||
}
|
}
|
||||||
|
@ -15,11 +15,17 @@ namespace vcpkg
|
|||||||
g_shutdown_handler = func;
|
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};
|
static std::atomic<bool> have_entered{false};
|
||||||
if (have_entered) std::terminate();
|
if (have_entered.exchange(true))
|
||||||
have_entered = true;
|
{
|
||||||
|
#if defined(_WIN32)
|
||||||
|
::TerminateProcess(::GetCurrentProcess(), exit_code);
|
||||||
|
#else
|
||||||
|
std::terminate();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
if (g_shutdown_handler) g_shutdown_handler();
|
if (g_shutdown_handler) g_shutdown_handler();
|
||||||
|
|
||||||
@ -38,14 +44,14 @@ namespace vcpkg
|
|||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
std::abort();
|
std::abort();
|
||||||
#else
|
#else
|
||||||
cleanup_and_exit(EXIT_FAILURE);
|
final_cleanup_and_exit(EXIT_FAILURE);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void Checks::exit_with_code(const LineInfo& line_info, const int exit_code)
|
void Checks::exit_with_code(const LineInfo& line_info, const int exit_code)
|
||||||
{
|
{
|
||||||
Debug::print(System::Color::error, line_info, '\n');
|
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)
|
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) {
|
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);
|
auto buffer = std::make_unique<char[]>(buffer_size);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -4,121 +4,14 @@
|
|||||||
#include <vcpkg/base/chrono.h>
|
#include <vcpkg/base/chrono.h>
|
||||||
#include <vcpkg/base/system.debug.h>
|
#include <vcpkg/base/system.debug.h>
|
||||||
#include <vcpkg/base/system.h>
|
#include <vcpkg/base/system.h>
|
||||||
#include <vcpkg/base/system.process.h>
|
|
||||||
#include <vcpkg/base/util.h>
|
#include <vcpkg/base/util.h>
|
||||||
|
|
||||||
#include <ctime>
|
#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;
|
using namespace vcpkg::System;
|
||||||
|
|
||||||
namespace vcpkg
|
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)
|
Optional<CPUArchitecture> System::to_cpu_architecture(StringView arch)
|
||||||
{
|
{
|
||||||
if (Strings::case_insensitive_ascii_equals(arch, "x86")) return CPUArchitecture::X86;
|
if (Strings::case_insensitive_ascii_equals(arch, "x86")) return CPUArchitecture::X86;
|
||||||
@ -179,338 +72,6 @@ namespace vcpkg
|
|||||||
return supported_architectures;
|
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
|
Optional<std::string> System::get_environment_variable(ZStringView varname) noexcept
|
||||||
{
|
{
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
@ -609,24 +170,6 @@ namespace vcpkg
|
|||||||
return PATH;
|
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(); }
|
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 "pch.h"
|
||||||
|
|
||||||
|
#include <vcpkg/base/cache.h>
|
||||||
#include <vcpkg/base/checks.h>
|
#include <vcpkg/base/checks.h>
|
||||||
#include <vcpkg/base/chrono.h>
|
#include <vcpkg/base/chrono.h>
|
||||||
#include <vcpkg/base/enums.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)
|
for (auto&& env_var : pre_build_info.passthrough_env_vars)
|
||||||
{
|
|
||||||
auto env_val = System::get_environment_variable(env_var);
|
|
||||||
|
|
||||||
if (env_val)
|
|
||||||
{
|
{
|
||||||
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)
|
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 arch = to_vcvarsall_toolchain(pre_build_info.target_architecture, toolset);
|
||||||
const auto target = to_vcvarsall_target(pre_build_info.cmake_system_name);
|
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(),
|
toolset.vcvarsall.u8string(),
|
||||||
Strings::join(" ", toolset.vcvarsall_options),
|
Strings::join(" ", toolset.vcvarsall_options),
|
||||||
arch,
|
arch,
|
||||||
@ -419,32 +423,6 @@ namespace vcpkg::Build
|
|||||||
return variables;
|
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::string get_triplet_abi(const VcpkgPaths& paths, const PreBuildInfo& pre_build_info, Triplet triplet)
|
||||||
{
|
{
|
||||||
static std::map<fs::path, std::string> s_hash_cache;
|
static std::map<fs::path, std::string> s_hash_cache;
|
||||||
@ -536,14 +514,29 @@ namespace vcpkg::Build
|
|||||||
|
|
||||||
const auto timer = Chrono::ElapsedTimer::create_started();
|
const auto timer = Chrono::ElapsedTimer::create_started();
|
||||||
|
|
||||||
std::string command = make_build_cmd(paths, pre_build_info, config, triplet);
|
auto command =
|
||||||
std::unordered_map<std::string, std::string> env = make_env_passthrough(pre_build_info);
|
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)
|
#if defined(_WIN32)
|
||||||
const int return_code =
|
std::string build_env_cmd = make_build_env_cmd(pre_build_info, paths.get_toolset(pre_build_info));
|
||||||
System::cmd_execute_clean(command, env, powershell_exe_path.parent_path().u8string() + ";");
|
|
||||||
|
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
|
#else
|
||||||
const int return_code = System::cmd_execute_clean(command, env);
|
const int return_code = System::cmd_execute_clean(command);
|
||||||
#endif
|
#endif
|
||||||
// With the exception of empty packages, builds in "Download Mode" always result in failure.
|
// With the exception of empty packages, builds in "Download Mode" always result in failure.
|
||||||
if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES)
|
if (config.build_package_options.only_downloads == Build::OnlyDownloads::YES)
|
||||||
@ -757,7 +750,9 @@ namespace vcpkg::Build
|
|||||||
return nullopt;
|
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();
|
auto& fs = paths.get_filesystem();
|
||||||
|
|
||||||
@ -770,14 +765,12 @@ namespace vcpkg::Build
|
|||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||||
|
auto cmd = Strings::format(
|
||||||
int result = System::cmd_execute_clean(Strings::format(
|
R"("%s" x "%s" -o"%s" -y)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string());
|
||||||
R"("%s" x "%s" -o"%s" -y >nul)", seven_zip_exe.u8string(), archive_path.u8string(), pkg_path.u8string()));
|
|
||||||
#else
|
#else
|
||||||
int result = System::cmd_execute_clean(
|
auto cmd = Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string());
|
||||||
Strings::format(R"(unzip -qq "%s" "-d%s")", archive_path.u8string(), pkg_path.u8string()));
|
|
||||||
#endif
|
#endif
|
||||||
return result;
|
return System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compress the source directory into the destination file.
|
// Compress the source directory into the destination file.
|
||||||
@ -793,8 +786,10 @@ namespace vcpkg::Build
|
|||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
auto&& seven_zip_exe = paths.get_tool_exe(Tools::SEVEN_ZIP);
|
||||||
|
|
||||||
System::cmd_execute_clean(Strings::format(
|
System::cmd_execute_and_capture_output(
|
||||||
R"("%s" a "%s" "%s\*" >nul)", seven_zip_exe.u8string(), destination.u8string(), source.u8string()));
|
Strings::format(
|
||||||
|
R"("%s" a "%s" "%s\*")", seven_zip_exe.u8string(), destination.u8string(), source.u8string()),
|
||||||
|
System::get_clean_environment());
|
||||||
#else
|
#else
|
||||||
System::cmd_execute_clean(
|
System::cmd_execute_clean(
|
||||||
Strings::format(R"(cd '%s' && zip --quiet -r '%s' *)", source.u8string(), destination.u8string()));
|
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");
|
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)
|
if (archive_result != 0)
|
||||||
{
|
{
|
||||||
|
@ -169,19 +169,19 @@ namespace vcpkg::Commands::Edit
|
|||||||
candidate_paths.insert(candidate_paths.end(), from_registry.cbegin(), from_registry.cend());
|
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");
|
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];
|
LPWSTR dst = new wchar_t[MAX_PATH];
|
||||||
ExpandEnvironmentStrings(Strings::to_utf16(*entry).c_str(), dst, MAX_PATH);
|
ExpandEnvironmentStrings(Strings::to_utf16(*entry).c_str(), dst, MAX_PATH);
|
||||||
auto full_path = Strings::to_utf8(dst);
|
auto full_path = Strings::to_utf8(dst);
|
||||||
#else
|
#else
|
||||||
LPSTR dst = new char[MAX_PATH];
|
LPSTR dst = new char[MAX_PATH];
|
||||||
ExpandEnvironmentStrings(entry->c_str(), dst, MAX_PATH);
|
ExpandEnvironmentStrings(entry->c_str(), dst, MAX_PATH);
|
||||||
auto full_path = std::string(dst);
|
auto full_path = std::string(dst);
|
||||||
#endif
|
#endif
|
||||||
auto begin = full_path.find_first_not_of('@');
|
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__)
|
#elif defined(__APPLE__)
|
||||||
candidate_paths.push_back(
|
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/share/code/bin/code"});
|
||||||
candidate_paths.push_back(fs::path{"/usr/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 mime_qry = Strings::format(R"(xdg-mime query default text/plain)");
|
||||||
auto execute_result = System::cmd_execute_and_capture_output(mime_qry);
|
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);
|
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});
|
candidate_paths.push_back(fs::path{execute_result.output});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +233,7 @@ namespace vcpkg::Commands::Edit
|
|||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (editor_exe == "Code.exe" || editor_exe == "Code - Insiders.exe")
|
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);
|
Checks::exit_success(VCPKG_LINE_INFO);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -78,7 +78,7 @@ namespace vcpkg::Commands::Env
|
|||||||
args.command_arguments.empty() ? "cmd" : Strings::format("cmd /c %s", args.command_arguments.at(0));
|
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);
|
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);
|
Checks::exit_success(VCPKG_LINE_INFO);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,12 +370,13 @@ namespace vcpkg::Export::IFW
|
|||||||
repository_dir.generic_u8string(),
|
repository_dir.generic_u8string(),
|
||||||
failure_point.string());
|
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(),
|
repogen_exe.u8string(),
|
||||||
packages_dir.u8string(),
|
packages_dir.u8string(),
|
||||||
repository_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");
|
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW repository generating failed");
|
||||||
|
|
||||||
System::printf(
|
System::printf(
|
||||||
@ -397,7 +398,7 @@ namespace vcpkg::Export::IFW
|
|||||||
std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or("");
|
std::string ifw_repo_url = ifw_options.maybe_repository_url.value_or("");
|
||||||
if (!ifw_repo_url.empty())
|
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(),
|
binarycreator_exe.u8string(),
|
||||||
config_file.u8string(),
|
config_file.u8string(),
|
||||||
repository_dir.u8string(),
|
repository_dir.u8string(),
|
||||||
@ -405,14 +406,15 @@ namespace vcpkg::Export::IFW
|
|||||||
}
|
}
|
||||||
else
|
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(),
|
binarycreator_exe.u8string(),
|
||||||
config_file.u8string(),
|
config_file.u8string(),
|
||||||
packages_dir.u8string(),
|
packages_dir.u8string(),
|
||||||
installer_file.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");
|
Checks::check_exit(VCPKG_LINE_INFO, exit_code == 0, "Error: IFW installer generating failed");
|
||||||
|
|
||||||
System::printf(
|
System::printf(
|
||||||
|
@ -180,7 +180,7 @@ namespace vcpkg::Commands::Integrate
|
|||||||
if (fs.exists(old_system_wide_targets_file))
|
if (fs.exists(old_system_wide_targets_file))
|
||||||
{
|
{
|
||||||
const std::string param =
|
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);
|
const ElevationPromptChoice user_choice = elevated_cmd_execute(param);
|
||||||
switch (user_choice)
|
switch (user_choice)
|
||||||
{
|
{
|
||||||
@ -211,7 +211,7 @@ namespace vcpkg::Commands::Integrate
|
|||||||
const fs::path sys_src_path = tmp_dir / "vcpkg.system.targets";
|
const fs::path sys_src_path = tmp_dir / "vcpkg.system.targets";
|
||||||
fs.write_contents(sys_src_path, create_system_targets_shortcut(), VCPKG_LINE_INFO);
|
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(),
|
SYSTEM_WIDE_TARGETS_FILE.parent_path().string(),
|
||||||
sys_src_path.string(),
|
sys_src_path.string(),
|
||||||
SYSTEM_WIDE_TARGETS_FILE.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);
|
nuspec_file_path, create_nuspec_file_contents(paths.root, nuget_id, nupkg_version), VCPKG_LINE_INFO);
|
||||||
|
|
||||||
// Using all forward slashes for the command line
|
// 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(),
|
nuget_exe.u8string(),
|
||||||
buildsystems_dir.u8string(),
|
buildsystems_dir.u8string(),
|
||||||
nuspec_file_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;
|
||||||
|
|
||||||
const fs::path nuget_package = buildsystems_dir / Strings::format("%s.%s.nupkg", nuget_id, nupkg_version);
|
const fs::path nuget_package = buildsystems_dir / Strings::format("%s.%s.nupkg", nuget_id, nupkg_version);
|
||||||
Checks::check_exit(
|
Checks::check_exit(
|
||||||
|
@ -90,16 +90,16 @@ namespace vcpkg::Commands::PortsDiff
|
|||||||
const auto checkout_this_dir =
|
const auto checkout_this_dir =
|
||||||
Strings::format(R"(.\%s)", ports_dir_name_as_string); // Must be relative to the root of the repository
|
Strings::format(R"(.\%s)", ports_dir_name_as_string); // Must be relative to the root of the repository
|
||||||
|
|
||||||
const std::string cmd =
|
const std::string cmd = Strings::format(R"("%s" --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s)",
|
||||||
Strings::format(R"("%s" --git-dir="%s" --work-tree="%s" checkout %s -f -q -- %s %s & "%s" reset >NUL)",
|
git_exe.u8string(),
|
||||||
git_exe.u8string(),
|
dot_git_dir.u8string(),
|
||||||
dot_git_dir.u8string(),
|
temp_checkout_path.u8string(),
|
||||||
temp_checkout_path.u8string(),
|
git_commit_id,
|
||||||
git_commit_id,
|
checkout_this_dir,
|
||||||
checkout_this_dir,
|
".vcpkg-root");
|
||||||
".vcpkg-root",
|
System::cmd_execute_and_capture_output(cmd, System::get_clean_environment());
|
||||||
git_exe.u8string());
|
System::cmd_execute_and_capture_output(Strings::format(R"("%s" reset)", git_exe.u8string()),
|
||||||
System::cmd_execute_clean(cmd);
|
System::get_clean_environment());
|
||||||
const auto all_ports =
|
const auto all_ports =
|
||||||
Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
|
Paragraphs::load_all_ports(paths.get_filesystem(), temp_checkout_path / ports_dir_name_as_string);
|
||||||
std::map<std::string, VersionT> names_and_versions;
|
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";
|
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);
|
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(),
|
nuget_exe.u8string(),
|
||||||
exported_dir_path.u8string(),
|
exported_dir_path.u8string(),
|
||||||
nuspec_file_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");
|
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);
|
fs.write_contents(nuspec_file_path, nuspec_file_content, VCPKG_LINE_INFO);
|
||||||
|
|
||||||
// -NoDefaultExcludes is needed for ".vcpkg-root"
|
// -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(),
|
nuget_exe.u8string(),
|
||||||
output_dir.u8string(),
|
output_dir.u8string(),
|
||||||
nuspec_file_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");
|
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");
|
const fs::path output_path = output_dir / (nuget_id + "." + nuget_version + ".nupkg");
|
||||||
|
@ -441,7 +441,7 @@ namespace vcpkg::Metrics
|
|||||||
if (ec) return;
|
if (ec) return;
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#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(),
|
temp_folder_path_exe.u8string(),
|
||||||
vcpkg_metrics_txt_path.u8string());
|
vcpkg_metrics_txt_path.u8string());
|
||||||
System::cmd_execute_no_wait(cmd_line);
|
System::cmd_execute_no_wait(cmd_line);
|
||||||
|
@ -227,6 +227,7 @@
|
|||||||
<ClCompile Include="..\src\vcpkg\base\stringview.cpp" />
|
<ClCompile Include="..\src\vcpkg\base\stringview.cpp" />
|
||||||
<ClCompile Include="..\src\vcpkg\base\system.cpp" />
|
<ClCompile Include="..\src\vcpkg\base\system.cpp" />
|
||||||
<ClCompile Include="..\src\vcpkg\base\system.print.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\binaryparagraph.cpp" />
|
||||||
<ClCompile Include="..\src\vcpkg\build.cpp" />
|
<ClCompile Include="..\src\vcpkg\build.cpp" />
|
||||||
<ClCompile Include="..\src\vcpkg\cmakevars.cpp" />
|
<ClCompile Include="..\src\vcpkg\cmakevars.cpp" />
|
||||||
|
@ -228,6 +228,9 @@
|
|||||||
<ClCompile Include="..\src\vcpkg\portfileprovider.cpp">
|
<ClCompile Include="..\src\vcpkg\portfileprovider.cpp">
|
||||||
<Filter>Source Files\vcpkg</Filter>
|
<Filter>Source Files\vcpkg</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\src\vcpkg\base\system.process.cpp">
|
||||||
|
<Filter>Source Files\vcpkg\base</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\include\pch.h">
|
<ClInclude Include="..\include\pch.h">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user