|
5 | 5 | #include "clang/Tooling/CommonOptionsParser.h" |
6 | 6 | #include "clang/Basic/Version.h" |
7 | 7 |
|
| 8 | +#include "clu/custom_compilation_database.hpp" |
8 | 9 | #include "clu/cmd_line_arg.hpp" |
9 | 10 | #include "utility/macros.hpp" |
10 | 11 | #include "utility/logger.hpp" |
@@ -81,9 +82,60 @@ int main(int argc, const char **argv) try { |
81 | 82 | config = read_configuration(config_filename); |
82 | 83 | config._depfile_name = opt_depfile; |
83 | 84 |
|
84 | | - // ------- main tool |
| 85 | + // --- Correct the compilation database |
| 86 | + // Enforce that the compiler for source0 is the clang compiler used in compiling clair itself. |
| 87 | + // This a ABSOLUTELY necessary to ensure clair sees the system paths, has the right -resource-dir. |
| 88 | + // It is useful in at least 2 cases: |
| 89 | + // - call with -- options: the default "compiler" would be "clang-tool", and if the system path are not standard (i.e. in most cluster machine) |
| 90 | + // it would fail. |
| 91 | + // - when developing with another compiler, e.g. gcc. |
| 92 | + |
| 93 | + auto ¤t_compdb = opt_parser->getCompilations(); |
| 94 | + auto all_compile_cmds = current_compdb.getAllCompileCommands(); |
| 95 | + // WARNING: Database behavior depends on the type of the compilation database: |
| 96 | + // - JSONCompilationDatabase (from compile_commands.json): getAllCompileCommands() returns all entries |
| 97 | + // - FixedCompilationDatabase (from -- arguments) : getAllCompileCommands() returns empty always |
| 98 | + // it can generate commands for any file on-demand via getCompileCommands(filename), so there's no finite "all" to return. |
| 99 | + // This seems to be a long-standing LLVM design choice [Cf Claude 4.5]. |
| 100 | + // If future LLVM versions change this behavior, adjust the logic below accordingly. |
| 101 | + bool using_fixed_db = all_compile_cmds.empty(); |
| 102 | + if (using_fixed_db) { |
| 103 | + llvm::errs() << "Calling with --. Getting compile commands for source file.\n"; |
| 104 | + all_compile_cmds = current_compdb.getCompileCommands(source0); |
| 105 | + if (all_compile_cmds.empty()) |
| 106 | + throw std::runtime_error("Internal Error: no compilation commands found or for " + source0 + "\n and none could be generated."); |
| 107 | + } |
| 108 | + |
| 109 | + // Now fix the compiler for the compile command corresponding to source0. |
| 110 | + // Use canonical for comparison (to handle symlinks), but absolute for storage (ClangTool doesn't follow symlinks). |
| 111 | + auto canonical_source0 = fs::canonical(source0).string(); |
| 112 | + for (auto &cmd : all_compile_cmds) { |
| 113 | + if (fs::canonical(cmd.Filename).string() == canonical_source0) { |
| 114 | + if (cmd.CommandLine.empty()) throw std::runtime_error("CompileCommand has empty CommandLine for " + source0); |
| 115 | + auto expected_compiler = clu::get_clang_compiler_path(); |
| 116 | + if (cmd.CommandLine[0] != expected_compiler) { |
| 117 | + if (opt_verbose) |
| 118 | + llvm::errs() << "Warning: clair-c2py. When analyzing source file " << source0 << ", replacing compiler \n" |
| 119 | + << cmd.CommandLine[0] << "\n with \n" |
| 120 | + << expected_compiler << "\n"; |
| 121 | + cmd.CommandLine[0] = expected_compiler; |
| 122 | + } |
| 123 | + // For FixedCompilationDatabase: update Filename to canonical path. |
| 124 | + // For JSONCompilationDatabase: do nothing |
| 125 | + if (using_fixed_db) { |
| 126 | + cmd.Filename = canonical_source0; |
| 127 | + source0 = canonical_source0; |
| 128 | + } |
| 129 | + break; // we found and fixed the command for source0. we are done. |
| 130 | + } |
| 131 | + } |
| 132 | + // Finally we construct a custom compilation database with the fixed commands |
| 133 | + auto custom_db = clu::custom_compilation_database(all_compile_cmds); |
85 | 134 |
|
86 | | - clang::tooling::ClangTool main_tool(opt_parser->getCompilations(), opt_parser->getSourcePathList()); |
| 135 | + // ------- main tool |
| 136 | + // For FixedCompilationDatabase, pass canonical path to ClangTool to match what's in the database |
| 137 | + //auto source_for_tool = using_fixed_db ? canonical_source0 : source0; |
| 138 | + clang::tooling::ClangTool main_tool(custom_db, {source0}); // we use the fixed compilation database |
87 | 139 |
|
88 | 140 | // Additional Command line arguments to be given to the compiler, after all other options |
89 | 141 | // from e.g. CXXFLAGS and co, and the -resource-dir. |
|
0 commit comments