Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manifest install: Cache compiler information for change detection #362

Open
wants to merge 34 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
aac20fc
manifest install: Add option to check stamp file
autoantwort Feb 17, 2022
9139104
Merge branch 'main' into check-stamp
autoantwort Apr 24, 2022
5db2fb8
Check last_write_times instead of file hashes
autoantwort Apr 24, 2022
35bff02
Non apple unix
autoantwort Apr 24, 2022
944317d
Fix warning
autoantwort Apr 24, 2022
ee3d870
Format
autoantwort Apr 25, 2022
1848311
Merge branch 'main' into check-stamp
autoantwort Jun 2, 2022
d42a431
Merge branch 'main' into check-stamp
autoantwort Jun 9, 2022
bec26c8
Merge branch 'main' into check-stamp
autoantwort Jun 15, 2022
21decee
Merge branch 'main' into check-stamp
autoantwort Aug 9, 2022
d6321f4
Trigger Build
autoantwort Aug 9, 2022
446fc4f
Merge branch 'main' into check-stamp
autoantwort Aug 13, 2022
0fe5b17
Merge branch 'main' into check-stamp
autoantwort Oct 1, 2022
2e6b46c
Merge branch 'main' into check-stamp
autoantwort Oct 7, 2022
8e2a24d
Implement Compiler Info Cache
autoantwort Oct 21, 2022
1a20637
remove check-stamp-file code
autoantwort Oct 23, 2022
2589952
no white space changes
autoantwort Oct 23, 2022
58acd5a
Merge branch 'main' into check-stamp
autoantwort Oct 23, 2022
7b799c5
Merge branch 'main' into check-stamp
autoantwort Oct 28, 2022
e919aa1
Move detect_compiler files to source code
autoantwort Oct 30, 2022
2d3b228
Merge branch 'main' into check-stamp
autoantwort Oct 30, 2022
6d93b3a
Change last_write_time check from <= to !=
autoantwort Oct 30, 2022
3c10a82
fix wrong comparison
autoantwort Oct 31, 2022
b06227c
Merge branch 'main' into check-stamp
autoantwort Nov 9, 2022
c567f17
Merge branch 'main' into check-stamp
autoantwort Dec 21, 2022
2571fea
Merge branch 'main' into check-stamp
autoantwort Feb 20, 2023
84a45f5
Merge branch 'main' into check-stamp
autoantwort Mar 7, 2023
5933fcd
Merge branch 'main' into check-stamp
autoantwort Apr 6, 2023
56e7755
Merge branch 'main' into check-stamp
autoantwort Oct 12, 2023
5ccabbc
Merge branch 'main' into check-stamp
autoantwort Oct 12, 2023
d39e4d7
Merge branch 'main' into check-stamp
autoantwort Dec 13, 2023
0df3ea5
Merge branch 'main' into check-stamp
autoantwort Dec 25, 2024
6c940e5
Only use the cache for change detection. Never use cached compiler in…
autoantwort Jan 2, 2025
371e0f0
Merge branch 'main' into check-stamp
autoantwort Jan 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/vcpkg/base/files.h
Original file line number Diff line number Diff line change
Expand Up @@ -321,6 +321,9 @@ namespace vcpkg
virtual FileType symlink_status(const Path& target, std::error_code& ec) const = 0;
FileType symlink_status(const Path& target, LineInfo li) const noexcept;

virtual int64_t last_write_time(const Path& target, std::error_code& ec) const = 0;
int64_t last_write_time(const Path& target, LineInfo li) const noexcept;

virtual Path absolute(const Path& target, std::error_code& ec) const = 0;
Path absolute(const Path& target, LineInfo li) const;

Expand Down
1 change: 1 addition & 0 deletions include/vcpkg/base/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ namespace vcpkg::Hash

