Skip to content

Commit

Permalink
Support for detecting if compiler and resource files are available
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Beer <dbeer1@bloomberg.net>
  • Loading branch information
dbeer1 authored and ruoso committed Jul 22, 2019
1 parent 9d0a1b6 commit b93f82f
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 2 deletions.
3 changes: 2 additions & 1 deletion .travis.clang7.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ WORKDIR clangmetatool
# Build tool, run tests, and do a test install
RUN mkdir build && cd build && \
cmake -DClang_DIR=/usr/share/llvm-7/cmake .. && \
make all test && \
make all && \
ctest --output-on-failure && \
make install && \
cd .. && rm -rf build

Expand Down
3 changes: 2 additions & 1 deletion .travis.clang8.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,8 @@ WORKDIR clangmetatool
# Build tool, run tests, and do a test install
RUN mkdir build && cd build && \
cmake -DClang_DIR=/usr/share/llvm-8/cmake .. && \
make all test && \
make all && \
ctest --output-on-failure && \
make install && \
cd .. && rm -rf build

Expand Down
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ file(RELATIVE_PATH CLANG_CMAKE_RELATIVE_DIR ${CMAKE_INSTALL_PREFIX}
add_library(
clangmetatool

src/tool_application_support.cpp

src/collectors/definitions.cpp
src/collectors/find_calls.cpp
src/collectors/find_cxx_member_calls.cpp
Expand Down
45 changes: 45 additions & 0 deletions include/clangmetatool/tool_application_support.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef INCLUDED_CLANGMETATOOL_MAIN_SUPPORT_H
#define INCLUDED_CLANGMETATOOL_MAIN_SUPPORT_H

#include <clang/Tooling/CompilationDatabase.h>

#include <string>
#include <vector>

namespace clangmetatool {

/**
* Functions and utilities to support clangmetatool-based applications.
*/
struct ToolApplicationSupport {
/**
* Using the given compilations and source list (as can be obtained from a
* tooling::CommonOptionsParser), check that the toolchain needed to start
* clang is installed, and that this clang-based application has been
* installed along with the required resource files. If the installation is
* broken, report a fatal error and exit.
*/
static void
verifyInstallation(const clang::tooling::CompilationDatabase &compilations,
const std::vector<std::string> &sourcePathList);
};

} // namespace clangmetatool

#endif

// ----------------------------------------------------------------------------
// Copyright 2019 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
117 changes: 117 additions & 0 deletions src/tool_application_support.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include <clangmetatool/tool_application_support.h>

#include <clang/Basic/Diagnostic.h>
#include <clang/Driver/Compilation.h>
#include <clang/Driver/Driver.h>
#include <clang/Driver/ToolChain.h>
#include <llvm/ADT/SmallVector.h>
#include <llvm/Option/Option.h>
#include <llvm/Support/ErrorHandling.h>
#include <llvm/Support/FileSystem.h>
#include <llvm/Support/Host.h>
#include <llvm/Support/Path.h>

#include <llvm/Config/llvm-config.h>
#if LLVM_VERSION_MAJOR >= 8
#include <llvm/Support/VirtualFileSystem.h>
#else
#include <clang/Basic/VirtualFileSystem.h>
#endif

#include <cstring>
#include <memory>
#include <sstream>

namespace clangmetatool {

void ToolApplicationSupport::verifyInstallation(
const clang::tooling::CompilationDatabase &compilations,
const std::vector<std::string> &sourcePathList) {
clang::DiagnosticsEngine diagnostics(new clang::DiagnosticIDs,
new clang::DiagnosticOptions,
new clang::IgnoringDiagConsumer);

// Check each compile command, each may have different settings for toolchain
// and resource directory.

for (const auto &source : sourcePathList) {
for (const auto &command : compilations.getCompileCommands(source)) {
std::vector<std::string> args = command.CommandLine;

// Create a driver and toolchain to verify

clang::driver::Driver driver(args[0], llvm::sys::getDefaultTargetTriple(),
diagnostics);

std::vector<const char *> argsArray;
for (const auto &arg : args) {
argsArray.push_back(arg.c_str());
}

std::unique_ptr<clang::driver::Compilation> compilation(
driver.BuildCompilation(llvm::makeArrayRef(argsArray)));

const clang::driver::ToolChain &toolChain =
compilation->getDefaultToolChain();

// Check that we can find C++ includes using the toolchain

llvm::opt::InputArgList inputArgs;
llvm::opt::ArgStringList cxxIncludes;
toolChain.AddClangCXXStdlibIncludeArgs(inputArgs, cxxIncludes);

bool found = false;
for (const auto &include : cxxIncludes) {
// Skip options

if (include[0] == '-') {
continue;
}

// Check if a sample C++ header can be found at this path

llvm::SmallVector<char, 128> path(include,
include + std::strlen(include));
llvm::sys::path::append(path, "iostream");
if (llvm::sys::fs::exists(path)) {
found = true;
break;
}
}

if (!found) {
std::ostringstream os;
os << "clang could not find a C++ toolchain to use, check that the "
<< "compiler used to configure clang is installed";
llvm::report_fatal_error(os.str().c_str(), false);
}

// Check that the configured resource directory exists

if (!llvm::sys::fs::exists(driver.ResourceDir)) {
std::ostringstream os;
os << "clang resource files are missing from " << driver.ResourceDir
<< ", check that this application is installed properly";
llvm::report_fatal_error(os.str().c_str(), false);
}
}
}
}

} // namespace clangmetatool

// ----------------------------------------------------------------------------
// Copyright 2019 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
117 changes: 117 additions & 0 deletions t/029-tool-application-support.t.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include "clangmetatool-testconfig.h"

#include <gtest/gtest.h>

#include <clangmetatool/tool_application_support.h>

#include <clang/Tooling/CommonOptionsParser.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/ErrorHandling.h>

#include <string>
#include <queue>

class LLVMFatalError : public std::runtime_error {
public:
LLVMFatalError(const std::string& reason)
: std::runtime_error(reason)
{
}
};

struct ToolApplicationSupportTest : public ::testing::Test {
public:
static void fatalErrorHandler(void *,
const std::string& reason,
bool generateCrashDiagnostic)
{
throw LLVMFatalError(reason);
}

ToolApplicationSupportTest()
{
llvm::install_fatal_error_handler(&fatalErrorHandler, 0);
}

~ToolApplicationSupportTest()
{
llvm::remove_fatal_error_handler();
}

std::string verifyInstallation(const std::vector<std::string>& arguments)
{
try {
llvm::cl::OptionCategory category("test");

std::vector<const char*> argumentPtrs;
for (const auto& item : arguments) {
argumentPtrs.push_back(item.c_str());
}

int argc = argumentPtrs.size();
const char** argv = argumentPtrs.data();
clang::tooling::CommonOptionsParser parser(argc, argv, category);

clangmetatool::ToolApplicationSupport::verifyInstallation(
parser.getCompilations(),
parser.getSourcePathList());
}
catch(const LLVMFatalError& e) {
return e.what();
}

return std::string();
}
};

TEST_F(ToolApplicationSupportTest, resource_dir)
{
EXPECT_EQ("", verifyInstallation({"tool", "test.cpp", "--",
"-resource-dir", CLANG_STD_INCLUDE_DIR}));

EXPECT_EQ("clang resource files are missing from /non-existent/123, "
"check that this application is installed properly",
verifyInstallation({"tool", "test.cpp", "--",
"-resource-dir", "/non-existent/123"}));
}

TEST_F(ToolApplicationSupportTest, toolchain)
{
EXPECT_EQ("clang could not find a C++ toolchain to use, check that the "
"compiler used to configure clang is installed",
verifyInstallation({"tool", "test.cpp", "--",
"-resource-dir", CLANG_STD_INCLUDE_DIR,
"-gcc-toolchain", "/non-existent/123"}));

// Check using a c file

EXPECT_EQ("", verifyInstallation({"tool", "test.c", "--",
"-resource-dir", CLANG_STD_INCLUDE_DIR}));

EXPECT_EQ("clang could not find a C++ toolchain to use, check that the "
"compiler used to configure clang is installed",
verifyInstallation({"tool", "test.c", "--",
"-resource-dir", CLANG_STD_INCLUDE_DIR,
"-gcc-toolchain", "/non-existent/123"}));
}

TEST_F(ToolApplicationSupportTest, compilation_database)
{
std::string buildDir =
CMAKE_SOURCE_DIR "/t/data/029-tool-application-support";

EXPECT_EQ("", verifyInstallation({"tool", "/src/test1.cpp",
"-p", buildDir}));

EXPECT_EQ("clang resource files are missing from /non-existent/123, "
"check that this application is installed properly",
verifyInstallation({"tool", "/src/test2.cpp",
"-p", buildDir}));

EXPECT_EQ("clang resource files are missing from /non-existent/123, "
"check that this application is installed properly",
verifyInstallation({"tool", "/src/test1.cpp",
"/src/testa2.cpp",
"-p", buildDir}));
}

1 change: 1 addition & 0 deletions t/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ foreach(
026-macro-propagation
027-c-style-variadic-integer-propagation
028-diagnostic-during-postprocessing
029-tool-application-support
)

add_executable(${TEST}.t ${TEST}.t.cpp)
Expand Down
8 changes: 8 additions & 0 deletions t/data/029-tool-application-support/compile_commands.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[
{ "directory": "/src",
"command": "clang test1.cpp -resource-dir .",
"file": "test1.cpp" },
{ "directory": "/src",
"command": "clang test2.cpp -resource-dir /non-existent/123",
"file": "test2.cpp" }
]

0 comments on commit b93f82f

Please sign in to comment.