Cheerp Tutorial

Alessandro Pignotti edited this page Oct 1, 2014 · 6 revisions

This tutorial will walk you through all the steps required to compile your first Web application in C++ using Cheerp.

Before starting, make sure to have Cheerp installed on your computer by following these instructions. After completing the installation, you will find the Cheerp compiler under the following paths:

  • Windows: C:\cheerp\bin\clang++.exe
  • Mac OS X: /opt/cheerp/bin/clang++
  • Linux: /opt/cheerp/bin/clang++

All the examples require running the Cheerp compiler from a command line. On Linux or Mac OS X, open the Terminal of your choice. On Windows, you can use the command prompt (Start - type 'cmd') or PowerShell (Start - type 'powershell'). All the following examples will assume a Linux environment, but similar command lines can be used under Mac OS X and Windows.

Hello World Wide Web!

You are now ready to compile your first Web application using Cheerp. Save the following C++ program as example.cpp.

// The cheerp/clientlib.h header contains declarations
// for all the browser APIs. 
#include <cheerp/clientlib.h>

// webMain is the entry point for web applications written in Cheerp.
void webMain()
{
    // client is a C++ namespace that contains all browser APIs 
    client::console.log("Hello World Wide Web!");
}

You can compile this program using the following command line:

/opt/cheerp/bin/clang++ -target cheerp example.cpp -o example.js

You can now run the generated JavaScript directly using node.js

nodejs example.js

Or you can include it inside an HTML file (e.g. example.html)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Cheerp test</title>
    <script defer src="example.js"></script>
  </head>
  <body>
  <h1 id="pagetitle">Boring static text</h1>
  </body>
</html>

And open it in your favorite browser. The message will appear in the browser JavaScript console.

Cheerp Hello World in Firefox

cheerp/clientlib.h contains declarations for the browser APIs. All functions are only declared so that the Cheerp C++ compiler can use them, but they are simply forwarded (with no additional overhead) to the browser at runtime. No implementation of these functions is provided by Cheerp, so that all browser APIs have the semantics provided by the browser you are currently using.

client is a C++ namespace that contains all browser APIs declared in cheerp/clientlib.h. The console object represent the console object of the browser. In the example, the console.log() function is invoked with a C string literal argument that will be implicitly converted to a JavaScript String.

The webMain entry point

The main function is the traditional entry point of a C++ program. It also contains the whole program, which terminates after the main function returns. On a Cheerp application, the webMain function plays the role of the entry point in a very different manner. webMain initializes the program, sets up event handlers and returns control to the browser as soon as possible. After returning, the browser notifies the events you registered handlers for.

Using DOM APIs

The following example shows how to write a simple Web application that uses the Browser's DOM functionalities. Check our online API reference for extensive documentation of Web APIs in the client namespace using Cheerp.

#include <cheerp/clientlib.h>

void webMain()
{
    // client::document represent the Javascript document object
    client::Element* titleElement=client::document.getElementById("pagetitle");
    // Wide strings can also be implicitly converted to JavaScript Strings
    titleElement->set_textContent(L"Exciting dynamic title, with non-Latin letters ΩЯÅ");
}

After compiling this example and embedding it in a web page, the result will look like:

Using callbacks

Let's extend the previous program to revert the original text after 3 seconds.

#include <cheerp/client.h>
#include <cheerp/clientlib.h>

// client is a regular C++ namespace, so we can reduce verbosity by using it
using namespace client;

void webMain()
{
    Element* titleElement=document.getElementById("pagetitle");
    // Save the old text, it is a JavaScript String
    String* oldText=titleElement->get_textContent();
    titleElement->set_textContent(L"Exciting dynamic title, with non-Latin letters ΩЯÅ");
    // setTimeout is included in the client namespace like other browser APIs
    // cheerp::Callback is bridge function to invoke C++ lambdas and functions as
    // JavaScript callbaks. We use C++11 lambda in this case.
    setTimeout(cheerp::Callback([titleElement,oldText](client::Event* e)
        {
            titleElement->set_textContent(oldText);
        }), 3000);
}