struct Hasher
{
void add_bytes(StringView data);
virtual void add_bytes(const void* start, const void* end) noexcept = 0;

// one may only call this once before calling `clear()` or the dtor
Expand Down
20 changes: 10 additions & 10 deletions include/vcpkg/commands.setinstalled.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@
namespace vcpkg::Commands::SetInstalled
{
extern const CommandStructure COMMAND_STRUCTURE;
void perform_and_exit_ex(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
const PortFileProvider::PathsPortFileProvider& provider,
BinaryCache& binary_cache,
const CMakeVars::CMakeVarProvider& cmake_vars,
Dependencies::ActionPlan action_plan,
DryRun dry_run,
const Optional<Path>& pkgsconfig_path,
Triplet host_triplet,
const Install::KeepGoing keep_going);
void perform_ex(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
const PortFileProvider::PathsPortFileProvider& provider,
BinaryCache& binary_cache,
const CMakeVars::CMakeVarProvider& cmake_vars,
Dependencies::ActionPlan action_plan,
DryRun dry_run,
const Optional<Path>& pkgsconfig_path,
Triplet host_triplet,
const Install::KeepGoing keep_going);
void perform_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
Triplet default_triplet,
Expand Down
3 changes: 2 additions & 1 deletion include/vcpkg/installedpaths.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ namespace vcpkg
Path vcpkg_dir_info() const { return vcpkg_dir() / "info"; }
Path vcpkg_dir_updates() const { return vcpkg_dir() / "updates"; }
Path lockfile_path() const { return vcpkg_dir() / "vcpkg-lock.json"; }
Path stampfile_path() const { return vcpkg_dir() / "stampfile"; }
Path triplet_dir(Triplet t) const { return m_root / t.canonical_name(); }
Path share_dir(const PackageSpec& p) const { return triplet_dir(p.triplet()) / "share" / p.name(); }
Path usage_file(const PackageSpec& p) const { return share_dir(p) / "usage"; }
Expand All @@ -29,4 +30,4 @@ namespace vcpkg
Path m_root;
};

}
}
1 change: 1 addition & 0 deletions locales/messages.en.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
"SeeURL": "See {url} for more information.",
"SettingEnvVar": "-- Setting \"{env_var}\" environment variables to \"{url}\".",
"SourceFieldPortNameMismatch": "The 'Source' field inside the CONTROL file, or \"name\" field inside the vcpkg.json file has the name {package_name} and does not match the port directory {path}.",
"StampNotChanged": "Installation skipped. Everything seems to be installed. To disable this check, don't pass the option `--{option}` to vcpkg.",
"SystemApiErrorMessage": "calling {system_api} failed with {exit_code} ({error_msg})",
"ToolFetchFailed": "Could not fetch {tool_name}.",
"ToolInWin10": "This utility is bundled with Windows 10 or later.",
Expand Down
2 changes: 2 additions & 0 deletions locales/messages.json
Original file line number Diff line number Diff line change
Expand Up @@ -332,6 +332,8 @@
"_SettingEnvVar.comment": "An example of env_var is \"HTTP(S)_PROXY\"'--' at the beginning must be preserved An example of {env_var} is VCPKG_DEFAULT_TRIPLET. An example of {url} is https://github.com/microsoft/vcpkg.",
"SourceFieldPortNameMismatch": "The 'Source' field inside the CONTROL file, or \"name\" field inside the vcpkg.json file has the name {package_name} and does not match the port directory {path}.",
"_SourceFieldPortNameMismatch.comment": "{package_name} and {path} are both names of installable ports/packages. 'Source', 'CONTROL', 'vcpkg.json', and 'name' references are locale-invariant. An example of {package_name} is zlib. An example of {path} is /foo/bar.",
"StampNotChanged": "Installation skipped. Everything seems to be installed. To disable this check, don't pass the option `--{option}` to vcpkg.",
"_StampNotChanged.comment": "An example of {option} is editable.",
"SystemApiErrorMessage": "calling {system_api} failed with {exit_code} ({error_msg})",
"_SystemApiErrorMessage.comment": "An example of {system_api} is CreateProcessW. An example of {exit_code} is 127. An example of {error_msg} is File Not Found.",
"ToolFetchFailed": "Could not fetch {tool_name}.",
Expand Down
35 changes: 35 additions & 0 deletions src/vcpkg/base/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1700,6 +1700,18 @@ namespace vcpkg
return result;
}

