Limitations of the Web platform
The main limitations to keep in mind that are introduced when targeting a Web application are:
- No real multithreading model is present (although a model similar to multiprocessing is available thanks to WebWorkers)
- No filesystem access (besides files that the user has explicitly selected)
The Cheerp compiler is developed following the philosophy of exposing both the features and limitations of the Web platform to the application. As such, any function exposed by the Web browser is available to be accessed from C/C++ code compiled with Cheerp, and conversely, all of its architectural limitations are exposed.
Limitations introduced by Cheerp
While most C++ applications, especially portable, multi-platform ones, have a sufficent level of type safety to be compilable with Cheerp, some C++ and many C applications and libraries will require some work to be portable using Cheerp. By default, Cheerp is quite verbose in reporting type safety issues, and its console output can be effectively used to guide the type-safety improvement efforts.
Unsupported code and workarounds
Custom allocators and type-unsafe pool allocators
A recommended workaround is to disable custom allocators and directly call
(struct destinationType*) malloc(sizeof(struct destinationType)) or
new destinationType(). Some C libraries (Zlib is an example) call
free indirectly through function pointers contained in a context structure. In such case you will need to replace the indirect call with direct calls to
malloc with a well defined type.
Code that requires a byte addressable space
C library functions such as
bsearch are not supported with Cheerp (in
genericjs mode) as they required a byte-addressable architecture. A workaround that can be used is to compile the C file as a C++ file and use C++ function equivalents, such as
std::binary_search from the C++ library. Similarily,
memcmp is also not supported in
genericjs mode, but can be replaced with
CHEERP_MEMCMP from the
Internal pointer ordering
When compiling in
genericjs mode (i.e. not in
asmjs/wasm) Cheerp will aggressively re-order members inside every
struct/class to optimize the amount of memory consumed by the corresponding JS object. This means that the ordering between pointer to members is undefined. As an example consider the following code:
On a native target (and when using Cheerp to compile
asmjs/wasm code) the assertion above will always be valid. When compiling in
genericjs mode the result is undefined (i.e. the assertion may trigger). This limitation is most usually not a problem. In case you need to maintain the ordering of members (for example, you need to memcpy the struct from a serialized buffer), you should use the
[[cheerp::bytelayout]] attribute. With this attribute Cheerp will use a different representation which provide the normal ordering between members.
Memory functions such as
memmove are supported, but the argument type must be known at compile time.
A recommended approach to porting an application
At Leaning Technologies we have built quite some experience in porting large-scale C/C++ code bases using Cheerp. In our opinion, the fastest, most effective way to get to a fully working ported application is to follow a top-down approach. Cheerp is designed to help in the porting process by providing verbose error and warning messages that highlight the code that is definitely (in case of errors) or possibly (in case of warnings) not supported on the Web platform.
The top-down approach that we recommend is as follows:
- Configure the build system to use the Cheerp compiler. Cheerp is derived from clang and it is mostly command line compatible with gcc/clang.
- If your codebase is already multiplatform, use the Linux or Unix target as the starting point for the Cheerp version. Cheerp defines the
__CHEERP__macro to make it possible to integrate Cheerp code in the platform specific sections of your codebases.
- Get most of your cosebase to compile, by fixing - if immediately obvious - or commenting out sections using the
#ifndef __CHEERP__/#endifidiom. You will be able to work those sections back in the code base later in the process, allowing you to prioritize the different parts.
- This should get you quickly to a rough proof of concept, which you can integrate into a Web application and test.
- Fix type safety and platform specific issues as required to get your tests and benchmarks to run.
- Gradually reintroduce the commented sections of your code into the code base and test them, until you get to your complete application.
Commenting out code
#ifndef __CHEERP__/#endif idiom to proceed further with the porting.
If you need to comment out subsections of a method we recommend the following idiom to avoid potential issues.
While commenting out code is effective to evaluate the scale of the required porting work and quickly getting to a proof-of-concept state, it should be kept in mind that it can also lead to issues that are difficult to debug, and a careful use of a version control system will help mitigating the risks of losing track of the root cause of some problems.