How to use standard library with Clang and LibTooling - c++

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.

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.

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.

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.

Use homebrew and install llvm using the command
brew install llvm
Your problem should be solved.

Related

Using libclang 6.0.1: stddef.h not found

To get started with libclang, I build a very simple program that tries to load a very simple source file. It fails with 'stddef.h' file not found.
Here is the program using libclang:
#include <clang-c/Index.h>
int main() {
CXIndex index = clang_createIndex(1,1);
const char *source_path = "foo.cpp";
clang_createTranslationUnitFromSourceFile(index,"foo.cpp",0,0,0,0);
}
(For conciseness, I left out code that is irrelevant to reproducing the issue).
And here is the file I am trying to load, foo.cpp:
#include <stddef.h>
int main() {}
I am using LLVM and Clang 6.0.1, compiled from source as follows:
cmake .. -DCMAKE_INSTALL_PREFIX=$HOME/local -DCMAKE_PREFIX_PATH=$HOME/local -DCMAKE_BUILD_TYPE=Release
make
make install
A quick search yields this promising post: Clang Error - stddef file not found? Unfortunately, this is about llvm 3.5, and I am using llvm 6.0.1. Also, the directory $HOME/local where I installed LLVM and Clang does not have a /usr/lib directory, so the solution proposed there does not work here.
The stddef.h header is present at $HOME/lib/clang/6.0.1/include/stddef.h. Explicitly adding this path as a -isystem option to the clang_createTranslationUnitFromSourceFile call solves the problem.
Moreover, the include search path used by clang_createTranslationUnitFromSourceFile is not the same as that used by clang++; clang++ foo.cpp works without errors.
Is there any documentation on the include search path used by clang_createTranslationUnitFromSourceFile and similar functions in libclang, so that I can determine which include paths need to be added?
Any other suggestions on how to invoke clang_createTranslationUnitFromSourceFile with a correct include search path, equivalent to the path used by clang++?
libclang works as if you tried to compile the file, i.e.: to parse a file it needs to know where to look for the headers, and potentially other info such as macro definitions, compile flags, etc.
clang_createTranslationUnitFromSourceFile has two parameters: num_clang_command_line_args and clang_command_line_args. There you need to pass actual header search path, e.g.:
const char *cli_args[] = { "-I", "~/local" };
clang_createTranslationUnitFromSourceFile(index, "foo.cpp", 2, cli_args, 0, 0);

gcc and clang under msys2 cannot resolve includes with absolute paths

I try to get tests generated by the cxxtest framework working under a MinGW environment managed by mysys2. The tool generates C++ files with absolute paths. However, gcc seems to be unable to resolve this absolute paths.
Here is a minimal example to demonstrate the problem:
// file1.h
#include <iostream>
inline void hallo() { std::cout << "Hallo\n"; }
// main.cpp
#include "/home/phil/example/file1.h"
int main()
{
hallo();
return 0;
}
The file exists (at least the msys2 shell resolves the path):
$ ls /home/phil/example/file1.h
/home/phil/example/file1.h
... but calling g++ results in this error:
$ g++ main.cpp
main.cpp:1:38: fatal error: /home/phil/example/file1.h: No such file or directory
#include "/home/phil/example/file1.h"
^
compilation terminated.
Same error with clang.
Under a full Linux environment, the example works. It also works if I replace the absolute path by a relative one (#include "file1.h").
So, I assume the problem lies in the layer over Windows that is responsible to resolve paths. Not sure whether I should report it as a bug to the msys2 project, or whether it is a known problem. If it is a known problem, are there any workarounds (like setting -I options)?
(If possible, I would like to avoid replace the absolute paths, as they are in generated code by the cxxtest framework. Technically, running a postprocessing step on the generated files would be possible but seems like a hack in the long run.)
Since you are running compilers that use MinGW-w64 as their runtime environment, they don't recognize POSIX-style paths like that. I think they actually interpret the root directory "/" to be "C:\". Other than that, they would only recognize native Windows-style paths.
I recommend that you pass the argument -I/home/phil/example to your compiler from some program running in the msys-2.0.dll POSIX emulation runtime environment (e.g. /usr/bin/bash or /usr/bin/make). The msys-2.0.dll runtime will then convert that argument to use a native Windows path so the compiler can understand it, and statements like #include <file1.h> will work. Alternatively, you might try putting a Windows-style path in your source code, e.g. the path should start with C:\.
Note however that having absolute paths in source code or build scripts is a bad idea since it makes it harder to build the code on a different computer. You could consider using environment variables or relative paths.
Try using the MinGW compiler that Cygwin provides as a package. (In other words, forget the MSYS environment; work under Cygwin, but build the code as before, in the MinGW style.)
Then you should be able to have include references /home/phil; it will just resolve to C:\Cygwin\home\phil or wherever your Cygwin root is.
Actually, it might be possible under MSYS also (which, after all, is just the descendant of an old for of Cygwin). You just have to figure out what /home/phil is referring to, create that tree and work under there.

Clang fails to find iostream. What should I do?

Earlier, I posed a related question.
I have the following program extracted from a large project in my Mac OS
#include <iostream>
int main(){
std::cout<<"hello"<<std::endl;
return 0;
}
Compiling it with Clang fails with the following error:
$ clang test.cpp
test.cpp:1:10: fatal error: 'iostream' file not found
#include <iostream>
^
1 error generated.
For information,
A) I have already installed xcode command line tools, using xcodeselect --install. But it seems iostream does not locate in the default search path of clang.
B) Using g++ instead of clang compiles the program. But in my problem, I am not allowed to use other compiler than clang, or to change the source program.
C) I can see workaround techniques, e.g, by tweaking the search path in .bashrc or with some symbolic link, etc. But I feel reluctant to use them, because it seems that I have an installation problem with my Clang and tweaking the path only helps to avoid one of these path issues.
clang and clang++ do different things. If you want to compile C++ code, you need to use clang++
Alternatively you can invoke c++ compiler directly by providing language name explicitely:
clang -x=c++

