Emscripten: Error: undefined exported function

Created on 22 Dec 2018  路  14Comments  路  Source: emscripten-core/emscripten

I'm using a Wasm Backend. I tried to compile this code:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <list>
#include <stdexcept>
#include <emscripten/emscripten.h>
#include <emscripten/bind.h>

#undef SDL_MAIN

namespace my
{
    template<typename Input_Iter, typename T>
    EMSCRIPTEN_KEEPALIVE std::ptrdiff_t count(Input_Iter first, Input_Iter last, const T &val);
}

void use_count();

int main()
{
    std::cout << "Module loaded\n";
}

void use_count()
{
    std::vector<int> myvec{ 1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 9, 9, 10, 10, 10 };
    constexpr int key = 3;
    auto num_occur = std::count(myvec.begin(), myvec.end(), key);
    auto num_occur2 = my::count(myvec.begin(), myvec.end(), key);
    std::cout << "Number of occurrences of " << key << " in myvec using std::count is " << num_occur
        << " and is " << num_occur2 << " using my::count\n";
}

template<typename Input_Iter, typename T>
std::ptrdiff_t my::count(Input_Iter first, Input_Iter last, const T &val)
// Requires Input_Iterable<C> 
            // && Container<C>
            // && Equality_comparable<T>
/**
 * pre: first and last must point to an iterable, non-empty container
 * post: return a number of occurrences of given value
 */
{
    std::ptrdiff_t res{};
    while (first != last)
    {
        if (val == *first)
        {
            ++res;
        }
        ++first;
    }
    return res;
}

with this command:

em++ -std=c++14 -Wall -pedantic -flto=thin --emrun -s EXPORTED_FUNCTIONS="['_use_count', '_main']" -s WASM=1 main.cpp -o index.js

but got this error:

shared:ERROR: undefined exported function: "_use_count"

and before I tried this:

em++ -std=c++14 -Wall -pedantic -flto=thin --emrun -s EXPORTED_FUNCTIONS="['my::_count', '_use_count', '_main']" -s WASM=1 main.cpp -o index.js

and had this error:

shared:ERROR: undefined exported function: "_my::count"

What's the problem? What am I doing wrong?

wontfix

Most helpful comment

C++ functions use "name mangling" on the exported symbol name, which iirc doesn't get handled for you when referencing a function with ccall etc.

Generally to export a C++ function you would do one of two things:

  • create a C-style exported function in an extern "C" block, which will not have its name mangled. Then call it directly or with ccall etc.
  • use embind or WebIDL to create a structured interface on top of the raw wasm function export

Embind has some basic docs on the emscripten.org site, though it can be esoteric sometimes. I'm less familiar with webidl myself.

As for types -- ptrdiff_t should be equivalent to an int (32-bit, signed).

All 14 comments

my::_count would not be a valid JS name, so I don't think it can be a valid exported function name. I'm not sure how embind handles that - looking for examples of similar things in the test suite is probably the best idea.

In general when you get stuck on something like this, I'd find code in the test suite that is similar, since it's known to work, and then change it step by step to be like your code, and then if it breaks at some point you can have a good idea of why.

_my::count didn't work, either. And _use_count also didn't get exported.

What test programs use exported functions? I guess I'll start there.

@kripken : I tried to export my::count before, when I hadn't put EMSCRIPTEN_KEEPALIVE before the function prototype. And right now the problem is that it's saying that _use_count is an undefined exported function.

@kripken I was trying to port this code to WebAssembly there:

// Osman Zakir
// 12 / 19 / 2017
// Bjarne Stroustrup: Programming: Principles and Practice Using C++ 2nd Edition
// Chapter 21 Exercise 3
// This program implements a custom count algorithm and tests it
// Exercise Specifications:
/**
 * Implement count() yourself. Test it.
 */

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <list>
#include <stdexcept>
#include "../../cust_std_lib_facilities.h"

namespace my
{
    template<typename Input_Iter, typename T>
    std::ptrdiff_t count(Input_Iter first, Input_Iter last, const T &val);
}

int main()
{
    std::vector<int> myvec{1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 9, 9, 10, 10, 10};
    constexpr int key = 3;
    auto num_occur = std::count(myvec.begin(), myvec.end(), key);
    auto num_occur2 = my::count(myvec.begin(), myvec.end(), key);
    std::cout << "Number of occurrences of " << key << " in myvec using std::count is " << num_occur
        << " and is " << num_occur2 << " using my::count\n";
    keep_window_open();
}

template<typename Input_Iter, typename T>
std::ptrdiff_t my::count(Input_Iter first, Input_Iter last, const T &val)
// Requires Input_Iterable<C> 
            // && Container<C>
            // && Equality_comparable<T>
/**
 * pre: first and last must point to an iterable, non-empty container
 * post: return a number of occurrences of given value
 */
{
    std::ptrdiff_t res{};
    while (first != last)
    {
        if (val == *first)
        {
            ++res;
        }
        ++first;
    }
    return res;
}

