emscripten-core / emscripten-core/emscripten
Function signature mismatch with Embind + Function Pointers + dynamic libraries + Optimizations (with minimal test case)
- Dominant language
- C++
- Stars
- 27.6k
- Forks
- 3.6k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 105
Description
Test case: https://github.com/donalffons/embind-dynamicLibs-04
Preview Link: https://embind-dynamic-libs-04-git-master.donalffons.vercel.app/javascript
Error message:
```
Uncaught (in promise) RuntimeError: function signature mismatch
at NCollection_Vector::expandV() (:wasm-function[31]:0x2127)
at STEPCAFControl_Reader::ReadFile() (:wasm-function[32]:0x2177)
at emscripten::internal::MethodInvoker::invoke(void (STEPCAFControl_Reader::* const&)(), STEPCAFControl_Reader*) (:wasm-function[28]:0x20fb)
at STEPCAFControl_Reader$ReadFile [as ReadFile] (eval at new_ (http://localhost:5000/emscripten/build/main.js:30415:27), :8:1)
at http://localhost:5000/javascript/myWorker.js:14:10
```
This test case is distilled down from a large project with several thousand source files. Here's the gist:
- I'm using Embind and dynamic libraries. There is one MAIN_MODULE and one SIDE_MODULE (if I don't use modules, the error goes away)
- The MAIN_MODULE is empty (contains an empty bindings file as input)
- The SIDE_MODULE contains bindings for the class `STEPCAFControl_Reader` and the following code
```cpp
/* NCollection_Vector.h */
class NCollection_Vector
{
typedef void (*initMemBlocks_t) ();
initMemBlocks_t myInitBlocks;
public:
NCollection_Vector() : myInitBlocks(NCollection_Vector::initMemBlocks) {}
void expandV();
static void initMemBlocks() {}
};
/* NCollection_Vector.cxx */
void NCollection_Vector::expandV()
{
myInitBlocks(); // ERROR: Uncaught (in promise) RuntimeError: function signature mismatch
}
```
```cpp
/* STEPCAFControl_Reader.hxx */
class STEPCAFControl_Reader
{
public:
STEPCAFControl_Reader(){}
void ReadFile();
};
/* STEPCAFControl_Reader.cxx */
void STEPCAFControl_Reader::ReadFile()
{
std::cout << "1" << std::endl;
NCollection_Vector testVec;
std::cout << "2" << std::endl;
testVec.expandV(); // Error
std::cout << "3" << std::endl;
}
```
- In my JavaScript code, I want to use `STEPCAFControl_Reader` like this:
```js
const reader = new o.STEPCAFControl_Reader();
reader.ReadFile(); // Error
```
- I'm am using a two-staged build system, which first compiles all source files into `.o`-files using `emcc -c`. Those `.o`-files are then used as input files to the `emcc --bind` command of the SIDE_MODULE. If I use the `.cxx` files directly (instead of the `.o`-files), the error goes away. If I put the method definition of the problematic `expandV` method directly into the header files, the error also goes away.
- I'm building the SIDE_MODULE with `-O3` optimizations. If I'm building it [with `-O1` or `O0` optimizations](https://github.com/donalffons/embind-dynamicLibs-04/blob/master/emscripten/build.sh#L22), the error goes away.
- If I remove the bindings for [`NCollection_Vector`](https://github.com/donalffons/embind-dynamicLibs-04/blob/master/emscripten/embind-library.cpp#L8), the error goes away.
- I read the documentation on potential issues with [function pointers](https://emscripten.org/docs/porting/guidelines/function_pointer_issues.html), but if I understand correctly, the pitfalls mentioned there, do not apply to this case.
I would greatly appreciate it if someone could take a look at this issue. Based on my investigations, I see several potential workarounds. However, I do think that this test case *should* work as it is.
Contributor guide
Assessment
This issue has not been assessed yet.