Skip to content

Commit

Permalink
refactor: modular cmake functions
Browse files Browse the repository at this point in the history
  • Loading branch information
alandefreitas committed Jan 23, 2024
1 parent 59681e8 commit f53685e
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 73 deletions.
88 changes: 49 additions & 39 deletions src/lib/Lib/CMakeExecution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -195,49 +195,34 @@ parseCmakeArgs(std::string const& cmakeArgsStr) {
return args;
}

} // anonymous namespace

Expected<std::string>
executeCmakeExportCompileCommands(llvm::StringRef projectPath, llvm::StringRef cmakeArgs)
{
MRDOCS_CHECK(llvm::sys::fs::exists(projectPath), "Project path does not exist");
MRDOCS_TRY(auto const cmakePath, getCmakePath());

llvm::SmallString<128> tempDir;
MRDOCS_CHECK(!llvm::sys::fs::createUniqueDirectory("compile_commands", tempDir), "Failed to create temporary directory");

llvm::SmallString<128> errorPath;
MRDOCS_CHECK(!llvm::sys::fs::createTemporaryFile("cmake-error", "txt", errorPath),
"Failed to create temporary file");

std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), llvm::StringRef(), errorPath.str()};
std::vector<llvm::StringRef> args = {cmakePath, "-S", projectPath, "-B", tempDir.str(), "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"};

auto const additionalArgs = parseCmakeArgs(cmakeArgs.str());

Expected<void>
pushCMakeArgs(
std::string const& cmakePath,
std::vector<llvm::StringRef> &args,
std::vector<std::string> const& additionalArgs) {
bool visualStudioFound = false;
for (size_t i = 0; i < additionalArgs.size(); ++i)
for (size_t i = 0; i < additionalArgs.size(); ++i)
{
auto const& arg = additionalArgs[i];
if (arg.starts_with("-G"))
{
if (arg.size() == 2)
if (arg.size() == 2)
{
if (i + 1 < additionalArgs.size())
if (i + 1 < additionalArgs.size())
{
auto const& generatorName = additionalArgs[i + 1];
if (generatorName.starts_with("Visual Studio"))
if (generatorName.starts_with("Visual Studio"))
{
args.push_back("-GNinja");
args.emplace_back("-GNinja");
visualStudioFound = true;
++i;
continue;
}
}
} else {
if (arg.find("Visual Studio", 2) != std::string::npos)
if (arg.find("Visual Studio", 2) != std::string::npos)
{
args.push_back("-GNinja");
args.emplace_back("-GNinja");
visualStudioFound = true;
continue;
}
Expand All @@ -246,39 +231,63 @@ executeCmakeExportCompileCommands(llvm::StringRef projectPath, llvm::StringRef c

if (arg.starts_with("-D"))
{
if (arg.size() == 2)
if (arg.size() == 2)
{
if (i + 1 < additionalArgs.size())
if (i + 1 < additionalArgs.size())
{
auto const& optionName = additionalArgs[i + 1];
if (optionName.starts_with("CMAKE_EXPORT_COMPILE_COMMANDS"))
if (optionName.starts_with("CMAKE_EXPORT_COMPILE_COMMANDS"))
{
++i;
continue;
}
}
} else {
if (arg.find("CMAKE_EXPORT_COMPILE_COMMANDS", 2) != std::string::npos)
if (arg.find("CMAKE_EXPORT_COMPILE_COMMANDS", 2) != std::string::npos)
{
continue;
}
}
}
args.push_back(arg);
}
args.emplace_back(arg);
}
if ( ! visualStudioFound)

if (!visualStudioFound)
{
MRDOCS_TRY(auto const cmakeDefaultGeneratorIsVisualStudio, cmakeDefaultGeneratorIsVisualStudio(cmakePath));
if (cmakeDefaultGeneratorIsVisualStudio)
MRDOCS_TRY(
bool const cmakeDefaultGeneratorIsVisualStudio,
cmakeDefaultGeneratorIsVisualStudio(cmakePath));
if (cmakeDefaultGeneratorIsVisualStudio)
{
args.push_back("-GNinja");
args.emplace_back("-GNinja");
}
}
return {};
}

} // anonymous namespace

Expected<std::string>
executeCmakeExportCompileCommands(llvm::StringRef projectPath, llvm::StringRef cmakeArgs)
{
MRDOCS_CHECK(llvm::sys::fs::exists(projectPath), "Project path does not exist");
MRDOCS_TRY(auto const cmakePath, getCmakePath());

llvm::SmallString<128> tempDir;
MRDOCS_CHECK(!llvm::sys::fs::createUniqueDirectory("compile_commands", tempDir), "Failed to create temporary directory");

ScopedTempFile const errorPath("cmake-error", "txt");
MRDOCS_CHECK(errorPath, "Failed to create temporary file");

std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), llvm::StringRef(), errorPath.path()};
std::vector<llvm::StringRef> args = {cmakePath, "-S", projectPath, "-B", tempDir.str(), "-DCMAKE_EXPORT_COMPILE_COMMANDS=ON"};

