C/C++
Run the C/C++ examples calling byexample as:
$ byexample -l cpp your-file-here # byexample: +skip
To support C/C++, byexample relays in the cling interpreter.
You need to have cling installed first.
It is still an experimental feature that works pretty well but it is not immune to bugs, quirks nor crashes.
Don’t forget to send your feedback to the cling community.
Stability:
experimental- non backward compatibility changes are possible or even removal between versions (even patch versions).
Because installing and using cling may be a little difficult, we
offer a docker image with cling
pre-installed (the
dockerfile
is available too).
To use the cling in that docker image follow
the how to run with docker tutorial
which explains how to configure the host system and how to run
byexample with an interpreter (cling) which it is in a docker image.
Variable definition
All the variables are global and can be accessed by other examples
?: double radio = 2.0;
?: double sup = 3.14 * (radio * radio);
?: sup
(double) 12.56<...>
The last expression without ending with a ; is interpreted by
cling as the expression to not only evaluate but also to print its value.
stdlib
You can use the stdlib as usual.
Here is an example of how to print something and check the output later:
?: #include <iostream>
?: int i;
?: for (i = 0; i < 3; ++i) {
:: std::cout << i << std::endl;
:: }
0
1
2
External libs
In addition to stdlib you can add your own. These can be
in the form of C++ code and it will be compiled by cling or in
the form of PIC, shared and dynamically linked library (aka, .so)
For the first case you need to pass the path to the source code
with .L or these pragma
?: #pragma cling load("test/ds/mylib1.cpp") // this will compile mylib1.cpp
?: #include "test/ds/mylib1.h" // the headers are needed to, as usual
?: mylib1_foo(2)
calling my lib1
(int) 4
For the second case, we need to compile the code ourselves:
$ g++ -shared -fPIC -o test/ds/libmylib2.so test/ds/mylib2.cpp # byexample: +timeout=16
The load then proceeds as before.
?: #pragma cling load("test/ds/libmylib2.so") // already compiled
?: #include "test/ds/mylib2.h" // the headers are needed to, as usual
?: mylib2_foo(2)
increased performance with lib2
(int) 6
We can define where to search for libraries and headers via two pragma
so we can avoid some typing
?: #pragma cling add_library_path("test/ds/")
?: #pragma cling add_include_path("test/ds/")
?: #pragma cling load("mylib3.cpp") // works for .so too
?: #include "mylib3.h"
?: mylib3_foo(2)
lib3, four times better
(int) 8
Note:
clingis quite experimental and at least for the 0.6 version, it has not good diagnostic messages.If you find an error like
fatal error: 'libmylib2.so' file not foundit may indicate that you are not configuring the path correctly or that the library was not compiled as shared.Best way to troubleshoot is to use explicit paths to distinguish one error from the other.
If
clingtries to load you shared library but it complains that it is not an UTF-8 valid file it means thatclingis trying to see the library as source code. I found that this happen if the library is not compiled as a shared library.Double check with
file libmylib2.so, you should see something likelibmylib2.so: ELF 64-bit LSB pie executable, ..., dynamically linked, ...
Running C code (and not C++)
cling only supports C++ however it is possible to test C code
if it is compiled outside of cling and loaded as a library.
$ gcc -std=c99 -shared -fPIC -o test/ds/libmylibC.so test/ds/mylibC.c # byexample: +timeout=16
?: #pragma cling load("test/ds/libmylibC.so") // C code
?: #include "test/ds/mylibC.h" // the declarations must be inside the extern "C" {...}
?: mylibC_foo(2)
(int) 3
While the examples will be running as C++ code, the function
mylibC_foo was compiled as C code.
Keep in mind that the header mylibC.h must have all the function
declarations inside extern "C" { ... } so cling will know that it
has to use the “C” calling convention and not the “C++” one.
See language linkage for reference.
Syntax errors
byexample will show you the syntax errors detected by cling.
You can even check for them as part of the normal output:
?: for (i = 0; i < unknown; ++i) {
:: std::cout << i << std::endl;
:: }
<...>: error: use of undeclared identifier 'unknown'
for (i = 0; i < unknown; ++i) {
^
Known limitations
Gotchas
To print boolean expressions you need to surround them with parenthesis
?: (1 == 2)
(bool) false
Terminal support
To work with the current C/C++ interpreter, cling, the ANSI
terminal emulator is
enabled by default (+term=ansi) and cannot be disabled.
Also, the terminal geometry is set to a default of 1024 columns and 2048 rows with a minimum of 128x128.
Changed: before
byexample 11.0.0the runner was forced to use a 128x128 geometry without possibilities of change it. Since11.0.0, the default is expanded to 2048x1024 and can be changed at any time but always with a minimum of 128x128.
Note: the minimum is enforced because if the snippet of C++ or the output is larger than the size of the terminal, the output will be undefined.
The default of 2048x1024 should be fine for most of the use cases.
Echoed input lines
If the C/C++ snippet has a very long line, greater than the terminal’s width, the last part of the line that does not fit in the terminal will be echoed in the output of the example.
This is an annoying artifact due how cling works.
A simple workaround is to make the lines of the code in the snippet shorter or increase the terminal width.
Abort on a timeout
If a C/C++ example takes too long and timeout, the whole execution timeout.
Type text
The type
feature (+type) is not supported.
C/C++ specific options
$ byexample -l cpp --show-options # byexample: +norm-ws
<...>
cpp's specific options
----------------------
None.