const std::string& chunk,
size_t index)
{
- // 1. Create a temp file for this CUDA chunk
auto tmp_result = util::TemporaryFile::create(
- FMT("{}/cuda_tmp_{}.i", ctx.config.temporary_dir(), index),
+ FMT("{}/cuda_tmp_{}", ctx.config.temporary_dir(), index),
FMT(".{}", ctx.config.cpp_extension()));
if (!tmp_result) {
return tl::unexpected(Statistic::internal_error);
const auto& chunk_path = tmp_result->path;
tmp_result->fd.close(); // we only need the path, not the open fd
- // 2. Write the chunk contents into the temp file
if (!util::write_file(chunk_path, chunk)) {
return tl::unexpected(Statistic::internal_error);
}
- // 3. Register the file so it gets cleaned up later
ctx.register_pending_tmp_file(chunk_path);
-
- // 4. Add a unique hash delimiter for this chunk
hash.hash_delimiter(FMT("cu_{}", index));
-
- // 5. Process the chunk just like a normal preprocessed file
TRY(process_preprocessed_file(ctx, hash, chunk_path));
return {};
}
static bool
-get_clang_cu_enable_verbose_mode(Args& args)
+get_clang_cu_enable_verbose_mode(const Args& args)
{
for (size_t i = 1; i < args.size(); i++) {
if (args[i] == "-v") {
util::Bytes cpp_stdout_data;
// When Clang runs in verbose mode, it outputs command details to stdout,
- // which can corrupt the output of precompiled CUDA files.
- // Therefore, caching is disabled in this scenario.
- // (Is there a better approach to handle this?)
+ // which can corrupt the output of precompiled CUDA files. Therefore, caching
+ // is disabled in this scenario. (Is there a better approach to handle this?)
const bool is_clang_cu = ctx.config.is_compiler_group_clang()
&& (ctx.args_info.actual_language == "cu"
|| ctx.args_info.actual_language == "cuda")
if (is_clang_cu) {
util::write_file(preprocessed_path, cpp_stdout_data);
-
auto chunks =
- util::split_preprocess_file_in_clang_cuda(preprocessed_path.string());
-
+ util::split_preprocessed_file_from_clang_cuda(preprocessed_path);
for (size_t i = 0; i < chunks.size(); ++i) {
TRY(process_cuda_chunk(ctx, hash, chunks[i], i));
}
sources
assertions.cpp
bytes.cpp
+ clang.cpp
cpu.cpp
direntry.cpp
environment.cpp
tokenizer.cpp
umaskscope.cpp
zstd.cpp
- clang.cpp
)
file(GLOB headers *.hpp)
#include "clang.hpp"
+#include <ccache/util/filesystem.hpp>
+#include <ccache/util/format.hpp>
#include <ccache/util/logging.hpp>
+#include <cerrno>
#include <fstream>
#include <iostream>
-#include <string>
-#include <vector>
+
+namespace fs = util::filesystem;
namespace util {
std::vector<std::string>
-split_preprocess_file_in_clang_cuda(const std::string& mixed_preprocessed_path)
+split_preprocessed_file_from_clang_cuda(const fs::path& path)
{
- std::ifstream infile(mixed_preprocessed_path);
- std::vector<std::string> split_preprocess_file_list;
+ std::ifstream infile(path);
+ std::vector<std::string> chunks;
if (!infile) {
- LOG("Can't open file {}", mixed_preprocessed_path);
- return split_preprocess_file_list;
+ LOG("Failed to open {}: {}", path, strerror(errno));
+ return chunks;
}
std::string delimiter;
if (!std::getline(infile, delimiter)) {
- return split_preprocess_file_list;
+ return chunks;
}
- std::string currentPart = delimiter + "\n";
+ std::string current_part = delimiter + "\n";
std::string line;
while (std::getline(infile, line)) {
if (line == delimiter) {
- split_preprocess_file_list.push_back(currentPart);
- currentPart = delimiter + "\n";
+ chunks.push_back(current_part);
+ current_part = delimiter + "\n";
} else {
- currentPart += line + "\n";
+ current_part += line + "\n";
}
}
- if (!currentPart.empty()) {
- split_preprocess_file_list.push_back(currentPart);
+ if (!current_part.empty()) {
+ chunks.push_back(current_part);
}
- return split_preprocess_file_list;
+ return chunks;
}
} // namespace util
#pragma once
+#include <filesystem>
#include <string>
#include <vector>
namespace util {
std::vector<std::string>
-split_preprocess_file_in_clang_cuda(const std::string& mixed_preprocessed_path);
+split_preprocessed_file_from_clang_cuda(const std::filesystem::path& path);
} // namespace util
-setup_clang() {
+set_up_clang() {
local CUDA_PATH="--cuda-path=/usr/local/cuda"
if [ ! -z "$CUDA_HOME" ]; then
local CUDA_PATH="--cuda-path=$CUDA_HOME"
return
fi
- setup_clang
+ set_up_clang
touch test.cu
if ! $REAL_CLANG -c -x cu test.cu >/dev/null 2>&1; then
- echo "Clang's CUDA support is not compatible."
+ echo "Clang's CUDA support is not compatible"
fi
}
}
EOF
-
# Test code using cuda.
cat <<EOF >test_cuda.cu
#ifndef NUM
}
clang_cu_tests() {
- setup_clang
+ set_up_clang
clang_opts_cpp="-c -x c++"
clang_opts_cuda="-c -x $CLANG_CU_LANG_TYPE"
}
SUITE_clang_cu_direct() {
- setup_clang
+ set_up_clang
clang_opts_cpp="-c -x c++"
clang_opts_cuda="-c -x $CLANG_CU_LANG_TYPE"
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+#include "testutil.hpp"
+
#include <ccache/util/clang.hpp>
+#include <ccache/util/file.hpp>
+#include <ccache/util/filesystem.hpp>
#include <doctest/doctest.h>
-#include <filesystem>
-#include <fstream>
-#include <iostream>
-#include <ostream> // https://github.com/doctest/doctest/issues/618
#include <string>
-#include <vector>
-
-TEST_SUITE_BEGIN("util");
-
-// RAII helper class for test file management
-class TestFileGuard
-{
-private:
- std::string filename_;
-public:
- explicit TestFileGuard(const std::string& filename) : filename_(filename)
- {
- }
-
- ~TestFileGuard()
- {
- try {
- if (std::filesystem::exists(filename_)) {
- std::filesystem::remove(filename_);
- }
- } catch (...) {
- // Ignore cleanup errors in destructor
- }
- }
+namespace fs = util::filesystem;
- void
- create_file(const std::string& content)
- {
- std::ofstream outfile;
- outfile.open(filename_);
- if (outfile.is_open()) {
- outfile << content;
- outfile.close();
- }
- }
+using TestUtil::TestContext;
- const std::string&
- filename() const
- {
- return filename_;
- }
-};
+TEST_SUITE_BEGIN("util");
-TEST_CASE("util::split_preprocess_file_in_clang_cuda")
+TEST_CASE("util::split_preprocessed_file_from_clang_cuda")
{
+ TestContext test_context;
+
SUBCASE("normal")
{
- TestFileGuard guard("test_normal.txt");
- std::string content = R"(# 1 "test_cuda.cu"
+ fs::path filename = "test_normal.txt";
+ util::write_file(filename, R"(# 1 "test_cuda.cu"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
void caller() {
# 1 "test_cuda.cu"
# 1 "<built-in>" 1
# 1 "<built-in>" 3
-)";
- guard.create_file(content);
+)");
- auto result = util::split_preprocess_file_in_clang_cuda(guard.filename());
+ auto result = util::split_preprocessed_file_from_clang_cuda(filename);
REQUIRE(result.size() == 2);
CHECK(result[0] == R"(# 1 "test_cuda.cu"
SUBCASE("non-existent file")
{
- std::string nonexistent_file = "nonexistent_file_12345.txt";
-
- auto result = util::split_preprocess_file_in_clang_cuda(nonexistent_file);
-
- CHECK(result.empty());
+ fs::path filename = "nonexistent_file.txt";
+ CHECK(util::split_preprocessed_file_from_clang_cuda(filename).empty());
}
SUBCASE("empty file")
{
- TestFileGuard guard("test_empty.txt");
- guard.create_file("");
-
- auto result = util::split_preprocess_file_in_clang_cuda(guard.filename());
+ fs::path filename = "test_empty.txt";
+ util::write_file(filename, "");
- CHECK(result.empty());
+ CHECK(util::split_preprocessed_file_from_clang_cuda(filename).empty());
}
}