Jesús Fernández

Scripting In C++

Published Friday June 15th, 2018
20 Comments on Scripting In C++
Posted in C++, Compilers, Dev Loop, Qt | Tags: ,

Recently I had to write some scripts to automatize some of my daily tasks. So I had to think about which scripting language to use. You’re probably not surprised when I say I went for C++. After trying several hacky approaches, I decided to try out Cling – a Clang-based C++ interpreter created by CERN.

Cling allows developers to write scripts using C and C++. Since it uses the Clang compiler, it supports the latest versions of the C++ standard.
If you execute the interpreter directly, you’ll have a live environment where you can start writing C++ code. As a part of the standard C/C++ syntax, you will find some other commands beginning with ‘.’ (dot).

When you use the interactive interpreter, you can write code like:

#include <stdio.h>
printf("hello world\n");

As you can see, there is no need to worry about scopes; you can just call a function.

If you plan to use Cling as an interpreter for creating your scripts, you need to wrap everything inside of a function. The entry point of the script by default is the same as the file name. It can be customized to call another function. So, the previous example would turn into something like:

#include <stdio.h>                                                                               
                                                                                                       
void _01_hello_world() {                                                                               
    printf("foo\n");                                                                                   
}

…or the C++ version:

#include <iostream>                                                                               

void _02_hello_world()
{
    std::cout << "Hello world" << std::endl;
}

The examples are quite simple, but they show you how to start.

 

What about Qt?

#include <QtWidgets/qapplication.h>                                                                    
#include <QtWidgets/qpushbutton.h>                                                                     
                                                                                                       
void _03_basic_qt()                                                                                    
{                                                                                                      
    int argc = 0;                                                                                      
    QApplication app(argc, nullptr);                                                                   
                                                                                                       
    QPushButton button("Hello world");                                                                 
    QObject::connect(&button, &QPushButton::pressed, &app, &QApplication::quit);                       
    button.show();                                                                                     
                                                                                                       
    app.exec();                                                                                        
}

But the previous code won’t work out of the box – you need to pass some custom parameters to cling:

cling -I/usr/include/x86_64-linux-gnu/qt5 -fPIC -lQt5Widgets 03_basic_qt.cpp

You can customize your “cling” in a custom script based on your needs.

You can also load Cling as a library in your applications to use C++ as a scripting language. I’ll show you how to do this in one of my next blog posts. Cheers!

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in C++, Compilers, Dev Loop, Qt | Tags: ,

20 comments

Lachu says:

I have had an idea to extend C/C++ preprocessor to support JavaScript commands, so programmer will have new possibilities, like creating an array by process files in project. Of course, there’s need to sandbox preprocessor.

Alexander says:

“If the only thing you have is a hammer, everything looks like a nail.”

Anyway, could be useful for a script with high-performance requirements.

d3fault says:

interesting but kinda not suited for Qt (which is async by default).

Interactive interpreters and asynchronous don’t play very well I wouldn’t think, but if you use Qt’s synchronous APIs this could be useful.

To clarify, in your example you instantiate a QPushButton and then call app.exec(). exec() never returns though, so you’ve lost the interactive’ness of your interactive interpreter! or maybe I’m wrong here, idk didn’t try the example

Here’s a thought: what if you set up async QObject trees on the main/gui thread, but then on a background thread you “spawned”(?) an interactive interpreter which is then run synchronously by user. that way you could interact, at runtime, with async Qt classes/designs (but then that background thread wouldn’t be able to receive events without giving up IT’S interactivity)

Jesús Fernández Jesús Fernández says:

You’re right; the event loop is mandatory. The previous code before the exec is to configure everything.
I did not use the interactive interpreter for the Qt example. It can work with classes not requiring an event loop (like QString, QFile, …).

My goal was to show how to write scripts using C++ and Qt.

This blog post is just a small part of a project I have in mind.

d3fault says:

would it be possible to have async-connected QObject trees running on one thread, and an interactive interpreter running on a different thread? you could thread-safely interact with the “QObject trees” thread by doing QMetaObject::invokeMethod calls

Jesús Fernández Jesús Fernández says:

Sounds like the way to go to have a live Qt interpreter. I’ll give a try.

Vladyslav Stelmakhovskyi says:

mmm. replace JS? gr8 idea

Jesús Fernández Jesús Fernández says:

Nop 😛

Andre says:

Awesome blog posts, Jesús. Keep them going!

Jesús Fernández Jesús Fernández says:

Thank you for reading!

MAASTARS says:

Thank you Jesús I will surely read that post

Jason says:

I would think that ChaiScript ( http://chaiscript.com/ ), a C++ Header-only scripting language would be a better choice?

Jesús Fernández Jesús Fernández says:

The good thing about using C++ as a scripting language is you don’t need to mess with bindings. You can just get the pointers and use them.
ChaiScript looks really good, I have been following it for a long time.

Yuri says:

Live goes in circle. Having QSA from around 2006 (which I think was really advance Qt feature by that time), I remeber building really flexible solutions with it.., then declare it obsolete, moving to QtScript (which I can understand to get ECMA compatibility, however I liked QSA syntax more) but also simplified a lot of things.. also used it a lot in production.. then declare it obsolete as well, and then 10+ years later got a blog post with 3rd party tools called Scripting in C++ =))

Liang Qi says:

Reference: https://doc.qt.io/archives/qsa-1.2.2/index.html

Yuri says:

Yeah.. even embedded debugger was quite Ok.. I think it was QSA Workbench or something.. was really easy to plug it in existing application and it was spawning debugger window on any error/exception happening in scripting..

Philip S. says:

Nice! This is pretty interesting. If you embedded the c++ scripting into your application and it calls a nullptr does the whole application crash or does the script just fail?

Philip S. says:

What’s the cross-platform support on cling? After doing a quick search, it seems like it has trouble on windows platforms.

Jesús Fernández Jesús Fernández says:

I’m a Linux user, so I don’t know. But it should work with WSL in Windows.

Jesús Fernández Jesús Fernández says:

^ no crash

Commenting closed.

Get started today with Qt Download now