[vcpkg] Environment Variable Passthrough (#7290)

* use additional env param

* remove partials

* remove change to linux triplet

* Fix some issues that vicroms pointed out

* whitespace change
This commit is contained in:
Curtis J Bezault 2019-07-18 09:02:21 -07:00 committed by GitHub
parent 5a41488a51
commit bb3a9ddb6e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 280 additions and 192 deletions

View File

@ -9,3 +9,4 @@ message("VCPKG_PLATFORM_TOOLSET=${VCPKG_PLATFORM_TOOLSET}")
message("VCPKG_VISUAL_STUDIO_PATH=${VCPKG_VISUAL_STUDIO_PATH}")
message("VCPKG_CHAINLOAD_TOOLCHAIN_FILE=${VCPKG_CHAINLOAD_TOOLCHAIN_FILE}")
message("VCPKG_BUILD_TYPE=${VCPKG_BUILD_TYPE}")
message("VCPKG_ENV_PASSTHROUGH=${VCPKG_ENV_PASSTHROUGH}")

View File

@ -117,6 +117,29 @@ namespace vcpkg::Build
std::string create_error_message(const BuildResult build_result, const PackageSpec& spec);
std::string create_user_troubleshooting_message(const PackageSpec& spec);
enum class VcpkgTripletVar
{
TARGET_ARCHITECTURE = 0,
CMAKE_SYSTEM_NAME,
CMAKE_SYSTEM_VERSION,
PLATFORM_TOOLSET,
VISUAL_STUDIO_PATH,
CHAINLOAD_TOOLCHAIN_FILE,
BUILD_TYPE,
ENV_PASSTHROUGH,
};
const std::unordered_map<std::string, VcpkgTripletVar> VCPKG_OPTIONS = {
{"VCPKG_TARGET_ARCHITECTURE", VcpkgTripletVar::TARGET_ARCHITECTURE},
{"VCPKG_CMAKE_SYSTEM_NAME", VcpkgTripletVar::CMAKE_SYSTEM_NAME},
{"VCPKG_CMAKE_SYSTEM_VERSION", VcpkgTripletVar::CMAKE_SYSTEM_VERSION},
{"VCPKG_PLATFORM_TOOLSET", VcpkgTripletVar::PLATFORM_TOOLSET},
{"VCPKG_VISUAL_STUDIO_PATH", VcpkgTripletVar::VISUAL_STUDIO_PATH},
{"VCPKG_CHAINLOAD_TOOLCHAIN_FILE", VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE},
{"VCPKG_BUILD_TYPE", VcpkgTripletVar::BUILD_TYPE},
{"VCPKG_ENV_PASSTHROUGH", VcpkgTripletVar::ENV_PASSTHROUGH},
};
/// <summary>
/// Settings from the triplet file which impact the build environment and post-build checks
/// </summary>
@ -135,6 +158,7 @@ namespace vcpkg::Build
Optional<fs::path> visual_studio_path;
Optional<std::string> external_toolchain_file;
Optional<ConfigurationType> build_type;
std::vector<std::string> passthrough_env_vars;
};
std::string make_build_env_cmd(const PreBuildInfo& pre_build_info, const Toolset& toolset);

View File

@ -23,6 +23,8 @@ namespace vcpkg
std::vector<std::string> filter_dependencies(const std::vector<Dependency>& deps, const Triplet& t);
std::vector<FeatureSpec> filter_dependencies_to_specs(const std::vector<Dependency>& deps, const Triplet& t);
std::vector<Features> filter_dependencies_to_features(const std::vector<vcpkg::Dependency>& deps,
const Triplet& t);
// zlib[uwp] becomes Dependency{"zlib", "uwp"}
std::vector<Dependency> expand_qualified_dependencies(const std::vector<std::string>& depends);

View File

