How to use standard library with Clang and LibTooling

5.4k views Asked by At

I want to use Clang and LibTooling to create some C++ source analysis and transformation tools. I've built Clang and LibTooling following this tutorial, and I've been able to run and create some analysis tools and compile C++ programs using the Clang binary I built. However, if I include headers from the standard library (in either source files or my tools), I run into issues when compiling or running the source files/tools. For instance, if I run clang-check on the following C++ source file:

#include <iostream>

int main() {
  std::cout << "Hello";
  return 0;
}

I get "fatal error: 'iostream' file not found". (Note: I can compile C++ programs, e.g. ones with user-defined classes, just not C++ programs using the standard library.) In an attempt to resolve the issue, I built libc++ (following this guide, building it in the llvm/project directory where I built LLVM and Clang), but I'm still having trouble getting Clang and the tools to use libc++. Now, if I try to compile a test file using:

export CPLUS_INCLUDE_PATH="~/clang-llvm/llvm/projects/libcxx/include"
export LD_LIBRARY_PATH="~/clang-llvm/llvm/projects/libcxx/lib"
~/clang-llvm/llvm/build/bin/clang++ ~/Documents/main.cpp

Then I get "fatal error: 'unistd.h' file not found". So my question is this: how do I properly point Clang and my tools to use libc++?

I am running OS X Yosemite 10.10 and using Clang 3.6.0.

4

There are 4 answers

0
Rafał Dembek On BEST ANSWER

Clang comes with some custom includes. So usually you have clang in /usr/bin/clang++ and the includes in /usr/lib/clang/3.6.1/include

but clang looks for them as a relative path: ../lib/clang/3.6.1/include

so make sure this relative path is accessible from either the clang++ binary, or your libtooling application.

0
Ethan On

Did you move/rename any of the parent directories after building/installing? The compiler should have been configured to know where to look for its standard libraries without having to specify the environment variable paths.

0
V Shreyas On

Use homebrew and install llvm using the command

brew install llvm

Your problem should be solved.

0
Alex H. On

Include your tool into this:

#include "clang/Tooling/CommonOptionsParser.h"      // For reading compiler switches from the command line
#include "clang/Tooling/Tooling.h"

static cl::OptionCategory MyToolCategory("SearchGlobalSymbols");
static cl::extrahelp MoreHelp("\nMore help text...");       // Text that will be appended to the help text. You can leave out this line.
/* Your code (definition of your custom RecursiveASTVisitor and ASTConsumer) */
/* Define class MyASTFrontendAction here, derived from ASTFrontendAction */

int main(int argc, const char **argv)
{
    /* Your code */
    CommonOptionsParser op(argc, argv, MyToolCategory);                     // Parse the command-line arguments
    ClangTool Tool(op.getCompilations(), op.getSourcePathList());           // Create a new Clang Tool instance (a LibTooling environment)
    return Tool.run(newFrontendActionFactory<MyASTFrontendAction>().get()); // Run custom Frontendaction
}

The CommonOptionsParser allows you to read commands from the command line that are passed to the compiler. For example, you can now call your tool like this:

your-tool yoursourcefile.c -- -nostdinc -I"path/to/your/standardlibrary"

Everything after the double dash will be passed to the compiler. Possible flags are described here: http://clang.llvm.org/docs/CommandGuide/clang.html

-nostdinc tells the Preprocessor not to look for standard include paths. You can specify you own paths instead after -I.

Hope it helped someone :) Ask me if I wasn't specific enough.