From c082458fb1eb94f58c57504ad9162d32c204ebe5 Mon Sep 17 00:00:00 2001 From: ykiko Date: Tue, 10 Dec 2024 16:15:50 +0800 Subject: [PATCH] 1. Make resource dir unique and global. 2. Use our custom CDB loader. --- include/Compiler/Command.h | 19 +++++ include/Compiler/Compiler.h | 16 ++-- include/Server/Command.h | 11 ++- include/Server/Scheduler.h | 2 +- include/Support/FileSystem.h | 25 +++++- src/Compiler/Command.cpp | 69 +++++++++++++++ src/Compiler/Compiler.cpp | 30 ++++--- src/Server/Command.cpp | 121 +++++++++++++++++++++------ src/Server/Scheduler.cpp | 50 ++++------- src/Server/Server.cpp | 6 ++ unittests/Compiler/Command.cpp | 53 ++++++++---- unittests/Compiler/Compiler.cpp | 64 ++------------ unittests/Compiler/Resolver.cpp | 26 ++---- unittests/Feature/CodeCompletion.cpp | 12 +-- unittests/Test.h | 10 +-- unittests/main.cpp | 12 +-- 16 files changed, 332 insertions(+), 194 deletions(-) create mode 100644 include/Compiler/Command.h create mode 100644 src/Compiler/Command.cpp diff --git a/include/Compiler/Command.h b/include/Compiler/Command.h new file mode 100644 index 00000000..31e61506 --- /dev/null +++ b/include/Compiler/Command.h @@ -0,0 +1,19 @@ +#pragma once + +#include "Clang.h" + +namespace clice { + +/// Processes and adjusts a raw compile command from compile_commands.json. +/// +/// This function tokenizes the input command, removes unnecessary arguments, +/// and ensures the resulting format is suitable for execution. +/// +/// @param command The raw shell-escaped compile command. +/// @param out A vector to hold pointers to the processed arguments. +/// @param buffer A storage buffer for the actual argument strings. +llvm::Error mangleCommand(llvm::StringRef command, + llvm::SmallVectorImpl& out, + llvm::SmallVectorImpl& buffer); + +} // namespace clice diff --git a/include/Compiler/Compiler.h b/include/Compiler/Compiler.h index 69db1482..93f76ba4 100644 --- a/include/Compiler/Compiler.h +++ b/include/Compiler/Compiler.h @@ -129,11 +129,17 @@ struct PCMInfo { }; struct CompliationParams { + /// Source file content. + llvm::StringRef content; + /// Source file path. llvm::SmallString<128> srcPath; - /// Source file content. - llvm::StringRef content; + /// Output file path. + llvm::SmallString<128> outPath; + + /// Responsible for storing the arguments. + llvm::SmallString<1024> command; /// - If we are building PCH, we need a size to verify the bounds of preamble. That is /// which source code range the PCH will cover. @@ -148,12 +154,6 @@ struct CompliationParams { /// - If the header is not empty, the preprocessor must be executed to compute the bounds. void computeBounds(llvm::StringRef header = ""); - /// Command line arguments. - llvm::ArrayRef args; - - /// Output file path. - llvm::SmallString<128> outPath; - llvm::IntrusiveRefCntPtr vfs = new ThreadSafeFS(); /// Information about reuse PCH. diff --git a/include/Server/Command.h b/include/Server/Command.h index ed889637..f467aadf 100644 --- a/include/Server/Command.h +++ b/include/Server/Command.h @@ -9,9 +9,16 @@ class CommandManager { public: void update(llvm::StringRef dir); - std::vector lookup(llvm::StringRef file); + /// Return the commands of first meet file. + llvm::StringRef lookupFirst(llvm::StringRef file); + + llvm::ArrayRef lookup(llvm::StringRef file); + private: - llvm::StringMap> CDBs; + /// CDB file -> file -> [commands] + using Commands = std::vector; + using CDB = llvm::StringMap; + llvm::StringMap CDBs; }; } // namespace clice diff --git a/include/Server/Scheduler.h b/include/Server/Scheduler.h index cd82b1c9..ee01033f 100644 --- a/include/Server/Scheduler.h +++ b/include/Server/Scheduler.h @@ -73,7 +73,7 @@ class Scheduler { private: async::promise updatePCH(llvm::StringRef path, llvm::StringRef content, - llvm::ArrayRef args); + llvm::StringRef command); async::promise updatePCM() { co_return; diff --git a/include/Support/FileSystem.h b/include/Support/FileSystem.h index ef8c00e6..be2bb62f 100644 --- a/include/Support/FileSystem.h +++ b/include/Support/FileSystem.h @@ -7,10 +7,31 @@ namespace clice { -namespace vfs = llvm::vfs; -namespace fs = llvm::sys::fs; namespace path = llvm::sys::path; +namespace fs { + +using namespace llvm::sys::fs; + +inline std::string resource_dir = ""; + +inline llvm::Error init_resource_dir(llvm::StringRef execute) { + llvm::SmallString<128> path; + path::append(path, path::parent_path(execute), ".."); + path::append(path, "lib", "clang", "20"); + + if(auto error = real_path(path, path)) { + return llvm::make_error(error.message(), error); + } + + resource_dir = path.str(); + return llvm::Error::success(); +} + +} // namespace fs + +namespace vfs = llvm::vfs; + class ThreadSafeFS : public vfs::ProxyFileSystem { public: explicit ThreadSafeFS() : ProxyFileSystem(vfs::createPhysicalFileSystem()) {} diff --git a/src/Compiler/Command.cpp b/src/Compiler/Command.cpp new file mode 100644 index 00000000..6357be3f --- /dev/null +++ b/src/Compiler/Command.cpp @@ -0,0 +1,69 @@ +#include "Compiler/Command.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" + +namespace clice { + +llvm::Error mangleCommand(llvm::StringRef command, + llvm::SmallVectorImpl& out, + llvm::SmallVectorImpl& buffer) { + llvm::SmallString<128> current; + llvm::SmallVector indices; + bool inSingleQuote = false; + bool inDoubleQuote = false; + + for(size_t i = 0; i < command.size(); ++i) { + char c = command[i]; + if(c == ' ' && !inSingleQuote && !inDoubleQuote) { + if(!current.empty()) { + indices.push_back(buffer.size()); + buffer.append(current); + buffer.push_back('\0'); + current.clear(); + } + } else if(c == '\'' && !inDoubleQuote) { + inSingleQuote = !inSingleQuote; + } else if(c == '"' && !inSingleQuote) { + inDoubleQuote = !inDoubleQuote; + } else { + current.push_back(c); + } + } + + if(!current.empty()) { + indices.push_back(buffer.size()); + buffer.append(current); + buffer.push_back('\0'); + } + + /// Add resource directory. + indices.push_back(buffer.size()); + current = std::format("-resource-dir={}", fs::resource_dir); + buffer.append(current); + buffer.push_back('\0'); + + /// FIXME: use better way to remove args. + for(size_t i = 0; i < indices.size(); ++i) { + llvm::StringRef arg(buffer.data() + indices[i]); + + /// Skip `-c` and `-o` arguments. + if(arg == "-c") { + continue; + } + + if(arg.starts_with("-o")) { + if(arg == "-o") { + ++i; + } + continue; + } + + /// TODO: remove PCH. + + out.push_back(arg.data()); + } + + return llvm::Error::success(); +} + +} // namespace clice diff --git a/src/Compiler/Compiler.cpp b/src/Compiler/Compiler.cpp index 2dbb99b9..54fd07db 100644 --- a/src/Compiler/Compiler.cpp +++ b/src/Compiler/Compiler.cpp @@ -1,4 +1,6 @@ +#include #include + #include #include @@ -17,24 +19,32 @@ bool PCHInfo::needUpdate(llvm::StringRef content) { namespace { -void adjustInvocation(clang::CompilerInvocation& invocation) { - auto& frontOpts = invocation.getFrontendOpts(); +auto createInvocation(CompliationParams& params) { + llvm::SmallString<1024> buffer; + llvm::SmallVector args; + + if(auto error = mangleCommand(params.command, args, buffer)) { + std::terminate(); + } + + clang::CreateInvocationOptions options = {}; + options.VFS = params.vfs; + auto invocation = clang::createInvocation(args, options); + + auto& frontOpts = invocation->getFrontendOpts(); frontOpts.DisableFree = false; - clang::LangOptions& langOpts = invocation.getLangOpts(); + clang::LangOptions& langOpts = invocation->getLangOpts(); langOpts.CommentOpts.ParseAllComments = true; langOpts.RetainCommentsFromSystemHeaders = true; - // FIXME: add more. + return invocation; } auto createInstance(CompliationParams& params) { auto instance = std::make_unique(); - /// TODO: Figure out `CreateInvocationOptions`. - clang::CreateInvocationOptions options = {}; - options.VFS = params.vfs; - instance->setInvocation(clang::createInvocation(params.args, options)); + instance->setInvocation(createInvocation(params)); /// TODO: use a thread safe filesystem and our customized `DiagnosticConsumer`. instance->createDiagnostics( @@ -44,8 +54,6 @@ auto createInstance(CompliationParams& params) { instance->createFileManager(params.vfs); - adjustInvocation(instance->getInvocation()); - /// Add remapped files, if bounds is provided, cut off the content. std::size_t size = params.bounds.has_value() ? params.bounds.value().Size : params.content.size(); @@ -140,7 +148,7 @@ void CompliationParams::computeBounds(llvm::StringRef header) { assert(!content.empty() && "Source content is required to compute bounds"); if(header.empty()) { - auto invocation = clang::createInvocation(args, {}); + auto invocation = createInvocation(*this); bounds = clang::Lexer::ComputePreamble(content, invocation->getLangOpts()); return; } diff --git a/src/Server/Command.cpp b/src/Server/Command.cpp index e652c451..ec982285 100644 --- a/src/Server/Command.cpp +++ b/src/Server/Command.cpp @@ -5,45 +5,114 @@ namespace clice { void CommandManager::update(llvm::StringRef dir) { - std::string error; - auto CDB = clang::tooling::CompilationDatabase::loadFromDirectory(dir, error); - if(!CDB) { - log::fatal("Failed to load compilation database from {0}, because {1}", dir, error); + llvm::SmallString<128> path; + path::append(path, dir, "compile_commands.json"); + + auto buffer = llvm::MemoryBuffer::getFile(path); + if(!buffer) { + log::warn("Failed to read compile_commands.json from {}, because {}", + dir, + buffer.getError().message()); return; } - CDBs.try_emplace(dir, std::move(CDB)); - log::info("Successfully loaded compilation database from {0}.", dir); -} + auto json = json::parse(buffer.get()->getBuffer()); + if(!json) { + log::warn("Failed to parse json file at {}, because {}", path, json.takeError()); + return; + } -std::vector CommandManager::lookup(llvm::StringRef file) { - std::vector result; - for(const auto& [dir, CDB]: CDBs) { - auto commands = CDB->getCompileCommands(file); - if(commands.empty()) { + if(!json->getAsArray()) { + log::warn("Invalid JSON format at {}, Compilation Database requires Array, but get {}", + path, + refl::enum_name(json->kind())); + return; + } + + auto& CDB = CDBs[dir]; + + /// Clear old commands. + /// FIXME: it would be better to have cache in some way. + CDB.clear(); + + for(auto& value: *json->getAsArray()) { + auto element = value.getAsObject(); + if(!element) { + log::warn("Invalid JSON format at {}, Compilation Database requires Object, but get {}", + path, + refl::enum_name(value.kind())); continue; } - auto& args = commands[0].CommandLine; - for(auto iter = args.begin(); iter != args.end(); ++iter) { - if(iter->starts_with("-o")) { - iter++; - continue; - } else if(iter->starts_with("-c")) { - continue; - } else if(*iter == "--") { - continue; + /// Source file path. + llvm::SmallString<128> path; + + auto file = element->getString("file"); + if(!file) { + log::warn("the element in {} does not have a file field", + path, + refl::enum_name(value.kind())); + continue; + } + + if(path::is_relative(file.value())) { + auto working = element->getString("directory"); + if(!working) { + log::warn( + "Invalid JSON format at {}, {} is relative path, but directory is not provided", + path, + file.value()); } - result.push_back(std::move(*iter)); + path::append(path, working.value(), file.value()); + } else { + path::append(path, file.value()); } - break; + + /// Command to compile the source file. + llvm::SmallString<1024> rawCommand; + + if(auto command = element->getString("command")) { + rawCommand = command.value(); + } else if(auto arguments = element->getArray("arguments")) { + /// FIXME: + std::terminate(); + } else { + log::warn( + "Invalid JSON format, the element in {} does not have a command or arguments field", + path, + refl::enum_name(value.kind())); + continue; + } + + CDB[path].emplace_back(rawCommand.str()); } - result.push_back("-resource-dir="); - result.back() += config::frontend().resource_dictionary; + log::info("Compilation Database at {} is up-to-date", dir); +} - return result; +llvm::StringRef CommandManager::lookupFirst(llvm::StringRef file) { + for(auto& [dir, cdb]: CDBs) { + auto iter = cdb.find(file); + if(iter != cdb.end()) { + return iter->second.front(); + } + } + + return {}; +} + +llvm::ArrayRef CommandManager::lookup(llvm::StringRef file) { + for(auto& [dir, cdb]: CDBs) { + /// FIXME: currently we directly return the first match. + /// it is better to provide a callback to handle all matches. + auto iter = cdb.find(file); + if(iter != cdb.end()) { + return iter->second; + } + } + + return {}; } } // namespace clice diff --git a/src/Server/Scheduler.cpp b/src/Server/Scheduler.cpp index 0fd60658..8ae1452e 100644 --- a/src/Server/Scheduler.cpp +++ b/src/Server/Scheduler.cpp @@ -6,16 +6,17 @@ namespace clice { async::promise Scheduler::updatePCH(llvm::StringRef filepath, llvm::StringRef content, - llvm::ArrayRef args) { + llvm::StringRef command) { auto [iter, success] = pchs.try_emplace(filepath); if(success || iter->second.needUpdate(content)) { Tracer tracer; CompliationParams params; - params.srcPath = filepath; params.content = content; - params.args = args; + params.srcPath = filepath; params.outPath = filepath; + params.command = command; + path::replace_path_prefix(params.outPath, config::workplace(), config::frontend().cache_directory); @@ -77,32 +78,20 @@ async::promise Scheduler::buildAST(llvm::StringRef filepath, llvm::StringR initCmd = true; } - /// FIXME: lookup from CDB file and adjust and remove unnecessary arguments.1 - auto cmd = cmdMgr.lookup(filepath); - llvm::SmallVector args; - for(auto& arg: cmd) { - args.push_back(arg.c_str()); - } - - /// through arguments to judge is it a module. - bool isModule = false; - co_await (isModule ? updatePCM() : updatePCH(filepath, content, args)); - - Tracer tracer; - - llvm::SmallString<128> command; - llvm::raw_svector_ostream os(command); - for(auto arg: args) { - os << arg << " "; - } - log::info("Start building AST for {0}, command: [{1}]", filepath, command.str()); - CompliationParams params; params.srcPath = path; params.content = content; - params.args = args; + params.command = cmdMgr.lookupFirst(filepath); params.addPCH(pchs.at(filepath)); + /// through arguments to judge is it a module. + bool isModule = false; + co_await (isModule ? updatePCM() : updatePCH(filepath, content, params.command)); + + Tracer tracer; + + log::info("Start building AST for {0}, command: [{1}]", filepath, params.command.str()); + auto task = [&] { /// FIXME: We cannot use reference capture the `pch` here, beacuse the reference may be /// Invalid Because other changed the `pchs` map. We also cannot to retrieve the `pch` from @@ -153,22 +142,15 @@ async::promise Scheduler::codeComplete(llvm::StringRef llvm::SmallString<128> path = filepath; /// FIXME: lookup from CDB file and adjust and remove unnecessary arguments.1 - llvm::SmallVector args = { - "clang++", - "-std=c++20", - path.c_str(), - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; CompliationParams params; - params.srcPath = path; - params.args = args; params.content = iter->second.content; + params.srcPath = path; + params.command = cmdMgr.lookupFirst(filepath); /// through arguments to judge is it a module. bool isModule = false; - co_await (isModule ? updatePCM() : updatePCH(params.srcPath, params.content, args)); + co_await (isModule ? updatePCM() : updatePCH(params.srcPath, params.content, params.command)); params.addPCH(pchs.at(filepath)); Tracer tracer; diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index d4ed5f94..d8b9fa13 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -22,6 +22,12 @@ int Server::run(int argc, const char** argv) { log::info("Successfully loaded configuration file from {0}.", cl::config.getValue()); } + /// Get the resource directory. + if(auto error = fs::init_resource_dir(argv[0])) { + log::fatal("Failed to get resource directory, because {0}", error); + return 1; + } + auto dispatch = [this](json::Value value) -> async::promise { assert(value.kind() == json::Value::Object); auto object = value.getAsObject(); diff --git a/unittests/Compiler/Command.cpp b/unittests/Compiler/Command.cpp index 74aee129..5b2b6274 100644 --- a/unittests/Compiler/Command.cpp +++ b/unittests/Compiler/Command.cpp @@ -1,16 +1,41 @@ #include "../Test.h" -// #include "Compiler/Command.h" -// -// namespace { -// -// TEST(clice, CommandManager) { -// clice::CommandManager manager("/home/ykiko/C++/clice2/tests"); -// auto args = manager.lookup("another_file.cpp"); -// for(auto arg: args) { -// llvm::outs() << arg << " "; -// } -// llvm::outs() << "\n"; -// } -// -// } // namespace +#include "Compiler/Command.h" + +namespace clice { + +namespace { + +TEST(clice, Command) { + llvm::SmallString<1024> buffer; + llvm::SmallVector args; + + auto command = + "/usr/local/bin/clang++" + " -Dclice_core_EXPORTS" + " -I/home/ykiko/C++/clice2/deps/llvm/build-install/include" + " -I/home/ykiko/C++/clice2/include" + " -I/home/ykiko/C++/clice2/deps/toml/include" + " -I/home/ykiko/C++/clice2/deps/libuv/include" + " -fno-rtti" + " -fno-exceptions" + " -g -O0 -fsanitize=address" + " -Wno-deprecated-declarations" + " -g -std=gnu++23 -fPIC -Winvalid-pch" + " -Xclang -include-pch" + " -Xclang /home/ykiko/C++/clice2/build/CMakeFiles/clice-core.dir/cmake_pch.hxx.pch" + " -Xclang -include -Xclang /home/ykiko/C++/clice2/build/CMakeFiles/clice-core.dir/cmake_pch.hxx" + " -o CMakeFiles/clice-core.dir/src/Basic/URI.cpp.o" + " -c /home/ykiko/C++/clice2/src/Basic/URI.cpp"; + + auto error = mangleCommand(command, args, buffer); + ASSERT_FALSE(bool(error)); + + for(auto arg: args) { + llvm::outs() << arg << '\n'; + } +} + +} // namespace + +} // namespace clice diff --git a/unittests/Compiler/Compiler.cpp b/unittests/Compiler/Compiler.cpp index 0a8a198b..3762b069 100644 --- a/unittests/Compiler/Compiler.cpp +++ b/unittests/Compiler/Compiler.cpp @@ -16,33 +16,16 @@ int main(){ } )cpp"; - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - CompliationParams params; - params.srcPath = "main.cpp"; params.content = code; - params.args = compileArgs; + params.srcPath = "main.cpp"; + params.command = "clang++ -std=c++20 main.cpp"; auto info = compile(params); ASSERT_TRUE(bool(info)); } TEST(Compiler, ComputeBounds) { - - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - const char* code = R"cpp( #include int main(){ @@ -52,9 +35,9 @@ int main(){ /// Test in no header file. CompliationParams params; - params.srcPath = "main.cpp"; - params.args = compileArgs; params.content = code; + params.srcPath = "main.cpp"; + params.command = "clang++ -std=c++20 main.cpp"; params.computeBounds(); ASSERT_TRUE(params.bounds.has_value()); @@ -62,8 +45,6 @@ int main(){ params.bounds.reset(); - compileArgs = {"clang++", "-std=c++20", "main.cpp"}; - std::unique_ptr vfs(new vfs::InMemoryFileSystem); const char* header = R"cpp( #include "target.h" @@ -80,14 +61,7 @@ int main(){ return 0; })cpp"; - compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - }; - params.srcPath = "main.cpp"; - params.args = compileArgs; params.content = code; params.vfs = std::move(vfs); params.computeBounds("target.h"); @@ -106,14 +80,6 @@ int main(){ } )cpp"; - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - llvm::SmallString<128> outpath; if(auto error = llvm::sys::fs::createTemporaryFile("main", "pch", outpath)) { llvm::errs() << error.message() << "\n"; @@ -129,7 +95,7 @@ int main(){ params.content = code; params.srcPath = "main.cpp"; params.outPath = outpath; - params.args = compileArgs; + params.command = "clang++ -std=c++20 main.cpp"; params.computeBounds(); PCHInfo pch; @@ -162,17 +128,11 @@ export int foo() { return; } - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cppm", - }; - CompliationParams params; params.srcPath = "main.cppm"; params.content = code; params.outPath = outpath; - params.args = compileArgs; + params.command = "clang++ -std=c++20 main.cppm"; PCMInfo pcm; ASSERT_TRUE(bool(clice::compile(params, pcm))); @@ -189,7 +149,7 @@ int main(){ params.srcPath = "main.cpp"; params.content = code2; - params.args = compileArgs; + params.command = "clang++ -std=c++20 main.cpp"; params.addPCM(pcm); auto info = compile(params); @@ -202,16 +162,10 @@ export module A; export int foo = 1; )cpp"; - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cppm", - }; - CompliationParams params; - params.srcPath = "main.cppm"; params.content = code; - params.args = compileArgs; + params.srcPath = "main.cppm"; + params.command = "clang++ -std=c++20 main.cppm"; params.line = 3; params.column = 10; diff --git a/unittests/Compiler/Resolver.cpp b/unittests/Compiler/Resolver.cpp index 925b30c8..d47f21f5 100644 --- a/unittests/Compiler/Resolver.cpp +++ b/unittests/Compiler/Resolver.cpp @@ -8,24 +8,16 @@ namespace { struct TemplateResolverTester : public clang::RecursiveASTVisitor { TemplateResolverTester(llvm::StringRef code) { - compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - CompliationParams params; - params.srcPath = "main.cpp"; - params.content = code; - params.args = compileArgs; - auto info = compile(params); - if(!info) { - llvm::errs() << info.takeError() << "\n"; - return; - } + // CompliationParams params; + // params.srcPath = "main.cpp"; + // params.content = code; + // params.args = compileArgs; + // auto info = compile(params); + // if(!info) { + // llvm::errs() << info.takeError() << "\n"; + // return; + // } - compiler = std::move(*info); test(); } diff --git a/unittests/Feature/CodeCompletion.cpp b/unittests/Feature/CodeCompletion.cpp index ef4150c1..f2a97154 100644 --- a/unittests/Feature/CodeCompletion.cpp +++ b/unittests/Feature/CodeCompletion.cpp @@ -14,18 +14,10 @@ int main() { } )cpp"; - llvm::SmallVector compileArgs = { - "clang++", - "-std=c++20", - "main.cpp", - "-resource-dir", - "/home/ykiko/C++/clice2/build/lib/clang/20", - }; - CompliationParams params; - params.srcPath = "main.cpp"; params.content = code; - params.args = compileArgs; + params.srcPath = "main.cpp"; + params.content = "clang++ -std=c++20 main.cpp"; auto result = feature::codeCompletion(params, 5, 7, "main.cpp", {}); for(auto& item: result) { diff --git a/unittests/Test.h b/unittests/Test.h index 3d758411..0f7cf011 100644 --- a/unittests/Test.h +++ b/unittests/Test.h @@ -185,15 +185,7 @@ public: Tester& run(const char* standard = "-std=c++20") { params.vfs = std::move(vfs); - - llvm::SmallVector args = { - "clang++", - standard, - params.srcPath.c_str(), - "-resource-dir", - test::resource_dir().data(), - }; - params.args = args; + params.command = std::format("clang++ {} {} main.cpp", standard, params.srcPath); auto info = compile(params); if(!info) { diff --git a/unittests/main.cpp b/unittests/main.cpp index 6f5b2d60..0fe49540 100644 --- a/unittests/main.cpp +++ b/unittests/main.cpp @@ -29,14 +29,16 @@ llvm::StringRef resource_dir() { } // namespace clice int main(int argc, char** argv) { + using namespace clice; + + if(auto error = fs::init_resource_dir(argv[0])) { + llvm::outs() << std::format("Failed to get resource directory, because {}\n", error); + return 1; + } + testing::InitGoogleTest(&argc, argv); llvm::cl::ParseCommandLineOptions(argc, argv, "clice test\n"); - if(auto error = clice::fs::real_path(llvm::Twine(argv[0]) + "/../../lib/clang/20)", - clice::cl::resource_dir)) { - llvm::errs() << "Failed to get resource directory, because " << error.message() << '\n'; - } - return RUN_ALL_TESTS(); }