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

Feature/cache compiler hash #1557

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 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
8f81ce3
Merge branch 'main' into feature/cache-compiler-hash
autoantwort Dec 28, 2024
b8fa09a
Remove controversial stuff
autoantwort Dec 29, 2024
3a88439
caching in c++
autoantwort Dec 30, 2024
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 @@ -198,6 +198,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;

// absolute/system_complete + lexically_normal + fixup_win32_path_case
// we don't use real canonical due to issues like:
// https://github.com/microsoft/vcpkg/issues/16614 (canonical breaking on some older Windows Server containers)
Expand Down
3 changes: 2 additions & 1 deletion include/vcpkg/commands.build.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ namespace vcpkg
std::string id;
std::string version;
std::string hash;
std::string path;
Path c_compiler_path;
Path cxx_compiler_path;
};

struct AbiInfo
Expand Down
1 change: 1 addition & 0 deletions include/vcpkg/installedpaths.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ namespace vcpkg
Path vcpkg_dir_updates() const { return vcpkg_dir() / FileUpdates; }
Path lockfile_path() const { return vcpkg_dir() / FileVcpkgLock; }
Path triplet_dir(Triplet t) const { return m_root / t.canonical_name(); }
Path compiler_hash_cache_file() const { return vcpkg_dir() / "compiler_hash_cache.json"; }
Path share_dir(const PackageSpec& p) const { return triplet_dir(p.triplet()) / FileShare / p.name(); }
Path usage_file(const PackageSpec& p) const { return share_dir(p) / FileUsage; }
Path spdx_file(const PackageSpec& p) const { return share_dir(p) / FileVcpkgSpdxJson; }
Expand Down
34 changes: 34 additions & 0 deletions src/vcpkg/base/files.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,18 @@ namespace vcpkg
return result;
}

int64_t ReadOnlyFilesystem::last_write_time(const Path& target, 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;
}

Path ReadOnlyFilesystem::almost_canonical(const Path& target, LineInfo li) const
{
std::error_code ec;
Expand Down Expand Up @@ -3027,6 +3039,28 @@ namespace vcpkg
#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 Path absolute(const Path& target, std::error_code& ec) const override
{
#if defined(_WIN32)
Expand Down
164 changes: 125 additions & 39 deletions src/vcpkg/commands.build.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <vcpkg/base/contractual-constants.h>
#include <vcpkg/base/file_sink.h>
#include <vcpkg/base/hash.h>
#include <vcpkg/base/jsonreader.h>
#include <vcpkg/base/message_sinks.h>
#include <vcpkg/base/messages.h>
#include <vcpkg/base/optional.h>
Expand Down Expand Up @@ -678,19 +679,112 @@ namespace vcpkg
out_vars.emplace_back(CMakeVariableGit, paths.get_tool_exe(Tools::GIT, out_sink));
}

static std::string compute_compiler_hash(const VcpkgPaths& paths,
const Filesystem& fs,
const Path& hash_cache,
const Path& c_compiler,
const Path& cxx_compiler)
{
auto root = fs.exists(hash_cache, VCPKG_LINE_INFO)
? Json::parse_file(VCPKG_LINE_INFO, fs, hash_cache).value.object(VCPKG_LINE_INFO)
: Json::Object();
std::string hashes;
bool fileUpdated = false;
for (const Path& compiler : {c_compiler, cxx_compiler})
{
auto size = static_cast<int64_t>(fs.file_size(compiler, VCPKG_LINE_INFO));
auto last_write_time = fs.last_write_time(compiler, VCPKG_LINE_INFO);
auto maybe_value = root.get(compiler.native());
std::string hash;
if (maybe_value)
{
auto entry = maybe_value->object(VCPKG_LINE_INFO);
if (entry.get("size")->integer(VCPKG_LINE_INFO) == size &&
entry.get("last_write_time")->integer(VCPKG_LINE_INFO) == last_write_time)
{
hash = entry.get("hash")->string(VCPKG_LINE_INFO).to_string();
}
}
if (hash.empty())
{
// "cmake -E sha1sum";
Command cmd{paths.get_tool_exe(Tools::CMAKE, out_sink)};
cmd.string_arg("-E").string_arg("sha1sum").string_arg(compiler);
hash =
Strings::split(cmd_execute_and_capture_output(cmd).value_or_exit(VCPKG_LINE_INFO).output, ' ')[0];
Json::Object entry;
entry.insert("size", Json::Value::integer(size));
entry.insert("last_write_time", Json::Value::integer(last_write_time));
entry.insert("hash", Json::Value::string(hash));
root.insert_or_replace(compiler, entry);
fileUpdated = true;
}
hashes += hash;
}
if (fileUpdated)
{
fs.write_contents(hash_cache, Json::stringify(root), VCPKG_LINE_INFO);
}

return Hash::get_string_sha256(hashes);
}

static CompilerInfo load_compiler_info(const VcpkgPaths& paths,
const PreBuildInfo& pre_build_info,
const Toolset& toolset)
{
static constexpr auto vcpkg_json = R"--(
{
"name": "detect-compiler",
"version": "0",
"description": "None"
}
)--";
static constexpr auto portfile_cmake = R"--(
set(VCPKG_BUILD_TYPE release)
vcpkg_configure_cmake(
SOURCE_PATH "${CMAKE_CURRENT_LIST_DIR}"
PREFER_NINJA
OPTIONS
"-DPACKAGES_DIR=${CURRENT_PACKAGES_DIR}"
)
)--";
static constexpr auto cmakelists_txt = R"--(
cmake_minimum_required(VERSION 3.20)
project(detect_compiler NONE)