The function keep_window_open keeps the console window open until the user enters a key. It's to prevent the program from immediately exiting like it does if you run the executable by double-clicking the .exe on Windows. Without it, if the program just prints something to the screen, it'll just flash in front of your eyes and then exit. I took it out when porting the code because it's not needed here.

Besides, as I said in another issue I opened, it thinks I'm trying to precompile headers if I have just one header file as input and doesn't allow me to have more than .cpp file. cust_std_lib_facilities.h has a .cpp file that I'd need to include in the compilation.

Anyway, I need to know what test to look at for this. Any help here, please? Thanks in advance.

How should I call my::count in JavaScript? And with it being of type std::ptrdiff_t, what type do I give it when calling with ccall (assuming I export it with -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']")? And if I just try to add it in EXPORTED_FUNCTIONS, what name should I give it? It's the function count inside namespace my, hence my::count.

Note: I've changed the ported code to this:

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <list>
#include <stdexcept>
#include <emscripten/emscripten.h>

#undef SDL_MAIN

namespace my
{
    template<typename Input_Iter, typename T>
    std::ptrdiff_t EMSCRIPTEN_KEEPALIVE count(Input_Iter first, Input_Iter last, const T &val);
}

int main()
{
    std::vector<int> myvec{1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 9, 9, 10, 10, 10};
    constexpr int key = 3;
    auto num_occur = std::count(myvec.begin(), myvec.end(), key);
    auto num_occur2 = my::count(myvec.begin(), myvec.end(), key);
    std::cout << "Number of occurrences of " << key << " in myvec using std::count is " << num_occur
        << " and is " << num_occur2 << " using my::count\n";
}

template<typename Input_Iter, typename T>
std::ptrdiff_t my::count(Input_Iter first, Input_Iter last, const T &val)
// Requires Input_Iterable<C> 
            // && Container<C>
        // && Equality_comparable<T>
/**
 * pre: first and last must point to an iterable, non-empty container
 * post: return a number of occurrences of given value
 */
{
    std::ptrdiff_t res{};
    while (first != last)
    {
        if (val == *first)
        {
            ++res;
        }
        ++first;
    }
    return res;
}

Any help is appreciated. Thanks in advance.

C++ functions use "name mangling" on the exported symbol name, which iirc doesn't get handled for you when referencing a function with ccall etc.

Generally to export a C++ function you would do one of two things:

  • create a C-style exported function in an extern "C" block, which will not have its name mangled. Then call it directly or with ccall etc.
  • use embind or WebIDL to create a structured interface on top of the raw wasm function export

Embind has some basic docs on the emscripten.org site, though it can be esoteric sometimes. I'm less familiar with webidl myself.

As for types -- ptrdiff_t should be equivalent to an int (32-bit, signed).

Is C++17 not supported by Embind at all? The documentation for Embind on the Emscripten website says that most C++ constructs, including those in C++11 and 14, are supported, but there's no mention of C++17. It could just be because C++17 wasn't published yet, but I still want confirmation.

Anyway, is this fine now?

#include <iostream>
#include <iterator>
#include <algorithm>
#include <string>
#include <vector>
#include <list>
#include <stdexcept>
#include <emscripten/emscripten.h>

#undef SDL_MAIN

using namespace emscripten;

namespace my
{
    template<typename Input_Iter, typename T>
    std::ptrdiff_t count(Input_Iter first, Input_Iter last, const T &val);
}

int main()
{
    std::vector<int> myvec{1, 1, 1, 2, 2, 3, 3, 3, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 9, 9, 10, 10, 10};
    constexpr int key = 3;
    auto num_occur = std::count(myvec.begin(), myvec.end(), key);
    auto num_occur2 = my::count(myvec.begin(), myvec.end(), key);
    std::cout << "Number of occurrences of " << key << " in myvec using std::count is " << num_occur
        << " and is " << num_occur2 << " using my::count\n";
}

template<typename Input_Iter, typename T>
std::ptrdiff_t my::count(Input_Iter first, Input_Iter last, const T &val)
// Requires Input_Iterable<C> 
        // && Container<C>
        // && Equality_comparable<T>
/**
 * pre: first and last must point to an iterable, non-empty container
 * post: return a number of occurrences of given value
 */
{
    std::ptrdiff_t res{};
    while (first != last)
    {
        if (val == *first)
        {
            ++res;
        }
        ++first;
    }
    return res;
}

EMSCRIPTEN_BINDINGS(module)
{
    function("my::count", &my::count);
}

and

<!DOCTYPE html>
<html lang="en-us">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Custom count() Function Test in WebAssembly</title>
</head>
<body>
    <script>alert('check console (by pressing F12 key and clicking on "Console")');</script>
    <script async src="index.js"></script>
    <button class="button">Run Custom count Function</button>
    <script>
        document.querySelector('.button').addEventListener('click', function () {
            alert('check console');
            var result = Module.ccall('my::count', // name of C++ function 
                Number, // return type
                null, // argument types
                null); // arguments
        });
    </script>
</body>
</html>

I got the idea for this on MDN website, by the way (the alert and ccall call).

When I try to compile my C++ using:

em++ --bind -std=c++14 -Wall -pedantic -s NO_EXIT_RUNTIME=1 -s WASM=1 -s EXTRA_EXPORTED_RUNTIME_METHODS="['ccall']" main.cpp -o index.js

now, I get this error:

main.cpp:55:2: error: no matching function for call to 'function'
        function("my::count", &my::count);
        ^~~~~~~~
C:\emscripten\system\include\emscripten/bind.h:424:10: note: candidate template ignored: couldn't infer template
      argument 'ReturnType'
    void function(const char* name, ReturnType (*fn)(Args...), Policies...) {
         ^
1 error generated.

What's the problem? I looked at this example:

// quick_example.cpp
#include <emscripten/bind.h>

using namespace emscripten;

float lerp(float a, float b, float t) {
    return (1 - t) * a + t * b;
}

EMSCRIPTEN_BINDINGS(my_module) {
    function("lerp", &lerp);
}

C++17 should work, using -std=c++17, in current versions of emscripten.

I think you're getting the bit about function not being defined because you didn't #include <emscripten/bind.h>?

One further problem -- it's still not going to come up as defined because the parameters don't match any of the possible parameter types for function():

You don't actually have a my::count() function here; you have a template<I,T> my::count() template which can define multiple functions instantiated at compile time, and can't be referenced with a single function pointer.

I think you need a more concrete function here that can be referenced as a symbol. If you need to accept multiple different types, you either need multiple specific entry points that accept a specific concrete type, or a single generic entry point that accepts any type (for instance by accepting a val which can be any JavaScript value) and converting or behaving differently depending on the type.

I #included emscripten/bind.h. I think the problem is more what you mentioned in that last comment.

Are you saying I need to use val on the C++ side? So would that be inside the binding definition? Please give an example of this.

By the way, I'm just trying to use Embind for practice here. I don't really need it for this particular program since it already works without it. The stuff that should be in the browser's console window is already there. I need some help in understanding how to use Embind, though. For example, when using it to bind classes. I don't understand what functions to bind with .function, with .class_function, with .property, etc., as needed. And it says in the docs for Embind that it has built-in support for std::unique_ptr. But I still at least need an example for how to use it. Would be great if there are tests in the Emscripten distribution that show all of this for Embind. If there are some, which of the tests are they?

To add: I can't use ccall. When I try to use it in my JavaScript code, the browser console says that Module.ccall isn't a function. And yes, I did export it using the EXTRA_EXPORTED_RUNTIME_METHODS setting on the em++ command line. Please help me out on this too.

There are test cases for embind in https://github.com/kripken/emscripten/tree/incoming/tests/embind which should help you see a few usage examples.

In general, the functions you want to bind to will be some sort of concrete function (not a template!), and can be either member functions on a class instance or free functions. They should take parameters and return values of types that are known by embind -- again, concrete types not templates (so for instance a concrete type of a templatized class like Foo<Bar> is ok, but you can't make a binding that's generic itself).

As for ccall, it works fine in my testing with current emscripten 1.38.21. Can you provide a runnable test case where it's missing? Double-check that Module itself is initialized etc at the time you're calling it.

If you don't need the full binding system and just need to pop pointers in as parameters and get a ptrdiff_t out, then ccall (or even direct calling the exported symbol) should be fine as long as it can find the symbol -- this usually means for C++ declaring the function as extern "C" something like: (This again means using concrete types on the interface.)

extern "C" {
  // Declare this so it's exported as non-mangled symbol "_mycount"
  ptrdiff_t mycount(int *start, int *end, int val);
}

// Now implement it
ptrdiff_t mycount(int *start, int *end, int val);
{
  // ...
}

Note that exported symbol has a _ at the front, per typical C convention.

You can then either call it as Module._mycount(start, end, val) or via ccall: Module.ccall("mycount", "number", ["number", "number", "number"], [start, end, val]). Direct call is more efficient if you don't need the possible conversions/marshalling, such as a case here where you just take pointers.

If you need this function to be generic from JS calls, then you'll have to do some footwork to do runtime type detection and dispatch to something like your templatized my::count that took iterators.

For val, see notes at https://kripken.github.io/emscripten-site/docs/porting/connecting_cpp_and_javascript/embind.html#embind-val-guide for starters. val can hold any JavaScript value, including embind wrappers for C++ objects, so it should be possible to do runtime type checking that way if you need it.

If I declare it as an extern "C" function, can it have C++ inside the definition? My current function has code that won't compile in plain C after all.

I tried to implement the hello3.c example at the MDN website, and that's where I had that error in the console. Doesn't that code declare the Module object before calling ccall?

I need to know of a way to make a completely generic function work with Embind. If possible. Or maybe I can make it work by putting EMSCRIPTEN_KEEPALIVE before the function name but after the type?

This issue has been automatically marked as stale because there has been no activity in the past year. It will be closed automatically if no further activity occurs in the next 7 days. Feel free to re-open at any time if this issue is still relevant.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ShawZG picture ShawZG  路  4Comments

yahsaves picture yahsaves  路  4Comments

HolgerStrauss picture HolgerStrauss  路  4Comments

JCash picture JCash  路  3Comments

hcomere picture hcomere  路  3Comments