Compilation error: "stddef.h: No such file or directory"

Whenever I try to compile this code it always ends up with this error:
In file included from /usr/include/wchar.h:6:0,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/cwchar:44,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/bits/postypes.h:40,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/iosfwd:40,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/ios:38,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/ostream:38,
from /usr/lib/gcc/i686-pc-cygwin/4.9.2/include/c++/iostream:39,
from test.cpp:1:
/usr/include/sys/reent.h:14:20: fatal error: stddef.h: No such file or directory
#include <stddef.h>
^
compilation terminated.
The code I was trying to compile is:
#include <iostream>
using namespace std;
int main()
{
cout << "Hello World! :D";
return 0;
}
The error is because your gcc-core package and gcc-g++ are not of the same version. Either downgrade one of them to solve the problem or update both the libraries. Updating both the libraries is the recommended way.
I had this error on a fresh MinGW install, it had nothing to do with the installed packages mentioned in the current accepted answer by "Prasanth Karri". In my case the issue was caused by -nostdinc in my Makefile. I actually only needed that compiler flag when building for a different target platform (not when using MinGW) so I fixed the issue by removing that flag from MinGW builds.
When I was incorporating a software library written in C into an existing demo project(used a C++ mbed library) I encountered this problem. The demo project would compile just fine, but after I replaced the existing main file by my own, this error occurred.
At this point I hadn't yet thought about the fact that the mbed library that I needed was written in C++. My own main file was a .c file that #include the mbed header file. As a result I used my normal C source as if it was a C++ source. Therefore the compiler that was used to compile my main file was the C compiler.
This C compiler then encountered a #include of a module that actually does not exist (within its scope), as it's not a C++ compiler.
Only after I inspected the output of the build log I realised the various source C and C++ files were compiled by more that 1 compiler(the c++ compiler). The project used used compilers arm-none-eabi-c++ and arm-none-eabi-gcc (for embedded systems) as seen below.
Compile log:
Building file: ../anyfile.cpp
Invoking: MCU C++ Compiler
arm-none-eabi-c++ <A lot of arguments> "../anyfile.cpp"
Finished building: ../anyfile.cpp
Building file: ../main.c
Invoking: MCU C Compiler
arm-none-eabi-gcc <A lot of arguments> "../main.c"
In file included from <Project directory>\mbed/mbed.h:21:0,
from ../main.c:16:
<Project directory>\mbed/platform.h:25:19: fatal error: cstddef: No such file or directory
compilation terminated.
Of course in a C++ environment cstddef exists, but in a C environment cstddef doesn't exist, in stead it's just C's implementation of stddef.
In other words, cstddef does not exist in the C compiler.
I resolved this problem by renaming my main.c file to main.cpp and the rest of the code compiled smoothly too.
TLDR/Conclusion: When building a C++ project, avoid mixing C files with C++ files(sources and headers). If possible rename .c files to .cpp files to use the C++ compiler in stead of the C compiler where required.
In order to update it, follow below.
If you are on Windows, just run these on command prompt or powershell
Update the package list: mingw-get update
After updating the package list, run: mingw-get upgrade
Source: How to update GCC in MinGW on Windows?
This problem was solved for me as I installed codeblocks with mingw compiler then I copied the mingw folder from codeblocks to C drive and added
C\mingw\bin to the environment variables.
If you try to compile and see a message like, "fatal error: stddef.h: No such file or directory", the error is because your gcc-core and gcc-g++ packages are not of the same version. Rerun the Cygwin install and make sure that you select the highest numbered versions of gcc-core and gcc-g++.
After installing the C++ compiler with MinGW I encountered this problem as well. Apparently, you have to also install mingw32-base. Go to C:/MinGW/bin/mingw-get.exe (my path) and check it for installation at the Basic Setup tab.