if(CMAKE_GENERATOR STREQUAL "Ninja" AND CMAKE_SYSTEM_NAME STREQUAL "Windows")
set(CMAKE_C_COMPILER_WORKS 1)
set(CMAKE_C_COMPILER_FORCED 1)
set(CMAKE_CXX_COMPILER_WORKS 1)
set(CMAKE_CXX_COMPILER_FORCED 1)
endif()

enable_language(C)
enable_language(CXX)

file(TIMESTAMP ${CMAKE_C_COMPILER} CMAKE_C_COMPILER_TIME )

file(WRITE "${PACKAGES_DIR}/abi_info" "${CMAKE_CXX_COMPILER_VERSION}
${CMAKE_CXX_COMPILER_ID}
${CMAKE_C_COMPILER}
${CMAKE_CXX_COMPILER}
${CMAKE_C_COMPILER_TIME}")
)--";
auto& triplet = pre_build_info.triplet;
msg::println(msgDetectCompilerHash, msg::triplet = triplet);
auto buildpath = paths.buildtrees() / FileDetectCompiler;
auto portpath = paths.buildtrees() / "detect_compiler-port";
auto packagespath = paths.packages() / ("detect_compiler_" + triplet.canonical_name());
auto& fs = paths.get_filesystem();
fs.write_contents_and_dirs(portpath / "vcpkg.json", vcpkg_json, VCPKG_LINE_INFO);
fs.write_contents_and_dirs(portpath / "portfile.cmake", portfile_cmake, VCPKG_LINE_INFO);
fs.write_contents_and_dirs(portpath / "CMakeLists.txt", cmakelists_txt, VCPKG_LINE_INFO);

std::vector<CMakeVariable> cmake_args{
{CMakeVariableCurrentPortDir, paths.scripts / FileDetectCompiler},
{CMakeVariableCurrentPortDir, portpath},
{CMakeVariableCurrentBuildtreesDir, buildpath},
{CMakeVariableCurrentPackagesDir,
paths.packages() / fmt::format("{}_{}", FileDetectCompiler, triplet.canonical_name())},
{CMakeVariableCurrentPackagesDir, packagespath},
// The detect_compiler "port" doesn't depend on the host triplet, so always natively compile
{CMakeVariableHostTriplet, triplet.canonical_name()},
};
Expand All @@ -699,60 +793,52 @@ namespace vcpkg
auto cmd = vcpkg::make_cmake_cmd(paths, paths.ports_cmake, std::move(cmake_args));
RedirectedProcessLaunchSettings settings;
settings.environment.emplace(paths.get_action_env(pre_build_info, toolset));
auto& fs = paths.get_filesystem();
fs.create_directory(buildpath, VCPKG_LINE_INFO);
auto stdoutlog = buildpath / ("stdout-" + triplet.canonical_name() + ".log");
CompilerInfo compiler_info;
std::string buf;

