Where communities thrive


  • Join over 1.5M+ people
  • Join over 100K+ communities
  • Free without limits
  • Create your own community
People
Activity
    Serega
    @kgames54
    Hello! Using cheerp without the "-cheerp-pretty-code" compilation option is not compatible with the jQuery library. If I connect to an empty project then it works fine. Writes the error "jQuery.Deferred exception: Cannot read property 'i0' of undefined TypeError: Cannot read property 'i0' of undefined". Is there a solution or should you use the "-cheerp-pretty-code" option?
    Carlo Piovesan
    @carlopi
    @gdmiron: could you set up a reproducible example so I could take a look?
    @kgames54: not sure what is the problem is, are you using client namespace + cheerp::jsexport?
    I would expect the solution is defining the relevant interfaces in namespace client and then whatever function that has to be available to external libraries.
    Could you share a somehow minimal example, so I could be able to provide directions?
    Serega
    @kgames54
    Yes, I use cheerp :: jsexport in my class
    #include <cheerp/client.h>
    #include <cheerp/clientlib.h>
    #include <random>
    #include <iostream>
    #include <stdio.h>
    #include <cstddef>
    #include <string.h>
    #include <stdio.h>
    #include <sstream>
    #include <algorithm>
    #include <iterator>
    #include <vector>
    
    #include "md5.h"
    #include "md5.cpp"
    
    using namespace client;
    using namespace std;
    
    class [[cheerp::jsexport]] HashGen
    {
    public:
           HashGen(String *method, String *params)
           {
           Generate(method, params);
           }
           void Generate(String *method, String *params)
           {
           String *url = new String(method);
           url = url->concat(params);
           url = url->concat(secret_key);
           hash = new String((char*)md5(string(*url)).c_str());
           }
           String* toMD5(String *value)
           {
           return new String((char*)md5(string(*value)).c_str());
           }
           String* getHash()
           {
           return new String(hash);
           }
    private:
           String *hash;
           const char *secret_key = "gf4H*3@@)jeJFmWlXxAaSx%^&k";
    };
    
    void loadCallback()
    {
    
    }
    
    void webMain()
    {
        document.addEventListener("DOMContentLoaded",cheerp::Callback(loadCallback));
    }
    I wanted to make a simple Hash signature generator to protect the server from request forgery.
    Serega
    @kgames54
    Compilation succeeds, but jQuery compatibility without the "-cheerp-pretty-code" parameter causes errors and crashes.
    Carlo Piovesan
    @carlopi
    How do you call HashGen?
    Given that jsexported class the interface should be something like:
    var hashGen = new HashGen("string1", "string2");
    console.log(hashGen.getHash());
    hashGen.Generate("otherString", "newParam");
    console.log(hashGen.getHash());
    console.log(hashGen.toMD5("someString"));
    Carlo Piovesan
    @carlopi
    In particular HashGen constructor has to be called always with the expected 2 parameters, could you check whether this might be the problem?
    If you need multiple constructors, you could use generator functions, something like
    class [[cheerp::jsexport]] SomeClass {
          SomeClass() {}
          SomeClass(int X) {}
         SomeClass(double A, double B) {}
    public:
          SomeClass* buildSomeClassVoid()
         {
              return new SomeClass();
         }
          SomeClass* buildSomeClassInt(int X)
         {
              return new SomeClass(X);
         }
          SomeClass* buildSomeClassTwoDouble(double A, double B)
         {
              return new SomeClass(A, B);
         }
         //....
    };
    Serega
    @kgames54

    If I create an empty constructor then the compiler gives the following error:
    LLVM ERROR: More than one constructor defined for class: HashGen
    Stack dump:

    1. Program arguments: C:\cheerp\bin\llc.exe -march=cheerp -o D:\HPDrivers\buildsystem\js\ghash.js -cheerp-pretty-code -filetype obj C:\Users\Andrey\AppData\Local\Temp\ghash-e7c4be.bc
    2. Running pass 'CheerpWritePass' on module 'C:\Users\Andrey\AppData\Local\Temp\ghash-e7c4be.bc'.
      clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)

    When compiling, I use the following command:
    C:\cheerp\bin\clang++.exe -target cheerp D:\HPDrivers\buildsystem\js\ghash.cpp -cheerp-pretty-code -Wunknown-attributes -Wunused-value -o D:\HPDrivers\buildsystem\js\ghash.js

    Carlo Piovesan
    @carlopi
    Yes, at most one constructor can be jsexported, but a basic patter would be having the other constructors private but then available via a factory function
    I realized I forgot to mark the factories as static in the previous example, now should be fixed:
    class [[cheerp::jsexport]] SomeClass {
          SomeClass() {}
          SomeClass(int X) {}
         SomeClass(double A, double B) {}
    public:
          static SomeClass* buildSomeClassVoid()
         {
              return new SomeClass();
         }
          static SomeClass* buildSomeClassInt(int X)
         {
              return new SomeClass(X);
         }
          static SomeClass* buildSomeClassTwoDouble(double A, double B)
         {
              return new SomeClass(A, B);
         }
         //....
    };
    Then you could call the constructors as:
    var hashGen = HashGen.buildSomeClassInt(4);
    Serega
    @kgames54
    image.png
    Tried building classes to do the same situation according to your sample. Perhaps jQuery is incompatible unless you use the -cheerp-pretty-code option.
    Thanks for the help! If I find any solution, I will definitely unsubscribe.
    Fabio
    @holofermes

    Hello!
    I'm playing around with cheerp and I'm trying to understand what's the best way to push data out of wasm into the browser.
    Here's a simple case of updating an array of positions, where a call to the native updatePositions_fromJS takes care of updating the local variable latestPositions with data calculated in wasm-land.

    I wasn't able to get any other combination of flags / attributes working.

    Have I gone off the mark, or is this the expected way of structuring such an intention?

    index.html:

    <script>
        let latestPositions;
        function updatePositions(positions) {
            latestPositions = positions;
        }
    </script>
    <script defer src="tessy.js"></script>
    <script>
      Tessy.promise.then(function () {
        const tessy = new Tessy();
    
        function updateTessy(){
            tessy.updatePositions_fromJS();
            for (let index = 0; index < latestPositions.length; index++) {
                const component = latestPositions[index];
                // do something with component
            }
            //   call this many times
            setTimeout(() => {
                updateTessy()
            }, 1000 / 60);  
          }
        updateTessy()
      });
    
    </script>

    main.cpp:

    #include <cheerp/clientlib.h>
    #include <cheerp/client.h>
    
    int nbPoints = 100;
    int nbPointsStorage = nbPoints * 3;
    float *positionsNative = new float[nbPointsStorage];
    
    namespace [[cheerp::genericjs]] client
    {
        void updatePositions(client::Float32Array *positions);
    }
    
    void [[cheerp::genericjs]] updatePositions_fromGeneric(float *t, int size)
    {
        client::Float32Array *positions = cheerp::MakeTypedArray(t, sizeof(float) * size);
        client::updatePositions(positions);
    }
    
    void updatePositions()
    {
        delete[] positionsNative;
        positionsNative = new float[nbPointsStorage];
        for (int i = 0; i < nbPoints; ++i)
        {
            positionsNative[i] = i;
        }
        updatePositions_fromGeneric(positionsNative, nbPointsStorage) ;
    }
    
    class [[cheerp::genericjs]] [[cheerp::jsexport]] Tessy
    {
    public:
        Tessy(){}
    
        void updatePositions_fromJS()
        {
            updatePositions();
        }
    };
    
    void webMain()
    {}

    And this is how I built this:

    clang++.exe -target cheerp-wasm main.o -o tessy.js -c src/main.cpp

    Carlo Piovesan
    @carlopi
    Hi @holofermes, I would structurate something like:
    #include <cheerp/clientlib.h>
    #include <cheerp/client.h>
    
    namespace [[cheerp::genericjs]] client
    {
        void updatePositions(client::Float32Array *positions);
    }
    
    class TessyImpl
    {
        const int nbPoints;
        const int nbPointsStorage;
        float *positionsNative;
    
    public:
        TessyImpl(int number) : nbPoints(number), nbPointsStorage(nbPoints*3), positionsNative(new float[nbPointsStorage]){}
    
        void updatePositionsImpl()
        {   
            delete[] positionsNative;
            positionsNative = new float[nbPointsStorage];
            for (int i = 0; i < nbPoints; ++i)
            {
                    positionsNative[i] = i;
            }
            updatePositions_fromGeneric(positionsNative, nbPointsStorage) ;
        }   
    private:
        void [[cheerp::genericjs]] updatePositions_fromGeneric(float *t, int size)
        {   
            client::Float32Array *positions = cheerp::MakeTypedArray(t, sizeof(float) * size);
            client::updatePositions(positions);
        }   
    };
    
    class [[cheerp::genericjs]] [[cheerp::jsexport]] Tessy
    {
            [[cheerp::wasm]] TessyImpl* impl;
    public:
            Tessy(int number) : impl(new TessyImpl(number))
            {
            }
            void updatePositions_fromJS()
            {
                    impl->updatePositionsImpl();
            }
            void delete_()
            {
                    //This has to be called when you are done with the instance of the Tessy class, otherwise resources will be leaked!
                    delete impl;
            }
    };
    
    void webMain()
    {}
    I am working on simplifying even further in the compiler, but currently pointer to Wasm implementation is probably the easier way. To note that the interface requires to call tessy.delete_() at some point.
    Note that this pointer to implementation pattern allows multiple Tessy classes to be alive at the same moment and things will not get messy
    The Tessy class will just forward the call to the relevant implementation class functions
    Fabio
    @holofermes
    worked great, thank you very much!
    George Dan Miron
    @gdmiron
    Hello, is there a reason why sleep(secs); form #include <unistd.h> called inside [[cheerp::wasm]] const std::string execTest(const std::vector<std::string> &argw) would build OK but crash upon code execution? Thanks!
    Carlo Piovesan
    @carlopi
    Hi @gdmiron: if you compile with the additional command line -cheerp-strict-linking=warning the compiler should inform you that "sleep" is not implemented, and so you are required to provide an implementation yourself. In this case this is not actually doable in practice. A solution that is viable in most cases is rewriting the sleep in term of a setTimeout/setInterval callback, but that have to be done at a source level.
    Something like void webMain() {while(true){ doStuff; sleep(100);} } to void webMain() { setInterval(doStuff(), 100);}
    George Dan Miron
    @gdmiron
    @carlopi Thanks!
    George Dan Miron
    @gdmiron
    @carlopi how to deal with calling "async" functions from C++ wasm, wait for the Promise to resolve to value, and continue with C++ code?
    George Dan Miron
    @gdmiron
    We are trying to read data from the browser database using JS functions that were exposed for C++
    Carlo Piovesan
    @carlopi
    Currently there is no support for awaiting on async function calls. Could the code be restructured so that code to be executed after the promise resolves becomes a callback?
    George Dan Miron
    @gdmiron
    @carlopi We managed to find a workaround and preload some of the data. But we now have a different issue when we parse json in C++ (compiled in wasm). We use the nlomann::json library. The code crashes when parsing a string json object that contains arrays with more than ~21 non primitive data entries e.g., 22 strings. The parsing works if the arrays contain any number of int, bool, float. It also works if the array contains many strings but in addition the same number of float entries, e.g. array of size 50 with 25 strings and 25 floats. Also parsing of objects with many nested objects works if no string that is larger than 21 entries with non primitive data is present. This points to some issue with memory allocation. We try to create a simple example and maybe you/colleagues can have a look. Thanks.
    Carlo Piovesan
    @carlopi
    This is very strange indeed, I would be interested to see an example of this behavior if possible
    bradwhitehead2
    @bradwhitehead2
    I have a requirement to support IE9 (no TypedArrays, no asm, and definitely no wasm ;-). I use a polyfill for the TypedArrays (and it works well with other libraries I'm using in the browser). I'd like to use Sqlite as part of the browser javascript. Emscripten has converted Sqlite to javascript as sql.js. Unfortunately Emscripten compiles to an asm. As part of the initialization of the asm, it grabs a lot of memory - too much memory for IE9. I can't even get the Emscripten-compiled Hello World program to run without running out of memory. So Cheerp looks like it should do the job. I had not problem compiling and running the Hello World program. When I try to compile the sqlite3.c program as a C program as generic JS, I get 5 errors, dealing with "Field not supported in" in unions. Sqlite uses a LOT of unions and most compile without any problem. I can't figure out what's special about these 5 unions. The field generating the error is always a pointer, but in some cases, it's only a char pointer. I know Cheerp can handle char pointers in unions. Here's an example:
    union {
    char zIndexedBy; / Identifier from "INDEXED BY <zIndex>" clause /
    ExprList
    pFuncArg; / Arguments to table-valued-function /
    } u1;
    sorry, forgot to Markdown it is code. Here's the union:
    `union {
    char zIndexedBy; / Identifier from "INDEXED BY <zIndex>" clause /
    ExprList
    pFuncArg; / Arguments to table-valued-function /
    } u1;'
    Here's the definition of the ExprList struct:
    bradwhitehead2
    @bradwhitehead2
    struct ExprList { int nExpr; /* Number of expressions on the list */ struct ExprList_item { /* For each expression in the list */ Expr *pExpr; /* The parse tree for this expression */ char *zEName; /* Token associated with this expression */ u8 sortFlags; /* Mask of KEYINFO_ORDER_* flags */ unsigned eEName :2; /* Meaning of zEName */ unsigned done :1; /* A flag to indicate when processing is finished */ unsigned reusable :1; /* Constant expression is reusable */ unsigned bSorterRef :1; /* Defer evaluation until after sorting */ unsigned bNulls: 1; /* True if explicit "NULLS FIRST/LAST" */ union { struct FIX1 x; int iConstExprReg; /* Register in which Expr value is cached */ } u; } a[1]; /* One slot for each expression in the list */ };
    union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ } u1;
    This generates:
    sqlite3.c:18437:11: error: Cheerp: Field not supported in '' char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    That caret is pointing at the first letter of the variable zIndexedBy
    Carlo Piovesan
    @carlopi
    I can reproduce the issue with this file: sqlite3_unions.c
    /opt/cheerp/bin/clang sqlite3_unions.c -target cheerp -o output.js
    In this case the compiler is acting as intended: when using -target cheerp as a target, pointers are opaque handles, and as such they can't be represented in an union, since they have no known binary representation
    Carlo Piovesan
    @carlopi
    As for your problem, what kind of memory limitations do you have? I would suspect that compiling to asmjs with low memory requirement + polyfiling TypedArrays is the easier way forward
    Cheerp while compiling to asmjs defaults to instantiating an ArrayBuffer of length 8388608, is that something feasible in your setting?
    George Dan Miron
    @gdmiron
    @carlopi We have prepared a repository with tests for jsonparsing using the nlohmann/json C++ library. The readme describes how to run the files and try to reproduce the errors https://github.com/congineer/cheerp-testlab/tree/jsonparse (branch jsonparse)
    Carlo Piovesan
    @carlopi
    @gdmiron: I did the basic set-up, and later I will check what's happening. Thanks for setting this up!
    George Dan Miron
    @gdmiron
    @carlopi Did you have time to check the tests? Thanks
    Carlo Piovesan
    @carlopi
    @gdmiron: yes, I reproduced the problem, we found a minimal testcase, identified what the problem is, and I am currently working on a fix. I will get back as soon as it's ready
    George Dan Miron
    @gdmiron
    @carlopi great!