On-The-Fly C++

Using cling to interpret C++ code

Posted on August 9, 2012 C++, llvm, clang .

I can’t recall how many times I had to write a basic small C or C++ program just to play around with an idea, the syntax of C++11 or anything similar. Very often indeed. Even though a good editor makes this very easy, it’s kind of a burden to have to create a project directory, a source file, spell out the same old includes and the main function before you actually can start the task you where about to try.
Then you compile and link, probably missing some libraries the first time until you finally get to take it on a first test run.

Building Cling

You gotta checkout llvm and clang from svn (do not use the git mirror! The makefile for cling uses the svn information!). Next checkout cling from svn into the tools folder and apply all the patches in the cling/patches directory and start your configure - make - make install cycle the same way you'd do for llvm and clang alone. Don't forget to include the --enable-targets=host when running configure.

So why put up with all of this when the next ruby or python or haskell interpreter is just a couple of keystrokes away: type irb or ghci and of you go. No includes, no compile, no linker. Just get to the meat of your idea and start experimenting. Still, would be nice to have this for C++ as well.
Yesterday I discovered something truly awesome: cling, an interactive interpreter for the C++ language based on clang/llvm.
Kind of a pain to get it set up correctly (they do not yet provide binaries for download) but once it’s done the fun can begin.

Enter the C++ interpreter: cling

Now that cling is build we can run it. Best to call it with C++11 support enabled so all of the C++11 features that clang provides should also work in cling:

$ cling  -Wc++11-extensions -std=c++11
****************** CLING ******************
* Type C++ code and press enter to run it *
*             Type .q to exit             *
*******************************************
[cling]$

Ready for a test run:

[cling]$ #include <iostream>
[cling]$ using namespace std;
[cling]$ int a[] = {1,2,3};
[cling]$ for (int& x: a){ x += 10; }
[cling]$ for (int& x: a){ cout << x << ","; }
11,12,13,

Doing calculations in C can yield some surprising results if the types are not correct. Checking small stuff in an interpreter can really help!
Same thing for bit fiddling…always nice to see how it will play out.

[cling]$ float r = 7/9;
[cling]$ r
(float) 0.000000e+00
[cling]$ r = (float)7/9;
[cling]$ r
(float) 7.777778e-01
[cling]$ (0b1 << 5) | 0x1
(int const) 33

Let’s use cling for more complicated math stuff. So we include the math header file:

[cling]$ #include <math>
input_line_36:1:10: fatal error: 'math' file not found
#include <math>
      ^

Uuh…header file not found…at least the error message is nice.

[cling]$ #include <cmath>
[cling]$ cos(7)
(double const) 7.539023e-01

Ok…that works nicely. What about using some C++11 features? Let’s try a lambda:

[cling]$ #include <iostream>
[cling]$ using namespace std;
[cling]$ auto func = [] () { cout << "Hello world" << endl; };
[cling]$ func
(class <lambda at input_line_6:2:14>) @0x7f7ad79b1021
[cling]$ func()
Hello world

Wow! Really impressive. Not only can you try out regular C++ bits and pieces, you can also fool around with C++11 features!
It’s even possible to load and access system libraries using the .L load instruction. Here is a brief example of how to load the libpthread and call one of it’s functions (pthread_self) to retrieve the ID of the calling thread:

[cling]$ .L libpthread
[cling]$ #include <pthread.h>
[cling]$ pthread_self()
(pthread_t const) 0x7fff7da43180

Summary of Metaprocessor commands

Cling understands some meta-commands that are not valid C++. Those commands are usefull to instruct cling to carry out certain administrative tasks, such as

  • .x test.cpp – load a file (if the file defines void test() it will be executed)
  • .L libname – load a libary or file
  • .x filename.cxx – loads filename and calls void filename() if defined
  • .I path – adds an include path
  • .printAST – shows the abstract syntax tree after each processed entity
  • .q – exit cling
  • .help – display a brief description

Worth a try

I’d say cling is definitely worth the try. It’s not perfect but can be a real timesaver when fooling around with C or C++ code. Especially for little bits and pieces you want to try out while working on a C/C++ codebase, it’s much less distracting to fire up a cling interpreter than to setup an example project.

Limitations

While using cling I discovered several things that were not perfect yet:

  • templates seem not to be supported
  • the auto keyword does not seem to be implicit on declarations like: i=5;
  • sometimes cling will segfault on small syntax errors and all current environment is lost
[cling]$ std:string s("hi");
input_line_7:2:6: error: unknown type name 'string'; did you mean 'std::string'?
 std:string s("hi");
     ^~~~~~
     std::string
/usr/include/c++/4.2.1/bits/stringfwd.h:59:33: note: 'std::string' declared here
  typedef basic_string<char>    string;
                                ^
Segmentation fault: 11

Further Information

Some interesting links people provided on hacker news

Photo: NASA / Dryden Flight Research Center