int64_t Filesystem::last_write_time(const Path& target, vcpkg::LineInfo li) const noexcept
{
std::error_code ec;
auto result = this->last_write_time(target, ec);
if (ec)
{
exit_filesystem_call_error(li, ec, __func__, {target});
}

return result;
}

void Filesystem::write_lines(const Path& file_path, const std::vector<std::string>& lines, LineInfo li)
{
std::error_code ec;
Expand Down Expand Up @@ -3066,6 +3078,29 @@ namespace vcpkg
return FileType::unknown;
#endif // ^^^ !_WIN32
}

virtual int64_t last_write_time(const Path& target, std::error_code& ec) const override
{
#if defined(_WIN32)
auto result = stdfs::last_write_time(to_stdfs_path(target), ec);
return result.time_since_epoch().count();
#else // ^^^ _WIN32 // !_WIN32 vvv
struct stat s;
if (::lstat(target.c_str(), &s) == 0)
{
ec.clear();
#ifdef __APPLE__
return s.st_mtimespec.tv_sec * 1'000'000'000 + s.st_mtimespec.tv_nsec;
#else
return s.st_mtim.tv_sec * 1'000'000'000 + s.st_mtim.tv_nsec;
#endif
}

ec.assign(errno, std::generic_category());
return {};
#endif // ^^^ !_WIN32
}

virtual void write_contents(const Path& file_path, StringView data, std::error_code& ec) override
{
StatsTimer t(g_us_filesystem_stats);
Expand Down
2 changes: 2 additions & 0 deletions src/vcpkg/base/hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ namespace vcpkg::Hash
return {};
}

void Hasher::add_bytes(StringView data) { add_bytes(data.data(), data.data() + data.size()); }

