mirror of
https://github.com/microsoft/vcpkg.git
synced 2025-01-19 03:03:05 +08:00
[vcpkg] Initial commit of experimental compressed binary archiving behind a flag
This commit is contained in:
parent
9eb9eca487
commit
25b8f25dad
@ -14,7 +14,7 @@ namespace vcpkg
|
||||
{
|
||||
BinaryParagraph();
|
||||
explicit BinaryParagraph(std::unordered_map<std::string, std::string> fields);
|
||||
BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet);
|
||||
BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet, const std::string& abi_tag);
|
||||
BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet);
|
||||
|
||||
std::string displayname() const;
|
||||
|
@ -98,6 +98,7 @@ namespace vcpkg::Build
|
||||
/// </summary>
|
||||
static PreBuildInfo from_triplet_file(const VcpkgPaths& paths, const Triplet& triplet);
|
||||
|
||||
std::string triplet_abi_tag;
|
||||
std::string target_architecture;
|
||||
std::string cmake_system_name;
|
||||
std::string cmake_system_version;
|
||||
|
@ -14,6 +14,7 @@ namespace vcpkg
|
||||
|
||||
static std::atomic<bool> debugging;
|
||||
static std::atomic<bool> feature_packages;
|
||||
static std::atomic<bool> g_binary_caching;
|
||||
|
||||
static std::atomic<int> g_init_console_cp;
|
||||
static std::atomic<int> g_init_console_output_cp;
|
||||
|
@ -81,6 +81,8 @@ namespace vcpkg
|
||||
|
||||
// feature flags
|
||||
Optional<bool> featurepackages = nullopt;
|
||||
Optional<bool> binarycaching = nullopt;
|
||||
|
||||
std::string command;
|
||||
std::vector<std::string> command_arguments;
|
||||
|
||||
|
@ -263,9 +263,18 @@ int main(const int argc, const char* const* const argv)
|
||||
}
|
||||
load_config();
|
||||
|
||||
const auto vcpkg_feature_flags_env = System::get_environment_variable("VCPKG_FEATURE_FLAGS");
|
||||
if (const auto v = vcpkg_feature_flags_env.get())
|
||||
{
|
||||
auto flags = Strings::split(*v, ",");
|
||||
if (std::find(flags.begin(), flags.end(), "binarycaching") != flags.end()) GlobalState::g_binary_caching = true;
|
||||
}
|
||||
|
||||
const VcpkgCmdArguments args = VcpkgCmdArguments::create_from_command_line(argc, argv);
|
||||
|
||||
if (const auto p = args.featurepackages.get()) GlobalState::feature_packages = *p;
|
||||
if (const auto p = args.binarycaching.get()) GlobalState::g_binary_caching = *p;
|
||||
|
||||
if (const auto p = args.printmetrics.get()) Metrics::g_metrics.lock()->set_print_metrics(*p);
|
||||
if (const auto p = args.sendmetrics.get()) Metrics::g_metrics.lock()->set_send_metrics(*p);
|
||||
if (const auto p = args.debug.get()) GlobalState::debugging = *p;
|
||||
|
@ -71,22 +71,17 @@ namespace vcpkg
|
||||
Checks::check_exit(VCPKG_LINE_INFO, multi_arch == "same", "Multi-Arch must be 'same' but was %s", multi_arch);
|
||||
}
|
||||
|
||||
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet)
|
||||
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const Triplet& triplet, const std::string& abi_tag)
|
||||
: version(spgh.version), description(spgh.description), maintainer(spgh.maintainer), abi(abi_tag)
|
||||
{
|
||||
this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
|
||||
this->version = spgh.version;
|
||||
this->description = spgh.description;
|
||||
this->maintainer = spgh.maintainer;
|
||||
this->depends = filter_dependencies(spgh.depends, triplet);
|
||||
}
|
||||
|
||||
BinaryParagraph::BinaryParagraph(const SourceParagraph& spgh, const FeatureParagraph& fpgh, const Triplet& triplet)
|
||||
: version(), feature(fpgh.name), description(fpgh.description), maintainer()
|
||||
{
|
||||
this->spec = PackageSpec::from_name_and_triplet(spgh.name, triplet).value_or_exit(VCPKG_LINE_INFO);
|
||||
this->version = "";
|
||||
this->feature = fpgh.name;
|
||||
this->description = fpgh.description;
|
||||
this->maintainer = "";
|
||||
this->depends = filter_dependencies(fpgh.depends, triplet);
|
||||
}
|
||||
|
||||
|
@ -238,10 +238,11 @@ namespace vcpkg::Build
|
||||
|
||||
static std::unique_ptr<BinaryControlFile> create_binary_control_file(const SourceParagraph& source_paragraph,
|
||||
const Triplet& triplet,
|
||||
const BuildInfo& build_info)
|
||||
const BuildInfo& build_info,
|
||||
const std::string& abi_tag)
|
||||
{
|
||||
auto bcf = std::make_unique<BinaryControlFile>();
|
||||
BinaryParagraph bpgh(source_paragraph, triplet);
|
||||
BinaryParagraph bpgh(source_paragraph, triplet, abi_tag);
|
||||
if (const auto p_ver = build_info.version.get())
|
||||
{
|
||||
bpgh.version = *p_ver;
|
||||
@ -321,11 +322,23 @@ namespace vcpkg::Build
|
||||
auto& fs = paths.get_filesystem();
|
||||
const Triplet& triplet = config.triplet;
|
||||
|
||||
struct AbiEntry
|
||||
{
|
||||
std::string key;
|
||||
std::string value;
|
||||
};
|
||||
|
||||
std::vector<AbiEntry> abi_tag_entries;
|
||||
|
||||
const PackageSpec spec =
|
||||
PackageSpec::from_name_and_triplet(config.scf.core_paragraph->name, triplet).value_or_exit(VCPKG_LINE_INFO);
|
||||
|
||||
std::vector<FeatureSpec> required_fspecs = compute_required_feature_specs(config, status_db);
|
||||
|
||||
// extract out the actual package ids
|
||||
auto dep_pspecs = Util::fmap(required_fspecs, [](FeatureSpec const& fspec) { return fspec.spec(); });
|
||||
Util::sort_unique_erase(dep_pspecs);
|
||||
|
||||
// Find all features that aren't installed. This destroys required_fspecs.
|
||||
Util::unstable_keep_if(required_fspecs, [&](FeatureSpec const& fspec) {
|
||||
return !status_db.is_installed(fspec) && fspec.name() != spec.name();
|
||||
@ -336,14 +349,110 @@ namespace vcpkg::Build
|
||||
return {BuildResult::CASCADED_DUE_TO_MISSING_DEPENDENCIES, std::move(required_fspecs)};
|
||||
}
|
||||
|
||||
// dep_pspecs was not destroyed
|
||||
for (auto&& pspec : dep_pspecs)
|
||||
{
|
||||
if (pspec == spec) continue;
|
||||
auto status_it = status_db.find_installed(pspec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, status_it != status_db.end());
|
||||
abi_tag_entries.emplace_back(
|
||||
AbiEntry{status_it->get()->package.spec.name(), status_it->get()->package.abi});
|
||||
}
|
||||
|
||||
const fs::path& cmake_exe_path = paths.get_cmake_exe();
|
||||
const fs::path& git_exe_path = paths.get_git_exe();
|
||||
|
||||
const fs::path ports_cmake_script_path = paths.ports_cmake;
|
||||
|
||||
if (GlobalState::g_binary_caching)
|
||||
{
|
||||
abi_tag_entries.emplace_back(AbiEntry{
|
||||
"portfile", Commands::Hash::get_file_hash(cmake_exe_path, config.port_dir / "portfile.cmake", "SHA1")});
|
||||
abi_tag_entries.emplace_back(AbiEntry{
|
||||
"control", Commands::Hash::get_file_hash(cmake_exe_path, config.port_dir / "CONTROL", "SHA1")});
|
||||
}
|
||||
|
||||
const auto pre_build_info = PreBuildInfo::from_triplet_file(paths, triplet);
|
||||
abi_tag_entries.emplace_back(AbiEntry{"triplet", pre_build_info.triplet_abi_tag});
|
||||
|
||||
std::string features = Strings::join(";", config.feature_list);
|
||||
abi_tag_entries.emplace_back(AbiEntry{"features", features});
|
||||
|
||||
if (config.build_package_options.use_head_version == UseHeadVersion::YES)
|
||||
abi_tag_entries.emplace_back(AbiEntry{"head", ""});
|
||||
|
||||
std::string full_abi_info =
|
||||
Strings::join("", abi_tag_entries, [](const AbiEntry& p) { return p.key + " " + p.value + "\n"; });
|
||||
|
||||
std::string abi_tag;
|
||||
|
||||
if (GlobalState::g_binary_caching)
|
||||
{
|
||||
if (GlobalState::debugging)
|
||||
{
|
||||
System::println("[DEBUG] <abientries>");
|
||||
for (auto&& entry : abi_tag_entries)
|
||||
{
|
||||
System::println("[DEBUG] %s|%s", entry.key, entry.value);
|
||||
}
|
||||
System::println("[DEBUG] </abientries>");
|
||||
}
|
||||
|
||||
auto abi_tag_entries_missing = abi_tag_entries;
|
||||
Util::stable_keep_if(abi_tag_entries_missing, [](const AbiEntry& p) { return p.value.empty(); });
|
||||
|
||||
if (abi_tag_entries_missing.empty())
|
||||
{
|
||||
std::error_code ec;
|
||||
fs.create_directories(paths.buildtrees / spec.name(), ec);
|
||||
auto abi_file_path = paths.buildtrees / spec.name() / "vcpkg_abi_info";
|
||||
fs.write_contents(abi_file_path, full_abi_info);
|
||||
|
||||
abi_tag = Commands::Hash::get_file_hash(paths.get_cmake_exe(), abi_file_path, "SHA1");
|
||||
}
|
||||
else
|
||||
{
|
||||
System::println("Warning: binary caching disabled because abi keys are missing values:\n%s",
|
||||
Strings::join("", abi_tag_entries_missing, [](const AbiEntry& e) {
|
||||
return " " + e.key + "\n";
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<BinaryControlFile> bcf;
|
||||
|
||||
auto archives_dir = paths.root / "archives";
|
||||
if (!abi_tag.empty())
|
||||
{
|
||||
archives_dir /= abi_tag.substr(0, 2);
|
||||
}
|
||||
auto archive_path = archives_dir / (abi_tag + ".zip");
|
||||
|
||||
if (GlobalState::g_binary_caching && !abi_tag.empty() && fs.exists(archive_path))
|
||||
{
|
||||
System::println("Using cached binary package: %s", archive_path.u8string());
|
||||
|
||||
auto pkg_path = paths.package_dir(spec);
|
||||
std::error_code ec;
|
||||
fs.remove_all(pkg_path, ec);
|
||||
fs.create_directories(pkg_path, ec);
|
||||
auto files = fs.get_files_non_recursive(pkg_path);
|
||||
Checks::check_exit(VCPKG_LINE_INFO, files.empty(), "unable to clear path: %s", pkg_path.u8string());
|
||||
|
||||
auto&& _7za = paths.get_7za_exe();
|
||||
|
||||
System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" x "%s" -o"%s" -y >nul)", _7za.u8string(), archive_path.u8string(), pkg_path.u8string()));
|
||||
|
||||
auto maybe_bcf = Paragraphs::try_load_cached_control_package(paths, spec);
|
||||
bcf = std::make_unique<BinaryControlFile>(std::move(maybe_bcf).value_or_exit(VCPKG_LINE_INFO));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (GlobalState::g_binary_caching && !abi_tag.empty())
|
||||
{
|
||||
System::println("Could not locate cached archive: %s", archive_path.u8string());
|
||||
}
|
||||
|
||||
std::string all_features;
|
||||
for (auto& feature : config.scf.feature_paragraphs)
|
||||
@ -363,7 +472,8 @@ namespace vcpkg::Build
|
||||
{"VCPKG_PLATFORM_TOOLSET", toolset.version.c_str()},
|
||||
{"VCPKG_USE_HEAD_VERSION",
|
||||
Util::Enum::to_bool(config.build_package_options.use_head_version) ? "1" : "0"},
|
||||
{"_VCPKG_NO_DOWNLOADS", !Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
|
||||
{"_VCPKG_NO_DOWNLOADS",
|
||||
!Util::Enum::to_bool(config.build_package_options.allow_downloads) ? "1" : "0"},
|
||||
{"GIT", git_exe_path},
|
||||
{"FEATURES", features},
|
||||
{"ALL_FEATURES", all_features},
|
||||
@ -393,7 +503,7 @@ namespace vcpkg::Build
|
||||
const BuildInfo build_info = read_build_info(fs, paths.build_info_file_path(spec));
|
||||
const size_t error_count = PostBuildLint::perform_all_checks(spec, paths, pre_build_info, build_info);
|
||||
|
||||
auto bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info);
|
||||
bcf = create_binary_control_file(*config.scf.core_paragraph, triplet, build_info, abi_tag);
|
||||
|
||||
if (error_count != 0)
|
||||
{
|
||||
@ -409,8 +519,40 @@ namespace vcpkg::Build
|
||||
}
|
||||
}
|
||||
|
||||
if (GlobalState::g_binary_caching && !abi_tag.empty())
|
||||
{
|
||||
std::error_code ec;
|
||||
fs.write_contents(
|
||||
paths.package_dir(spec) / "share" / spec.name() / "vcpkg_abi_info.txt", full_abi_info, ec);
|
||||
}
|
||||
|
||||
write_binary_control_file(paths, *bcf);
|
||||
|
||||
if (GlobalState::g_binary_caching && !abi_tag.empty())
|
||||
{
|
||||
auto tmp_archive_path = paths.buildtrees / spec.name() / (spec.triplet().to_string() + ".zip");
|
||||
|
||||
std::error_code ec;
|
||||
fs.remove(tmp_archive_path, ec);
|
||||
Checks::check_exit(VCPKG_LINE_INFO,
|
||||
!fs.exists(tmp_archive_path),
|
||||
"Could not remove file: %s",
|
||||
tmp_archive_path.u8string());
|
||||
auto&& _7za = paths.get_7za_exe();
|
||||
|
||||
System::cmd_execute_clean(Strings::format(
|
||||
R"("%s" a "%s" "%s\*" >nul)",
|
||||
_7za.u8string(),
|
||||
tmp_archive_path.u8string(),
|
||||
paths.package_dir(spec).u8string()));
|
||||
|
||||
fs.create_directories(archives_dir, ec);
|
||||
|
||||
fs.rename(tmp_archive_path, archive_path);
|
||||
|
||||
System::println("Stored binary cache: %s", archive_path.u8string());
|
||||
}
|
||||
}
|
||||
return {BuildResult::SUCCEEDED, std::move(bcf)};
|
||||
}
|
||||
|
||||
@ -549,6 +691,26 @@ namespace vcpkg::Build
|
||||
const fs::path ports_cmake_script_path = paths.scripts / "get_triplet_environment.cmake";
|
||||
const fs::path triplet_file_path = paths.triplets / (triplet.canonical_name() + ".cmake");
|
||||
|
||||
auto triplet_abi_tag = [&]() {
|
||||
static std::map<fs::path, std::string> s_hash_cache;
|
||||
|
||||
if (GlobalState::g_binary_caching)
|
||||
{
|
||||
auto it_hash = s_hash_cache.find(triplet_file_path);
|
||||
if (it_hash != s_hash_cache.end())
|
||||
{
|
||||
return it_hash->second;
|
||||
}
|
||||
auto hash = Commands::Hash::get_file_hash(paths.get_cmake_exe(), triplet_file_path, "SHA1");
|
||||
s_hash_cache.emplace(triplet_file_path, hash);
|
||||
return hash;
|
||||
}
|
||||
else
|
||||
{
|
||||
return std::string();
|
||||
}
|
||||
}();
|
||||
|
||||
const auto cmd_launch_cmake = System::make_cmake_cmd(cmake_exe_path,
|
||||
ports_cmake_script_path,
|
||||
{
|
||||
@ -560,6 +722,7 @@ namespace vcpkg::Build
|
||||
const std::vector<std::string> lines = Strings::split(ec_data.output, "\n");
|
||||
|
||||
PreBuildInfo pre_build_info;
|
||||
pre_build_info.triplet_abi_tag = triplet_abi_tag;
|
||||
|
||||
const auto e = lines.cend();
|
||||
auto cur = std::find(lines.cbegin(), e, FLAG_GUID);
|
||||
|
@ -9,6 +9,7 @@ namespace vcpkg
|
||||
|
||||
std::atomic<bool> GlobalState::debugging(false);
|
||||
std::atomic<bool> GlobalState::feature_packages(true);
|
||||
std::atomic<bool> GlobalState::g_binary_caching(false);
|
||||
|
||||
std::atomic<int> GlobalState::g_init_console_cp(0);
|
||||
std::atomic<int> GlobalState::g_init_console_output_cp(0);
|
||||
|
@ -133,6 +133,15 @@ namespace vcpkg
|
||||
{
|
||||
parse_switch(false, "featurepackages", args.featurepackages);
|
||||
continue;
|
||||
}
|
||||
if (arg == "--binarycaching")
|
||||
{
|
||||
parse_switch(true, "binarycaching", args.binarycaching);
|
||||
continue;
|
||||
}
|
||||
if (arg == "--no-binarycaching")
|
||||
{
|
||||
parse_switch(false, "binarycaching", args.binarycaching);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user