Optional<WriteFilePointer> out_file_storage = fs.open_for_write(stdoutlog, VCPKG_LINE_INFO);
auto& out_file = out_file_storage.value_or_exit(VCPKG_LINE_INFO);
auto rc = cmd_execute_and_stream_lines(cmd, settings, [&](StringView s) {
if (Strings::starts_with(s, MarkerCompilerHash))
{
compiler_info.hash = s.substr(MarkerCompilerHash.size()).to_string();
}
if (Strings::starts_with(s, MarkerCompilerCxxVersion))
{
compiler_info.version = s.substr(MarkerCompilerCxxVersion.size()).to_string();
}
if (Strings::starts_with(s, MarkerCompilerCxxId))
{
compiler_info.id = s.substr(MarkerCompilerCxxId.size()).to_string();
}
static constexpr StringLiteral s_path_marker = "#COMPILER_CXX_PATH#";
if (Strings::starts_with(s, s_path_marker))
auto result = flatten_out(cmd_execute_and_capture_output(cmd, settings), cmd.command_line());
CompilerInfo compiler_info;
if (result.has_value())
{
auto lines = fs.read_lines(packagespath / "abi_info").value_or_exit(VCPKG_LINE_INFO);
if (lines.size() >= 4)
{
const auto compiler_cxx_path = s.substr(s_path_marker.size());
compiler_info.path.assign(compiler_cxx_path.data(), compiler_cxx_path.size());
compiler_info.version = lines[0];
compiler_info.id = lines[1];
compiler_info.c_compiler_path = lines[2];
compiler_info.cxx_compiler_path = lines[3];
compiler_info.hash = compute_compiler_hash(paths,
fs,
paths.installed().compiler_hash_cache_file(),
compiler_info.c_compiler_path,
compiler_info.cxx_compiler_path);
}
Debug::println(s);
const auto old_buf_size = buf.size();
Strings::append(buf, s, '\n');
const auto write_size = buf.size() - old_buf_size;
Checks::msg_check_exit(VCPKG_LINE_INFO,
out_file.write(buf.c_str() + old_buf_size, 1, write_size) == write_size,
msgErrorWhileWriting,
msg::path = stdoutlog);
});
}

out_file_storage.clear();
if (compiler_info.hash.empty() || !succeeded(rc))
if (compiler_info.hash.empty() || !result.has_value())
{
Debug::println("Compiler information tracking can be disabled by passing --",
SwitchFeatureFlags,
"=-",
FeatureFlagCompilertracking);

msg::println_error(msgErrorDetectingCompilerInfo, msg::path = stdoutlog);
msg::write_unlocalized_text(Color::none, buf);
if (result.has_value())
{
msg::write_unlocalized_text(Color::none, *result.get());
msg::write_unlocalized_text(Color::none, fs.read_contents(packagespath / "abi_info", VCPKG_LINE_INFO));
}
else
{
msg::println(result.error());
}
Checks::msg_exit_with_error(VCPKG_LINE_INFO, msgErrorUnableToDetectCompilerInfo);
}

Debug::println("Detected compiler hash for triplet ", triplet, ": ", compiler_info.hash);
if (!compiler_info.path.empty())
if (!compiler_info.cxx_compiler_path.empty())
{
msg::println(msgCompilerPath, msg::path = compiler_info.path);
msg::println(msgCompilerPath, msg::path = compiler_info.cxx_compiler_path);
}
return compiler_info;
}
Expand Down
Loading