Interoperability with JavaScript code

Cheerp is designed to offer lightweight, bidirectional interoperability between C++ and JavaScript code. Let's see how you call JavaScript code from C++

Modify example.html to include and use jQuery

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Cheerp test</title>
    <script defer src="example.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script>
        // Use jQuery to make a (trivial) change to the page
        function changeTitle(str)
        {
                $("#pagetitle").text(str);
        }
    </script>
  </head>
  <body>
  <h1 id="pagetitle">Boring static text</h1>
  </body>
</html>

Let's use the JavaScript changeTitle function from C++

#include <cheerp/client.h>
#include <cheerp/clientlib.h>

// We need to extend the client namespace to declare our
// custom JavaScript function
namespace client
{
    // The name should be the same as the JavaScript one
    // The parameters needs to be a const client::String reference
    // so that implicit conversion from const char* is supported
    void changeTitle(const String& str);
}

using namespace client;

void webMain()
{
    Element* titleElement=document.getElementById("pagetitle");
    String* oldText=titleElement->get_textContent();
    changeTitle("Literal C++ string");
}

When declaring JavsScript methods in C++ you can use the following data types:

  • client::String as const references or pointers when using them as parameters and as pointers when returning them (e.g. client::String* concatStrings(const String& a, cinst String& b))
  • float, double and integer types
  • Pointers to C++ objects, to use them you still need to pass them back to C++ code.
  • C++ lambdas and functions as callback parameters. You need to use the client::EventListener* as the parameter type. (e.g. void addCallback(client::EventListener* callback)). In this case you need to use the cheerp::Callback bridge function as shown in the example above.

Directly invoking JavaScript code

You can also use the __asm__ keyword to inline JavaScript code in the middle of C++ code

void webMain()
{
    __asm__("console.log('Inline JS example')");
}

Invoking C++ code from JavaScript using the [[jsexport]] attribute

Cheerp makes it possible to allocate and use whole C++ classes from JavaScript. This is done using the [[jsexport]] class attribute.

#include <cheerp/client.h>
#include <cheerp/clientlib.h>

using namespace client;

// The class can of course have any name
// The [[jsexport]] attribute tells Cheerp to make
// the class available to JavaScript code
class [[jsexport]] JsBridge
{
private:
    // The class is allowed to have member variables
    // but they should all be trivially destructible
    int callCount;
public:
    JsBridge():callCount(0)
    {
    }
    int addAndReturn(int a)
    {
        console.log("Called C++ code");
        callCount+=a;
        return callCount;
    }
};

// An entry point, even if empty, is still required
void webMain()
{
}

We also need to modify the HTML page to interact with the jsexport-ed class

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Cheerp test</title>
    <script defer src="example.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
    <script>
        var jsBridge=null;
        function callCPPCode()
        {
            if(!jsBridge)
                jsBridge=new JsBridge();
            var ret=jsBridge.addAndReturn(3);
            $("#clickText").text("C++ code returned "+ret);
            return false;
        }
    </script>
  </head>
  <body>
  <a id="clickText" href="#" onclick="callCPPCode()">Click to call C++ code</a>
  </body>
</html>

As you can see you are free to allocate a new JsBridge object in JavaScript and use it directly.

Using complex browser APIs

We will show how to use XMLHttpRequest to retrieve a file. Please note that Chrome blocks XMLHttpRequests to local files so you need to run the example using Firefox or start a local web server.

#include <cheerp/client.h>
#include <cheerp/clientlib.h>

using namespace client;

void webMain()
{
    XMLHttpRequest* xhr=new XMLHttpRequest();
    // Let's load the C++ source code for this program
    xhr->open("GET","example.cpp");
    // Use a C++11 lambda to show the result on the page
    xhr->set_onload(cheerp::Callback([](Event* e) {
          XMLHttpRequest* target=(XMLHttpRequest*)e->get_target();
          String* ret=target->get_responseText();
          Element* newParagraph=document.createElement("p");
          newParagraph->set_textContent(ret);
          document.get_body()->appendChild(newParagraph);
      }));
  xhr->send();
}