@ -32,24 +32,16 @@ namespace vcpkg::Build::Command
using Dependencies::InstallPlanAction;
using Dependencies::InstallPlanType;
static constexpr StringLiteral OPTION_CHECKS_ONLY = "--checks-only";
void perform_and_exit_ex(const FullPackageSpec& full_spec,
const SourceControlFileLocation& scfl,
const ParsedArguments& options,
const VcpkgPaths& paths)
{
vcpkg::Util::unused(options);
const StatusParagraphs status_db = database_load_check(paths);
const PackageSpec& spec = full_spec.package_spec;
const auto& scf = *scfl.source_control_file;
if (Util::Sets::contains(options.switches, OPTION_CHECKS_ONLY))
{
const auto pre_build_info = Build::PreBuildInfo::from_triplet_file(paths, spec.triplet());
const auto build_info = Build::read_build_info(paths.get_filesystem(), paths.build_info_file_path(spec));
const size_t error_count =
PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info, scfl.source_location);
Checks::check_exit(VCPKG_LINE_INFO, error_count == 0);
Checks::exit_success(VCPKG_LINE_INFO);
}
const SourceControlFile& scf = *scfl.source_control_file;
Checks::check_exit(VCPKG_LINE_INFO,
spec.name() == scf.core_paragraph->name,
@ -57,7 +49,6 @@ namespace vcpkg::Build::Command
scf.core_paragraph->name,
spec.name());
const StatusParagraphs status_db = database_load_check(paths);
const Build::BuildPackageOptions build_package_options{
Build::UseHeadVersion::NO,
Build::AllowDownloads::YES,
@ -104,15 +95,11 @@ namespace vcpkg::Build::Command
Checks::exit_success(VCPKG_LINE_INFO);
}
static constexpr std::array<CommandSwitch, 1> BUILD_SWITCHES = {{
{OPTION_CHECKS_ONLY, "Only run checks, do not rebuild package"},
}};
const CommandStructure COMMAND_STRUCTURE = {
Help::create_example_string("build zlib:x64-windows"),
1,
1,
{BUILD_SWITCHES, {}},
{{}, {}},
nullptr,
};
@ -230,6 +217,23 @@ namespace vcpkg::Build
}));
}
std::unordered_map<std::string, std::string> make_env_passthrough(const PreBuildInfo& pre_build_info)
{
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)
{
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)
{
if (pre_build_info.external_toolchain_file.has_value()) return "";
@ -274,7 +278,7 @@ namespace vcpkg::Build
return bcf;
}
static void write_binary_control_file(const VcpkgPaths& paths, BinaryControlFile bcf)
static void write_binary_control_file(const VcpkgPaths& paths, const BinaryControlFile& bcf)
{
std::string start = Strings::serialize(bcf.core_paragraph);
for (auto&& feature : bcf.features)
@ -285,23 +289,43 @@ namespace vcpkg::Build
paths.get_filesystem().write_contents(binary_control_file, start, VCPKG_LINE_INFO);
}
static std::vector<Features> get_dependencies(const SourceControlFile& scf,
const std::set<std::string>& feature_list,
const Triplet& triplet)
{
return Util::fmap_flatten(
feature_list,
[&](std::string const& feature) -> std::vector<Features> {
if (feature == "core")
{
return filter_dependencies_to_features(scf.core_paragraph->depends, triplet);
}
auto maybe_feature = scf.find_feature(feature);
Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
return filter_dependencies_to_features(maybe_feature.get()->depends, triplet);
});
}
static std::vector<std::string> get_dependency_names(const SourceControlFile& scf,
const std::set<std::string>& feature_list,
const Triplet& triplet)
{
return Util::fmap(get_dependencies(scf, feature_list, triplet),
[&](const Features& feat) {
return feat.name;
}
);
}
static std::vector<FeatureSpec> compute_required_feature_specs(const BuildPackageConfig& config,
const StatusParagraphs& status_db)
{
const Triplet& triplet = config.triplet;
const std::vector<std::string> dep_strings =
Util::fmap_flatten(config.feature_list, [&](std::string const& feature) -> std::vector<std::string> {
if (feature == "core")
{
return filter_dependencies(config.scf.core_paragraph->depends, triplet);
}
auto maybe_feature = config.scf.find_feature(feature);
Checks::check_exit(VCPKG_LINE_INFO, maybe_feature.has_value());
return filter_dependencies(maybe_feature.get()->depends, triplet);
});
get_dependency_names(config.scf, config.feature_list, triplet);
auto dep_fspecs = FeatureSpec::from_strings_and_triplet(dep_strings, triplet);
Util::sort_unique_erase(dep_fspecs);
@ -353,6 +377,128 @@ namespace vcpkg::Build
return concurrency;
}
static std::vector<System::CMakeVariable> get_cmake_vars(const VcpkgPaths& paths,
const BuildPackageConfig& config,
const Triplet& triplet,
const Toolset& toolset)
{
#if !defined(_WIN32)
// TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107.
// bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted.
vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA));
#endif
const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
std::string all_features;
for (auto& feature : config.scf.feature_paragraphs)
{
all_features.append(feature->name + ";");
}
std::vector<System::CMakeVariable> variables{
{"CMD", "BUILD"},
{"PORT", config.scf.core_paragraph->name},
{"CURRENT_PORT_DIR", config.port_dir},
{"TARGET_TRIPLET", triplet.canonical_name()},
{"TARGET_TRIPLET_FILE", paths.get_triplet_file_path(triplet).u8string()},
{"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
{"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
{"DOWNLOADS", paths.downloads},
{"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
{"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
{"FEATURES", Strings::join(";", config.feature_list)},
{"ALL_FEATURES", all_features},
{"VCPKG_CONCURRENCY", std::to_string(get_concurrency())},
};
if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value())
{
variables.push_back({"GIT", git_exe_path});
}
return variables;
}
static std::string make_build_cmd(const VcpkgPaths& paths,
const PreBuildInfo& pre_build_info,
const BuildPackageConfig& config,
const 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,
const Triplet& triplet)
{
static std::map<fs::path, std::string> s_hash_cache;
const fs::path triplet_file_path = paths.get_triplet_file_path(triplet);
const auto& fs = paths.get_filesystem();
std::string hash;
auto it_hash = s_hash_cache.find(triplet_file_path);
if (it_hash != s_hash_cache.end())
{
hash = it_hash->second;
}
else
{
hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1");
if (auto p = pre_build_info.external_toolchain_file.get())
{
hash += "-";
hash += Hash::get_file_hash(fs, *p, "SHA1");
}
else if (pre_build_info.cmake_system_name == "Linux")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "Darwin")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "FreeBSD")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "Android")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1");
}
s_hash_cache.emplace(triplet_file_path, hash);
}
return hash;
}
static ExtendedBuildResult do_build_package(const VcpkgPaths& paths,
const PreBuildInfo& pre_build_info,
const PackageSpec& spec,
@ -372,72 +518,16 @@ namespace vcpkg::Build
System::printf("-- Installing port from location: %s\n", config.port_dir.u8string());
}
#if !defined(_WIN32)
// TODO: remove when vcpkg.exe is in charge for acquiring tools. Change introduced in vcpkg v0.0.107.
// bootstrap should have already downloaded ninja, but making sure it is present in case it was deleted.
vcpkg::Util::unused(paths.get_tool_exe(Tools::NINJA));
#endif
const fs::path& cmake_exe_path = paths.get_tool_exe(Tools::CMAKE);
const fs::path& git_exe_path = paths.get_tool_exe(Tools::GIT);
#if defined(_WIN32)
const fs::path& powershell_exe_path = paths.get_tool_exe("powershell-core");
if (!fs.exists(powershell_exe_path.parent_path() / "powershell.exe"))
{
fs.copy(powershell_exe_path, powershell_exe_path.parent_path() / "powershell.exe", fs::copy_options::none);
}
#endif
std::string all_features;
for (auto& feature : config.scf.feature_paragraphs)
{
all_features.append(feature->name + ";");
}
const Toolset& toolset = paths.get_toolset(pre_build_info);
std::vector<System::CMakeVariable> variables{
{"CMD", "BUILD"},
{"PORT", config.scf.core_paragraph->name},
{"CURRENT_PORT_DIR", config.port_dir},
{"TARGET_TRIPLET", spec.triplet().canonical_name()},
{"TARGET_TRIPLET_FILE", triplet_file_path},
{"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
{"VCPKG_USE_HEAD_VERSION", Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
{"DOWNLOADS", paths.downloads},
{"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
{"_VCPKG_DOWNLOAD_TOOL", to_string(config.build_package_options.download_tool)},
{"FEATURES", Strings::join(";", config.feature_list)},
{"ALL_FEATURES", all_features},
{"VCPKG_CONCURRENCY", std::to_string(get_concurrency())},
};
if (!System::get_environment_variable("VCPKG_FORCE_SYSTEM_BINARIES").has_value())
{
variables.push_back({"GIT", git_exe_path});
}
const std::string cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path, paths.ports_cmake, variables);
auto 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);
const auto timer = Chrono::ElapsedTimer::create_started();
const int return_code = System::cmd_execute_clean(
command,
{}
#ifdef _WIN32
,
powershell_exe_path.parent_path().u8string() + ";"
#endif
);
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);
const int return_code =
System::cmd_execute_clean(command, env);
const auto buildtimeus = timer.microseconds();
const auto spec_string = spec.to_string();
@ -711,7 +801,7 @@ namespace vcpkg::Build
{
System::print2("Using cached binary package: ", archive_path.u8string(), "\n");
auto archive_result = decompress_archive(paths, spec, archive_path);
int archive_result = decompress_archive(paths, spec, archive_path);
if (archive_result != 0)
{
@ -946,111 +1036,60 @@ namespace vcpkg::Build
const std::string variable_name = s.at(0);
const std::string variable_value = variable_with_no_value ? "" : s.at(1);
if (variable_name == "VCPKG_TARGET_ARCHITECTURE")
auto maybe_option = VCPKG_OPTIONS.find(variable_name);
if (maybe_option != VCPKG_OPTIONS.end())
{
pre_build_info.target_architecture = variable_value;
continue;
switch (maybe_option->second)
{
case VcpkgTripletVar::TARGET_ARCHITECTURE :
pre_build_info.target_architecture = variable_value;
break;
case VcpkgTripletVar::CMAKE_SYSTEM_NAME :
pre_build_info.cmake_system_name = variable_value;
break;
case VcpkgTripletVar::CMAKE_SYSTEM_VERSION :
pre_build_info.cmake_system_version = variable_value;
break;
case VcpkgTripletVar::PLATFORM_TOOLSET :
pre_build_info.platform_toolset =
variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
break;
case VcpkgTripletVar::VISUAL_STUDIO_PATH :
pre_build_info.visual_studio_path =
variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
break;
case VcpkgTripletVar::CHAINLOAD_TOOLCHAIN_FILE :
pre_build_info.external_toolchain_file =
variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
break;
case VcpkgTripletVar::BUILD_TYPE :
if (variable_value.empty())
pre_build_info.build_type = nullopt;
else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
pre_build_info.build_type = ConfigurationType::DEBUG;
else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
pre_build_info.build_type = ConfigurationType::RELEASE;
else
Checks::exit_with_message(
VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value);
break;
case VcpkgTripletVar::ENV_PASSTHROUGH :
pre_build_info.passthrough_env_vars = Strings::split(variable_value, ";");
break;
}
}
if (variable_name == "VCPKG_CMAKE_SYSTEM_NAME")
else
{
pre_build_info.cmake_system_name = variable_value;
continue;
Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line);
}
if (variable_name == "VCPKG_CMAKE_SYSTEM_VERSION")
{
pre_build_info.cmake_system_version = variable_value;
continue;
}
if (variable_name == "VCPKG_PLATFORM_TOOLSET")
{
pre_build_info.platform_toolset =
variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
continue;
}
if (variable_name == "VCPKG_VISUAL_STUDIO_PATH")
{
pre_build_info.visual_studio_path =
variable_value.empty() ? nullopt : Optional<fs::path>{variable_value};
continue;
}
if (variable_name == "VCPKG_CHAINLOAD_TOOLCHAIN_FILE")
{
pre_build_info.external_toolchain_file =
variable_value.empty() ? nullopt : Optional<std::string>{variable_value};
continue;
}
if (variable_name == "VCPKG_BUILD_TYPE")
{
if (variable_value.empty())
pre_build_info.build_type = nullopt;
else if (Strings::case_insensitive_ascii_equals(variable_value, "debug"))
pre_build_info.build_type = ConfigurationType::DEBUG;
else if (Strings::case_insensitive_ascii_equals(variable_value, "release"))
pre_build_info.build_type = ConfigurationType::RELEASE;
else
Checks::exit_with_message(
VCPKG_LINE_INFO, "Unknown setting for VCPKG_BUILD_TYPE: %s", variable_value);
continue;
}
Checks::exit_with_message(VCPKG_LINE_INFO, "Unknown variable name %s", line);
}
pre_build_info.triplet_abi_tag = [&]() {
const auto& fs = paths.get_filesystem();
static std::map<fs::path, std::string> s_hash_cache;
auto it_hash = s_hash_cache.find(triplet_file_path);
if (it_hash != s_hash_cache.end())
{
return it_hash->second;
}
auto hash = Hash::get_file_hash(fs, triplet_file_path, "SHA1");
if (auto p = pre_build_info.external_toolchain_file.get())
{
hash += "-";
hash += Hash::get_file_hash(fs, *p, "SHA1");
}
else if (pre_build_info.cmake_system_name.empty() ||
pre_build_info.cmake_system_name == "WindowsStore")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "windows.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "Linux")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "linux.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "Darwin")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "osx.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "FreeBSD")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "freebsd.cmake", "SHA1");
}
else if (pre_build_info.cmake_system_name == "Android")
{
hash += "-";
hash += Hash::get_file_hash(fs, paths.scripts / "toolchains" / "android.cmake", "SHA1");
}
s_hash_cache.emplace(triplet_file_path, hash);
return hash;
}();
pre_build_info.triplet_abi_tag =
get_triplet_abi(paths, pre_build_info, triplet);
return pre_build_info;
}
ExtendedBuildResult::ExtendedBuildResult(BuildResult code) : code(code) {}
ExtendedBuildResult::ExtendedBuildResult(BuildResult code, std::unique_ptr<BinaryControlFile>&& bcf)
: code(code), binary_control_file(std::move(bcf))

View File

@ -238,6 +238,28 @@ namespace vcpkg
return ret;
}
std::vector<Features> filter_dependencies_to_features(const std::vector<vcpkg::Dependency>& deps,
const Triplet& t)
{
std::vector<Features> ret;
for (auto&& dep : deps)
{
auto qualifiers = Strings::split(dep.qualifier, "&");
if (std::all_of(qualifiers.begin(), qualifiers.end(), [&](const std::string& qualifier) {
if (qualifier.empty()) return true;
if (qualifier[0] == '!')
{
return t.canonical_name().find(qualifier.substr(1)) == std::string::npos;
}
return t.canonical_name().find(qualifier) != std::string::npos;
}))
{
ret.emplace_back(dep.depend);
}
}
return ret;
}
std::vector<FeatureSpec> filter_dependencies_to_specs(const std::vector<Dependency>& deps, const Triplet& t)
{
return FeatureSpec::from_strings_and_triplet(filter_dependencies(deps, t), t);