auto const additionalArgs = parseCmakeArgs(cmakeArgs.str());
MRDOCS_TRY(pushCMakeArgs(cmakePath, args, additionalArgs));

int const result = llvm::sys::ExecuteAndWait(cmakePath, args, std::nullopt, redirects);
if (result != 0) {
auto bufferOrError = llvm::MemoryBuffer::getFile(errorPath);
auto bufferOrError = llvm::MemoryBuffer::getFile(errorPath.path());
MRDOCS_CHECK(bufferOrError, "CMake execution failed (no error output available)");
return Unexpected(Error("CMake execution failed: \n" + bufferOrError.get()->getBuffer().str()));
}
Expand All @@ -289,5 +298,6 @@ executeCmakeExportCompileCommands(llvm::StringRef projectPath, llvm::StringRef c
return compileCommandsPath.str().str();
}


} // mrdocs
} // clang
24 changes: 15 additions & 9 deletions src/tool/CompilerInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ namespace mrdocs {
std::optional<std::string>
getCompilerVerboseOutput(llvm::StringRef compilerPath)
{
if ( ! llvm::sys::fs::exists(compilerPath)) {
if ( ! llvm::sys::fs::exists(compilerPath))
{
return std::nullopt;
}

Expand All @@ -43,7 +44,7 @@ getCompilerVerboseOutput(llvm::StringRef compilerPath)

auto bufferOrError = llvm::MemoryBuffer::getFile(outputPath);
llvm::sys::fs::remove(outputPath);
if ( ! bufferOrError)
if (!bufferOrError)
{
return std::nullopt;
}
Expand Down Expand Up @@ -86,20 +87,25 @@ getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb)
std::unordered_map<std::string, std::vector<std::string>> res;
auto const allCommands = compDb.getAllCompileCommands();

for (auto const& cmd : allCommands) {
if ( ! cmd.CommandLine.empty()) {
for (auto const& cmd : allCommands)
{
if (!cmd.CommandLine.empty())
{
auto const& compilerPath = cmd.CommandLine[0];
if (res.contains(compilerPath)) {
if (res.contains(compilerPath))
{
continue;
}

std::vector<std::string> includePaths;
auto const compilerOutput = getCompilerVerboseOutput(compilerPath);
if ( ! compilerOutput) {
report::warn("Warning: could not get compiler info for \"{}\"", compilerPath);
if (!compilerOutput)
{
res.emplace(compilerPath, includePaths);
continue;
}
std::vector<std::string> includePaths = parseIncludePaths(*compilerOutput);
res.emplace(compilerPath, std::move(includePaths));
includePaths = parseIncludePaths(*compilerOutput);
res.emplace(compilerPath, std::move(includePaths));
}
}

Expand Down
71 changes: 46 additions & 25 deletions src/tool/GenerateAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,21 +51,31 @@ generateCompileCommandsFile(llvm::StringRef projectPath, llvm::StringRef cmakeAr
fs::file_status fileStatus;
MRDOCS_CHECK(!fs::status(projectPath, fileStatus), "Failed to get file status");

// --------------------------------------------------------------
// Input path is a project directory
// --------------------------------------------------------------
if (fs::is_directory(fileStatus))
{
return executeCmakeExportCompileCommands(projectPath, cmakeArgs);
}


// --------------------------------------------------------------
// Input path is a CMakeLists.txt
// --------------------------------------------------------------
auto const fileName = files::getFileName(projectPath);
if (fileName == "CMakeLists.txt")
{
return executeCmakeExportCompileCommands(files::getParentDir(projectPath), cmakeArgs);
}

// --------------------------------------------------------------
// Input path is a compile_commands.json
// --------------------------------------------------------------
if (fileName == "compile_commands.json")
{
return projectPath.str();
}

if (fileName == "CMakeLists.txt")
{
return executeCmakeExportCompileCommands(files::getParentDir(projectPath), cmakeArgs);
}

return projectPath.str();
}

Expand Down Expand Up @@ -94,12 +104,14 @@ DoGenerateAction()
ThreadPool threadPool(toolArgs.concurrency);
{
MRDOCS_CHECK(toolArgs.configPath, "The config path argument is missing");
MRDOCS_TRY(auto configFile, loadConfigFile(
toolArgs.configPath,
toolArgs.addonsDir,
extraYaml,
nullptr,
threadPool));
MRDOCS_TRY(
std::shared_ptr<ConfigImpl const> configFile,
loadConfigFile(
toolArgs.configPath,
toolArgs.addonsDir,
extraYaml,
nullptr,
threadPool));
config = std::move(configFile);
}

Expand All @@ -117,33 +129,39 @@ DoGenerateAction()

// --------------------------------------------------------------
//
// Load the compilation database file
// Generate compile_commands.json
//
// --------------------------------------------------------------

MRDOCS_CHECK(toolArgs.inputPaths, "The compilation database path argument is missing");
MRDOCS_CHECK(toolArgs.inputPaths.size() == 1,
formatError(
"got {} input paths where 1 was expected",
toolArgs.inputPaths.size()));


std::string_view cmakeArgs = config->object().exists("cmake") ?
config->object().get("cmake").getString() : "";
auto const inputPath = generateCompileCommandsFile(toolArgs.inputPaths.front(), cmakeArgs);
if ( ! inputPath)
Expected<std::string> const compileCommandsPathExp =
generateCompileCommandsFile(toolArgs.inputPaths.front(), cmakeArgs);
if (!compileCommandsPathExp)
{
report::error("Failed to generate compile_commands.json file: {}", inputPath.error());
return {};
report::error(
"Failed to generate compile_commands.json file: {}",
compileCommandsPathExp.error());
return Unexpected(compileCommandsPathExp.error());
}

auto compilationsPath = files::normalizePath(*inputPath);
MRDOCS_TRY(compilationsPath, files::makeAbsolute(compilationsPath));
// --------------------------------------------------------------
//
// Load the compilation database file
//
// --------------------------------------------------------------
std::string compileCommandsPath = files::normalizePath(*compileCommandsPathExp);
MRDOCS_TRY(compileCommandsPath, files::makeAbsolute(compileCommandsPath));
std::string errorMessage;
MRDOCS_TRY_MSG(
auto& compileCommands,
tooling::JSONCompilationDatabase::loadFromFile(
compilationsPath,
compileCommandsPath,
errorMessage,
tooling::JSONCommandLineSyntax::AutoDetect),
std::move(errorMessage));
Expand All @@ -152,9 +170,12 @@ DoGenerateAction()
auto const defaultIncludePaths = getCompilersDefaultIncludeDir(compileCommands);

// Custom compilation database that converts relative paths to absolute
auto compileCommandsDir = files::getParentDir(compilationsPath);
auto compileCommandsDir = files::getParentDir(compileCommandsPath);
MRDOCS_ASSERT(files::isDirsy(compileCommandsDir));
MrDocsCompilationDatabase compilationDatabase(
compileCommandsDir, compileCommands, config, defaultIncludePaths);
compileCommandsDir,
compileCommands, config,
defaultIncludePaths);

// Normalize outputPath path
MRDOCS_CHECK(toolArgs.outputPath, "The output path argument is missing");
Expand All @@ -172,7 +193,7 @@ DoGenerateAction()
CorpusImpl::build(
report::Level::info, config, compilationDatabase));

if(corpus->empty())
if (corpus->empty())
{
report::warn("Corpus is empty, not generating docs");
return {};
Expand Down

0 comments on commit f53685e

Please sign in to comment.