template<class UIntTy>
auto top_bits(UIntTy x) -> std::enable_if_t<std::is_unsigned<UIntTy>::value, uchar>
{
Expand Down
1 change: 0 additions & 1 deletion src/vcpkg/base/strings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ using namespace vcpkg;

namespace
{

DECLARE_AND_REGISTER_MESSAGE(InvalidFormatString,
(msg::actual),
"{actual} is the provided format string",
Expand Down
1 change: 0 additions & 1 deletion src/vcpkg/binarycaching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1353,7 +1353,6 @@ namespace

namespace vcpkg
{

LocalizedString UrlTemplate::valid()
{
std::vector<std::string> invalid_keys;
Expand Down
42 changes: 20 additions & 22 deletions src/vcpkg/commands.setinstalled.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,16 @@ namespace vcpkg::Commands::SetInstalled
nullptr,
};

void perform_and_exit_ex(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
const PortFileProvider::PathsPortFileProvider& provider,
BinaryCache& binary_cache,
const CMakeVars::CMakeVarProvider& cmake_vars,
Dependencies::ActionPlan action_plan,
DryRun dry_run,
const Optional<Path>& maybe_pkgsconfig,
Triplet host_triplet,
const Install::KeepGoing keep_going)
void perform_ex(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
const PortFileProvider::PathsPortFileProvider& provider,
BinaryCache& binary_cache,
const CMakeVars::CMakeVarProvider& cmake_vars,
Dependencies::ActionPlan action_plan,
DryRun dry_run,
const Optional<Path>& maybe_pkgsconfig,
Triplet host_triplet,
const Install::KeepGoing keep_going)
{
auto& fs = paths.get_filesystem();

Expand Down Expand Up @@ -139,8 +139,6 @@ namespace vcpkg::Commands::SetInstalled
Install::print_usage_information(it->get()->package, printed_usages, fs, paths.installed());
}
}

Checks::exit_success(VCPKG_LINE_INFO);
}

void perform_and_exit(const VcpkgCmdArguments& args,
Expand Down Expand Up @@ -186,16 +184,16 @@ namespace vcpkg::Commands::SetInstalled
action.build_options = Build::default_build_package_options;
}

perform_and_exit_ex(args,
paths,
provider,
binary_cache,
*cmake_vars,
std::move(action_plan),
dry_run ? DryRun::Yes : DryRun::No,
pkgsconfig,
host_triplet,
keep_going);
perform_ex(args,
paths,
provider,
binary_cache,
*cmake_vars,
std::move(action_plan),
dry_run ? DryRun::Yes : DryRun::No,
pkgsconfig,
host_triplet,
keep_going);
}

void SetInstalledCommand::perform_and_exit(const VcpkgCmdArguments& args,
Expand Down
114 changes: 103 additions & 11 deletions src/vcpkg/install.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,7 @@ namespace vcpkg::Install
static constexpr StringLiteral OPTION_RECURSE = "recurse";
static constexpr StringLiteral OPTION_KEEP_GOING = "keep-going";
static constexpr StringLiteral OPTION_EDITABLE = "editable";
static constexpr StringLiteral OPTION_CHECK_STAMP = "check-stamp";
static constexpr StringLiteral OPTION_XUNIT = "x-xunit";
static constexpr StringLiteral OPTION_USE_ARIA2 = "x-use-aria2";
static constexpr StringLiteral OPTION_CLEAN_AFTER_BUILD = "clean-after-build";
Expand All @@ -595,7 +596,7 @@ namespace vcpkg::Install
static constexpr StringLiteral OPTION_ENFORCE_PORT_CHECKS = "enforce-port-checks";
static constexpr StringLiteral OPTION_ALLOW_UNSUPPORTED_PORT = "allow-unsupported";

static constexpr std::array<CommandSwitch, 17> INSTALL_SWITCHES = {{
static constexpr std::array<CommandSwitch, 18> INSTALL_SWITCHES = {{
{OPTION_DRY_RUN, "Do not actually build or install"},
{OPTION_USE_HEAD_VERSION,
"Install the libraries on the command line using the latest upstream sources (classic mode)"},
Expand All @@ -606,6 +607,9 @@ namespace vcpkg::Install
{OPTION_KEEP_GOING, "Continue installing packages on failure"},
{OPTION_EDITABLE,
"Disable source re-extraction and binary caching for libraries on the command line (classic mode)"},
{OPTION_CHECK_STAMP,
"If the configuration (triplets, manifest file, registries, selected features) is the same as the last time "
"install is skipped. Local port modifications are not detected anymore."},

{OPTION_USE_ARIA2, "Use aria2 to perform download tasks"},
{OPTION_CLEAN_AFTER_BUILD, "Clean buildtrees, packages and downloads after building each package"},
Expand Down Expand Up @@ -897,6 +901,12 @@ namespace vcpkg::Install
"",
"The option --{option} is not supported in manifest mode.");

DECLARE_AND_REGISTER_MESSAGE(StampNotChanged,
(msg::option),
"",
"Installation skipped. Everything seems to be installed. To disable this check, don't "
"pass the option `--{option}` to vcpkg.");

void perform_and_exit(const VcpkgCmdArguments& args,
const VcpkgPaths& paths,
Triplet default_triplet,
Expand All @@ -912,6 +922,7 @@ namespace vcpkg::Install
const bool no_build_missing = Util::Sets::contains(options.switches, OPTION_ONLY_BINARYCACHING);
const bool is_recursive = Util::Sets::contains(options.switches, (OPTION_RECURSE));
const bool is_editable = Util::Sets::contains(options.switches, (OPTION_EDITABLE)) || !args.cmake_args.empty();
const bool check_stamp = Util::Sets::contains(options.switches, (OPTION_CHECK_STAMP));
const bool use_aria2 = Util::Sets::contains(options.switches, (OPTION_USE_ARIA2));
const bool clean_after_build = Util::Sets::contains(options.switches, (OPTION_CLEAN_AFTER_BUILD));
const bool clean_buildtrees_after_build =
Expand Down Expand Up @@ -972,6 +983,11 @@ namespace vcpkg::Install
msg::println_error(msgErrorInvalidClassicModeOption, msg::option = OPTION_MANIFEST_NO_DEFAULT_FEATURES);
failure = true;
}
if (Util::Sets::contains(options.switches, OPTION_CHECK_STAMP))
{
msg::println(Color::error, msgErrorInvalidClassicModeOption, msg::option = OPTION_CHECK_STAMP);
failure = true;
}
if (Util::Sets::contains(options.multisettings, OPTION_MANIFEST_FEATURE))
{
msg::println_error(msgErrorInvalidClassicModeOption, msg::option = OPTION_MANIFEST_FEATURE);
Expand Down Expand Up @@ -1107,6 +1123,79 @@ namespace vcpkg::Install
extended_overlay_ports.emplace_back(paths.builtin_ports_directory().native());
}

std::string hash;
{
auto hasher = Hash::get_hasher_for(Hash::Algorithm::Sha256);
hasher->add_bytes(default_triplet.to_string());
hasher->add_bytes(host_triplet.to_string());
for (const auto& feature : features)
{
hasher->add_bytes(feature);
}
if (paths.get_registry_set().is_default_builtin_registry())
{
auto maybe_git_sha = paths.get_current_git_sha();
if (maybe_git_sha)
{
hasher->add_bytes(maybe_git_sha.value_or_exit(VCPKG_LINE_INFO));
}
}
hash = hasher->get_hash();

auto have_file_change = [&]() {
auto last_install = fs.last_write_time(paths.installed().stampfile_path(), VCPKG_LINE_INFO);
for (auto&& path : args.overlay_ports)
{
if (fs.last_write_time(path, VCPKG_LINE_INFO) > last_install)
{
return true;
}
for (auto&& file : fs.get_files_recursive(path, VCPKG_LINE_INFO))
{
if (fs.last_write_time(file, VCPKG_LINE_INFO) > last_install)
{
return true;
}
}
}

if (fs.last_write_time(paths.get_manifest().value_or_exit(VCPKG_LINE_INFO).path, VCPKG_LINE_INFO) >
last_install)
{
return true;
}
auto config_file = paths.get_configuration().directory / "vcpkg-configuration.json";
if (fs.exists(config_file, VCPKG_LINE_INFO))
{
if (fs.last_write_time(config_file, VCPKG_LINE_INFO) > last_install)
{
return true;
}
}
if (fs.last_write_time(paths.get_triplet_file_path(default_triplet), VCPKG_LINE_INFO) >
last_install)
{
return true;
}
if (fs.last_write_time(paths.get_triplet_file_path(host_triplet), VCPKG_LINE_INFO) > last_install)
{
return true;
}
return false;
};

if (check_stamp && fs.exists(paths.installed().stampfile_path(), VCPKG_LINE_INFO))
{
if (fs.read_contents(paths.installed().stampfile_path(), VCPKG_LINE_INFO) == hash &&
!have_file_change())
{
msg::println(msgStampNotChanged, msg::option = OPTION_CHECK_STAMP);
Checks::exit_success(VCPKG_LINE_INFO);
}
fs.remove(paths.installed().stampfile_path(), VCPKG_LINE_INFO);
}
}

auto oprovider = PortFileProvider::make_manifest_provider(
paths, extended_overlay_ports, manifest->path, std::move(manifest_scf));
PackageSpec toplevel{manifest_core.name, default_triplet};
Expand Down Expand Up @@ -1137,16 +1226,19 @@ namespace vcpkg::Install
[&toplevel](auto&& action) { return action.spec == toplevel; });

PortFileProvider::PathsPortFileProvider provider(paths, std::move(oprovider));
Commands::SetInstalled::perform_and_exit_ex(args,
paths,
provider,
binary_cache,
var_provider,
std::move(install_plan),
dry_run ? Commands::DryRun::Yes : Commands::DryRun::No,
pkgsconfig,
host_triplet,
keep_going);

Commands::SetInstalled::perform_ex(args,
paths,
provider,
binary_cache,
var_provider,
std::move(install_plan),
dry_run ? Commands::DryRun::Yes : Commands::DryRun::No,
pkgsconfig,
host_triplet,
keep_going);
fs.write_contents_and_dirs(paths.installed().stampfile_path(), hash, VCPKG_LINE_INFO);
Checks::exit_success(VCPKG_LINE_INFO);
}

PortFileProvider::PathsPortFileProvider provider(
Expand Down