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

feat: Use compiler default include paths #515

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 1 addition & 13 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -325,19 +325,7 @@ jobs:
rm -rf __build__
fi
mkdir __build__
cd __build__
mkdir __include_dirs__
cd __include_dirs__
output_file="include_dirs.txt"
echo "cmake_minimum_required(VERSION 3.22)" > CMakeLists.txt
echo "project(get_implicit_dirs)" >> CMakeLists.txt
echo "file(WRITE \"${output_file}\" \"\${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}\")" >> CMakeLists.txt
mkdir __build__
cd __build__
cmake -D CMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx }} -D CMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc }} ..
cd ..
default_includes=$(cat "$output_file")
cd ..
cd __build__
cmake -D BOOST_URL_BUILD_TESTS=OFF -D BOOST_URL_BUILD_EXAMPLES=OFF -D CMAKE_EXPORT_COMPILE_COMMANDS=ON -D CMAKE_CXX_STANDARD_INCLUDE_DIRECTORIES="$default_includes" -D CMAKE_CXX_COMPILER=${{ steps.setup-cpp.outputs.cxx }} -D CMAKE_C_COMPILER=${{ steps.setup-cpp.outputs.cc }} ..

- name: Generate demos
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "lib/Support/Debug.hpp"
#include "lib/Support/Path.hpp"
#include "lib/Lib/ConfigImpl.hpp"
#include "lib/Lib/AbsoluteCompilationDatabase.hpp"
#include "lib/Lib/MrDocsCompilationDatabase.hpp"
#include <fmt/format.h>
#include <clang/Basic/LangStandard.h>
#include <clang/Driver/Driver.h>
Expand Down Expand Up @@ -51,14 +51,20 @@ static
std::vector<std::string>
adjustCommandLine(
const std::vector<std::string>& cmdline,
const std::vector<std::string>& additional_defines)
const std::vector<std::string>& additional_defines,
std::unordered_map<std::string, std::vector<std::string>> const& implicitIncludeDirectories)
{
std::vector<std::string> new_cmdline;
std::vector<std::string> discarded_cmdline;
llvm::opt::InputArgList args;
StringRef driver_mode;
std::vector<std::string> systemIncludePaths;

if(! cmdline.empty())
{
if (auto it = implicitIncludeDirectories.find(cmdline[0]); it != implicitIncludeDirectories.end()) {
systemIncludePaths = it->second;
}

std::vector<const char*> raw_cmdline;
raw_cmdline.reserve(cmdline.size());
for(const auto& s : cmdline)
Expand All @@ -85,6 +91,9 @@ adjustCommandLine(
for(const auto& def : additional_defines)
new_cmdline.emplace_back(fmt::format("-D{}", def));

for (auto const& inc : systemIncludePaths)
new_cmdline.emplace_back(fmt::format("-I{}", inc));

for(unsigned idx = 1; idx < cmdline.size();)
{
const unsigned old_idx = idx;
Expand All @@ -93,10 +102,6 @@ adjustCommandLine(

if(! arg)
{
discarded_cmdline.insert(
discarded_cmdline.end(),
cmdline.begin() + old_idx,
cmdline.begin() + idx);
continue;
}

Expand Down Expand Up @@ -148,10 +153,6 @@ adjustCommandLine(
// driver::options::OPT__SLASH_Tc
))
{
discarded_cmdline.insert(
discarded_cmdline.end(),
cmdline.begin() + old_idx,
cmdline.begin() + idx);
continue;
}

Expand All @@ -164,11 +165,12 @@ adjustCommandLine(
return new_cmdline;
}

AbsoluteCompilationDatabase::
AbsoluteCompilationDatabase(
MrDocsCompilationDatabase::
MrDocsCompilationDatabase(
llvm::StringRef workingDir,
CompilationDatabase const& inner,
std::shared_ptr<const Config> config)
std::shared_ptr<const Config> config,
std::unordered_map<std::string, std::vector<std::string>> const& implicitIncludeDirectories)
{
namespace fs = llvm::sys::fs;
namespace path = llvm::sys::path;
Expand All @@ -187,7 +189,8 @@ AbsoluteCompilationDatabase(
cmd.Output = cmd0.Output;
cmd.CommandLine = adjustCommandLine(
cmd0.CommandLine,
(*config_impl)->defines);
(*config_impl)->defines,
implicitIncludeDirectories);

if(path::is_absolute(cmd0.Directory))
{
Expand Down Expand Up @@ -227,7 +230,7 @@ AbsoluteCompilationDatabase(
}

std::vector<tooling::CompileCommand>
AbsoluteCompilationDatabase::
MrDocsCompilationDatabase::
getCompileCommands(
llvm::StringRef FilePath) const
{
Expand All @@ -243,7 +246,7 @@ getCompileCommands(
}

std::vector<std::string>
AbsoluteCompilationDatabase::
MrDocsCompilationDatabase::
getAllFiles() const
{
std::vector<std::string> allFiles;
Expand All @@ -254,7 +257,7 @@ getAllFiles() const
}

std::vector<tooling::CompileCommand>
AbsoluteCompilationDatabase::
MrDocsCompilationDatabase::
getAllCompileCommands() const
{
return AllCommands_;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
// Official repository: https://github.com/cppalliance/mrdocs
//

#ifndef MRDOCS_LIB_TOOL_ABSOLUTECOMPILATIONDATABASE_HPP
#define MRDOCS_LIB_TOOL_ABSOLUTECOMPILATIONDATABASE_HPP
#ifndef MRDOCS_LIB_TOOL_MR_DOCS_COMPILATION_DATABASE_HPP
#define MRDOCS_LIB_TOOL_MR_DOCS_COMPILATION_DATABASE_HPP

#include <mrdocs/Config.hpp>
#include <clang/Tooling/JSONCompilationDatabase.h>
Expand All @@ -26,24 +26,32 @@ namespace mrdocs {
them according to the working directory specified
at construction.
*/
class AbsoluteCompilationDatabase
class MrDocsCompilationDatabase
: public tooling::CompilationDatabase
{
std::vector<tooling::CompileCommand> AllCommands_;
llvm::StringMap<std::size_t> IndexByFile_;

public:
/** Constructor.

This copies the contents of the source compilation
database. Every relative path is converted into an
absolute path by resolving against the specified
working directory.
*/
AbsoluteCompilationDatabase(
/**
* Constructor.
*
* This copies the contents of the source compilation
* database. Every relative path is converted into an
* absolute path by resolving against the specified
* working directory.
*
* @param workingDir The working directory against which relative paths will be resolved.
* @param inner The source compilation database to copy.
* @param config The shared configuration object.
* @param implicitIncludeDirectories A map from compiler executable paths to their respective
* implicit include directories, as determined by the system's compiler.
*/
MrDocsCompilationDatabase(
llvm::StringRef workingDir,
CompilationDatabase const& inner,
std::shared_ptr<const Config> config);
std::shared_ptr<const Config> config,
std::unordered_map<std::string, std::vector<std::string>> const& implicitIncludeDirectories);

std::vector<tooling::CompileCommand>
getCompileCommands(
Expand All @@ -59,5 +67,5 @@ class AbsoluteCompilationDatabase
} // mrdocs
} // clang

#endif
#endif // MRDOCS_LIB_TOOL_MR_DOCS_COMPILATION_DATABASE_HPP

9 changes: 6 additions & 3 deletions src/test/TestRunner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
#include "TestArgs.hpp"
#include "lib/Support/Error.hpp"
#include "lib/Support/Path.hpp"
#include "lib/Lib/AbsoluteCompilationDatabase.hpp"
#include "lib/Lib/ConfigImpl.hpp"
#include "lib/Lib/CorpusImpl.hpp"
#include "lib/Lib/MrDocsCompilationDatabase.hpp"
#include "lib/Lib/SingleFileDB.hpp"
#include <mrdocs/Config.hpp>
#include <mrdocs/Generators.hpp>
Expand Down Expand Up @@ -105,9 +105,12 @@ handleFile(
path::replace_extension(expectedPath, xmlGen_->fileExtension());

auto workingDir = files::getParentDir(filePath);

std::unordered_map<std::string, std::vector<std::string>> defaultIncludePaths;

// Convert relative paths to absolute
AbsoluteCompilationDatabase compilations(
llvm::StringRef(workingDir), SingleFileDB(filePath), config);
MrDocsCompilationDatabase compilations(
llvm::StringRef(workingDir), SingleFileDB(filePath), config, defaultIncludePaths);
// Build Corpus
auto corpus = CorpusImpl::build(
report::Level::debug, config, compilations);
Expand Down
110 changes: 110 additions & 0 deletions src/tool/CompilerInfo.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
//
// This is a derivative work. originally part of the LLVM Project.
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (c) 2023 Vinnie Falco ([email protected])
//
// Official repository: https://github.com/cppalliance/mrdocs
//

#include "CompilerInfo.hpp"

#include <mrdocs/Support/Error.hpp>

#include <llvm/Support/Program.h>

namespace clang {
namespace mrdocs {

std::optional<std::string>
getCompilerVerboseOutput(llvm::StringRef compilerPath)
{
if ( ! llvm::sys::fs::exists(compilerPath)) {
return std::nullopt;
}

llvm::SmallString<128> outputPath;
if (auto ec = llvm::sys::fs::createTemporaryFile("compiler-info", "txt", outputPath))
{
return std::nullopt;
}

std::optional<llvm::StringRef> const redirects[] = {llvm::StringRef(), llvm::StringRef(), outputPath.str()};
std::vector<llvm::StringRef> const args = {compilerPath, "-v", "-E", "-x", "c++", "-"};
llvm::ArrayRef<llvm::StringRef> emptyEnv;
int const result = llvm::sys::ExecuteAndWait(compilerPath, args, emptyEnv, redirects);
if (result != 0)
{
llvm::sys::fs::remove(outputPath);
return std::nullopt;
}

auto bufferOrError = llvm::MemoryBuffer::getFile(outputPath);
llvm::sys::fs::remove(outputPath);
if ( ! bufferOrError)
{
return std::nullopt;
}

return bufferOrError.get()->getBuffer().str();
}

std::vector<std::string>
parseIncludePaths(std::string const& compilerOutput)
{
std::vector<std::string> includePaths;
std::istringstream stream(compilerOutput);
std::string line;
bool capture = false;

while (std::getline(stream, line))
{
if (line.find("#include <...> search starts here:") != std::string::npos)
{
capture = true;
continue;
}
if (line.find("End of search list.") != std::string::npos)
{
break;
}
if (capture)
{
line.erase(0, line.find_first_not_of(" "));
includePaths.push_back(line);
}
}

return includePaths;
}

std::unordered_map<std::string, std::vector<std::string>>
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()) {
auto const& compilerPath = cmd.CommandLine[0];
if (res.contains(compilerPath)) {
continue;
}

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

return res;
}

} // mrdocs
} // clang
55 changes: 55 additions & 0 deletions src/tool/CompilerInfo.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
// Copyright (c) 2023 Vinnie Falco ([email protected])
//
// Official repository: https://github.com/cppalliance/mrdocs
//

#ifndef MRDOCS_TOOL_COMPILER_HPP
#define MRDOCS_TOOL_COMPILER_HPP

#include <optional>
#include <string>
#include <vector>
#include <unordered_map>

#include <clang/Tooling/CompilationDatabase.h>
#include <llvm/ADT/StringRef.h>

namespace clang {
namespace mrdocs {

/**
* @brief Get the compiler verbose output.
*
* @param compilerPath The compiler path.
* @return std::optional<std::string> The compiler verbose output.
*/
std::optional<std::string>
getCompilerVerboseOutput(llvm::StringRef compilerPath);

/**
* @brief Parse the include paths.
*
* @param compilerOutput The compiler output.
* @return std::vector<std::string> The include paths.
*/
std::vector<std::string>
parseIncludePaths(std::string const& compilerOutput);

/**
* @brief Get the compiler default include dir.
*
* @param compDb The compilation database.
* @return std::unordered_map<std::string, std::vector<std::string>> The compiler default include dir.
*/
std::unordered_map<std::string, std::vector<std::string>>
getCompilersDefaultIncludeDir(clang::tooling::CompilationDatabase const& compDb);

} // mrdocs
} // clang

#endif
Loading
Loading