How can I use a C++11 to program the Arduino?

How can I use C++11 when programming the Arduino?
I would be fine using either the Arduino IDE or another environment. I am most interested in the core language improvements, not things that require standard library changes.
As of version 1.6.6, the Arduino IDE enables C++11 by default.
For older versions, read on:
It is very easy to change the flags for any element of the toolchain, including the assembler, compiler, linker or archiver.
Tested on the Arduino IDE version 1.5.7 (released on July 2014),
Locate the platform.txt file,
AVR architecture => {install path}\hardware\arduino\avr\platform.txt
SAM architecture => {install path}\hardware\arduino\sam\platform.txt
Inside that file, you can change any flag, for instance,
compiler.c.flags for changing the default compilation flags for C++ files.
compiler.cpp.flags for changing the default compilation flags for C++ files.
You can also change any of the "recipes" or compile patters, at the corresponding section of the configuration file, under the title "AVR/SAM compile patterns".
After making the changes, you must restart the Arduino IDE, at least on version 1.5.7.
For instance,
To enable support for C++11 (C++0x), tested on Arduino IDE versions 1.5.7 and 1.5.8, you will simply add the flag "-std=gnu++11" at the end of the line starting with compiler.cpp.flags=".
It is expected that C++11 is enabled by default in the near future on the Arduino IDE. However, as of version 1.5.8 (Oct 2014) it is still not the case.
Arduino IDE 1.6.6 and newer have C++11 enabled by default (they have the compiler flag "-std=gnu++11" set in the platform.txt file).
Firstly, only GCC 4.7 and above (and therefore AVR-GCC 4.7 and above) support C++11. So, check the versions installed with:
gcc --version
avr-gcc --version
If AVR-GCC is 4.7 or higher, then you may be able to use C++11.
The Arduino IDE does not support custom compiler flags. This has been requested, but has not yet been implemented.
So, you are left with having to use other environments or to compile your program directly from the command line.
In case, of compiling directly from the command line using AVR-GCC, you simply need to add an extra compiler flag for enabling C++11 support.
-std=c++11
For specific development environments, most would support editing of the compiler flags from the build options within the IDE. The above mentioned flag needs to be added to the list of flags for each environment.
C++0x was the name of working draft of the C++11 standard. C++0x support is available GCC 4.3 onwards. However, this is strictly experimental support so you cannot reliably expect C++11 features to be present. Here is the complete list of features available with the corresponding version of GCC. The availability of features in AVR-GCC will be the same as what's available in the corresponding GCC version.
The compiler flag for C++0x is:
-std=c++0x
Please, note, that there is no easy way to specify additional flags from Arduino IDE or use other IDE (Eclipse, Code::Blocks, etc.) or command line.
As a hack, you can use a small proxy program (should be cross-platform):
//============================================================================
// Name : gcc-proxy.cpp
// Copyright : Use as you want
// Description : Based on http://stackoverflow.com/questions/5846934/how-to-pass-a-vector-to-execvp
//============================================================================
#include <unistd.h>
#include <iostream>
#include <vector>
#include <fstream>
using namespace std;
int main(int argc, char *argv[]) {
vector<string> arguments;
vector<const char*> aptrs;
// Additional options, one per line
ifstream cfg((string(argv[0]) + ".ini").c_str());
if (cfg.bad())
cerr << "Could not open ini file (you're using proxy for some reason, er?)" << endl;
string arg;
while (cfg) {
getline(cfg, arg);
if(arg == "\r" || arg == "\n")
continue;
arguments.push_back(arg);
}
for (const string& arg : arguments)
aptrs.push_back(arg.c_str());
for (int i = 1; i < argc; ++i)
aptrs.push_back(argv[i]);
// Add null pointer at the end, execvp expects NULL as last element
aptrs.push_back(nullptr);
// Pass the vector's internal array to execvp
const char **command = &aptrs[0];
return execvp(command[0], command);
}
Compile the program.
Rename the original avr-g++.exe to avr-g++.orig.exe (or any other name).
Create avr-g++.ini file where the first line is FULL path to the original program (e.g. D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe) and add additional parameters, one per line, as desired.
You're done!
Example avr-g++.ini:
D:\Arduino\hardware\tools\avr\bin\avr-g++.orig.exe
-std=c++0x
I use Ino and this worked:
ino build -cppflags="-std=c++0x"
This generated a hex file at least 15k in size (that's with optimizations turned on), compared to about 5k for the standard build, which is a consideration for a poor little ATmega328. It might be okay for one of the microcontrollers with a lot more program space.
If you need more control and a better IDE, I recommend using Sloeber Plugin for Eclipse or the Sloeber IDE itself.
Creating more complicated code is much easier using this IDE. It also allows to add flags to the compiler (C, C++ and linker). So to customize the compile, just right click on project and select Properties. In the Properties window, select Arduino → Compiler Option. This way you can add options to your build.