WebAssembly: Export namespace from C++ library to JavaScript - c++

I'm trying to port the lhslib library (written in C++) to WebAssembly using emscripten (emcc v. 1.40.1, clang v. 12.0.0, macOS 10.15.5). Unfortunately I have a very limited understanding of C++, so please bear with me.
So far, I forked the repo, created a build folder, and from there started to try and convert the randomLHS.cpp file to WASM:
// a short overview of what the file looks like
#include "LHSCommonDefines.h"
#include "utilityLHS.h"
namespace lhslib
{
void randomLHS(int n, int k, bclib::matrix<int> & result, bclib::CRandom<double> & oRandom)
{
// further contents of the file
}
}
Running
emcc ../src/lhslib/randomLHS.cpp -I../src/bclib -o randomLHS.html
creates the expected files randomLHS.wasm ,randomLHS.js, and randomLHS.html.
However, when serving the html file and inspecting the Module object created by emscripten, it does not contain the desired randomLHS function.
I then read about the EXPORTED_FUNCTIONS option and proceeded to try the following
emcc ../src/lhslib/randomLHS.cpp -I../src/bclib -o randomLHS.html -s EXPORTED_FUNCTIONS='["_randomLHS"]' -s EXPORTED_RUNTIME_METHODS='["ccall", "cwrap"]'
This results in the following error:
emcc: error: undefined exported function: "_randomLHS" [-Wundefined] [-Werror]
Unfortunately I couldn't find any examples showcasing how to export a namespace (as in the randomLHS file), or how to specify a function from the namespace that should be exported.
Could you guide me on how I could achieve this?
Thanks for you help!

So according to the emscripten docs on using ccall and cwrap:
These methods can be used with compiled C functions — name-mangled C++ functions won’t work.
I believe there are other ways to do this; check out WebIDL Binder and Embind.

Related

How to use standard library with Clang and LibTooling

I want to use Clang and LibTooling to create some C++ source analysis and transformation tools. I've built Clang and LibTooling following this tutorial, and I've been able to run and create some analysis tools and compile C++ programs using the Clang binary I built. However, if I include headers from the standard library (in either source files or my tools), I run into issues when compiling or running the source files/tools. For instance, if I run clang-check on the following C++ source file:
#include <iostream>
int main() {
std::cout << "Hello";
return 0;
}
I get "fatal error: 'iostream' file not found". (Note: I can compile C++ programs, e.g. ones with user-defined classes, just not C++ programs using the standard library.) In an attempt to resolve the issue, I built libc++ (following this guide, building it in the llvm/project directory where I built LLVM and Clang), but I'm still having trouble getting Clang and the tools to use libc++. Now, if I try to compile a test file using:
export CPLUS_INCLUDE_PATH="~/clang-llvm/llvm/projects/libcxx/include"
export LD_LIBRARY_PATH="~/clang-llvm/llvm/projects/libcxx/lib"
~/clang-llvm/llvm/build/bin/clang++ ~/Documents/main.cpp
Then I get "fatal error: 'unistd.h' file not found". So my question is this: how do I properly point Clang and my tools to use libc++?
I am running OS X Yosemite 10.10 and using Clang 3.6.0.
Clang comes with some custom includes. So usually you have clang in
/usr/bin/clang++
and the includes in
/usr/lib/clang/3.6.1/include
but clang looks for them as a relative path:
../lib/clang/3.6.1/include
so make sure this relative path is accessible from either the clang++ binary, or your libtooling application.
Include your tool into this:
#include "clang/Tooling/CommonOptionsParser.h" // For reading compiler switches from the command line
#include "clang/Tooling/Tooling.h"
static cl::OptionCategory MyToolCategory("SearchGlobalSymbols");
static cl::extrahelp MoreHelp("\nMore help text..."); // Text that will be appended to the help text. You can leave out this line.
/* Your code (definition of your custom RecursiveASTVisitor and ASTConsumer) */
/* Define class MyASTFrontendAction here, derived from ASTFrontendAction */
int main(int argc, const char **argv)
{
/* Your code */
CommonOptionsParser op(argc, argv, MyToolCategory); // Parse the command-line arguments
ClangTool Tool(op.getCompilations(), op.getSourcePathList()); // Create a new Clang Tool instance (a LibTooling environment)
return Tool.run(newFrontendActionFactory<MyASTFrontendAction>().get()); // Run custom Frontendaction
}
The CommonOptionsParser allows you to read commands from the command line that are passed to the compiler.
For example, you can now call your tool like this:
your-tool yoursourcefile.c -- -nostdinc -I"path/to/your/standardlibrary"
Everything after the double dash will be passed to the compiler. Possible flags are described here:
http://clang.llvm.org/docs/CommandGuide/clang.html
-nostdinc tells the Preprocessor not to look for standard include paths. You can specify you own paths instead after -I.
Hope it helped someone :) Ask me if I wasn't specific enough.
Did you move/rename any of the parent directories after building/installing? The compiler should have been configured to know where to look for its standard libraries without having to specify the environment variable paths.
Use homebrew and install llvm using the command
brew install llvm
Your problem should be solved.

C++ mangling name for use in Emscripten

I'm trying to compile a simple HelloWorld Prgramm from C++ to Javascript using emscripten.
It works fine when I include a main function which call's e.g. the multi function.
Here is my code (HelloWorld.cpp).
#include <stdio.h>
class HelloWorld {
public: void sayHello() {
printf("Hello World Klasse! %f", multi(7));
}
public: double multi(double x){
return x * x;
}
};
However if I don't include a main function the emcc compile always put's out
ERROR root: No functions to process. Make sure you prevented LLVM
from eliminating them as dead (use EXPORTED_FUNCTIONS if necessary,
see the FAQ)
I know about the 'EXPORTED_FUNCTIONS' option which tells what functions should be included into the compile .js file.
I tried various diffrent things:
Using the mangling name, as far as I understood this the name should be '_multi_d10HelloWorldd'. I also tried without classname and some other combinations.
emcc -s HelloWorld.cpp -s EXPORTED_FUNCTIONS='["_multi_d10HelloWorldd"]'
Using the modifier EXPORT_ALL
emcc -s HelloWorld.cpp -s EXPORT_ALL=1
Whatever I do the functions won't be included in the final js file.
From what I understand from the EMCC FAQ I need to use EXPORTED_FUNCTIONS so I can later on call the desired function e.g. 'sayHello' from JS unsing the same method name.
And this is exactly what I need to do later on.
Could someone please point me to a solution or any other possible option which I may have not thought of ?
Is the mangling name I thought of correct ?
Create an "extern c" block. Inside this block define the functions you want to expose to javascript. These functions should be prefixed with an underscore. Inside one of these functions you can instantiate your C++ class.
This is the same approach as one would take when writing a dynamic library, which has the advantage that you can reuse your library in a native program should you wish.

Unable to compile program with twitcurl

I want to compile a C++ program with a twitter library, on Linux.
I'm current using twitcurl as the twitter API library and installed g++ and all the necessary files and packages that are listed on the official website: http://code.google.com/p/twitcurl/wiki/WikiHowToUseTwitcurlLibrary
However, when I compile my program using this command g++ twitterClient.cpp -ltwitcurl, I get this error: cannot find -ltwitcurl
I also used CodeBlocks IDE to compile it but got this error: undefined reference to twitCurl::~twitCurl()
`
My code only contains a few lines:
#include <iostream>
#include "Twitter/Twitter.hpp"
using namespace std ;
int main ()
{
Twitter t ;
return 0 ;
}
I've already spent a lot of time on this but am unable to solve the problem. What should I do in order to compile the program on the command-line and CodeBlocks?
$ g++ twitterClient.cpp -ltwitcurl
cannot find -ltwitcurl
This means your compiler doesn't find the libtwitcurl.so.1. in its library directories.
First, make sure you correctly build the twitcurl library and obtained the libtwitcurl.so.1. file with something like this :
svn co http://twitcurl.googlecode.com/svn/trunk/libtwitcurl
cd libtwitcurl/
make
Secondly, make sure you put the file (or a symlink) in one of your compiler's library path :
cp libtwitcurl.so.1.0 /usr/lib/
You can check g++ library paths using the following command :
g++ --print-search-dirs | grep libraries
(/usr/lib/ is usually at the end.)
If you don't want/can't put the file in your compiler's library path, you can also tell it where to find libtwitcurl.so.1. by adding -L/path/to/twitcurl/ in the g++ options, but it is not needed if the file is already in one of the compiler's library path.
You need to specify path to twitter lib:
g++ twitterClient.cpp -L/path/to/lib/dir -ltwitcurl

Strange error when adding #include <string>

I have the following very simple application that compiles and runs fine:
EDIT: changed the example to be simpilar to end confusion of the real issue
int main() {
return 0;
}
As soon as I add #include <string> (and not even reference std::string), it fails to compile and I get the following error:
/usr/include/c++/4.1.2/bits/allocator.h:82 error: expected template-name before '<' token
Along with about 456 other, similar errors.
Any ideas? Thanks!
UPDATE:
Line 82 of /usr/include/c++/4.1.2/bits/allocator.h references the template __glibcxx_base_allocator at the location of the error. That template is defined in bits/c++allocator.h. When I search the system for that file, I get 3 hits, but none of them are in /usr/include/c++/4.1.2/bits/ as one would expect.
I have version 3.1.6, 4.1.1, and 4.3.2, but not 4.1.2 as the rest of the includes I am using. I am not sure which one is being used (if any, however, I don't get any error for an unknown file), but it seems the problem may stem from this.
The problem appears to be the installed development packages are not correct or incomplete (not to be confused with corrupt). Forcing g++ to use different include versions corrects that:
g++ -nostdic++ hello.cc -o hello -I/usr/include/c++/3.4.6
All the alternative directories (4.1.1, 4.1.2 and 4.3.2) are incomplete causing inappropriate files to be included causing the unusually errors. For example:
/usr/include/c++/4.1.2/bits/allocator.h requires __glibcxx_base_allocator located in bits/c++allocator.h which is being included from either /usr/include/c++/4.1.1 or /usr/include/c++/4.3.2 and appear to be incompatible. Forcing the compiler to use the only complete set of includes rectifies this.
Almost certainly g++ is detecting .cc as a C source file, not C++ and passes it through to gcc instead of compiling as C++. You can easily test by renaming your file to hello.C. There's also a language parameter to g++ you can use.
EDIT: This seems to work fine in g++ 4.2 with a .cc extension so that might not be it. Do you have any other headers included you aren't showing us? They could be interfering with <string>.
EDIT2: Alternatively your headers might not be set up right. Does this work:
#include <string>
int main()
{
return 0;
}
Errors like this have been heard of to occur when the C++ standard library headers are corrupted/not fully installed – maybe there is even a message referring to a missing include among your 456 other errors.
In any case, make sure that libstdc++-devel, resp. the package containing the C++ standard library header files of your distribution, is properly installed.
Check your include path. The paths can be specified as environment variables or specified on the command line. You could be using an include file from a different compiler or different version of the same compiler.
Also, try using <cstdio> rather than <stdio.h>.
Another suggestion: change <> to "".
This could be error caused at preprocess stage. Just preprocess your cpp file by passing flag -E to gcc and Look at the place the compiler complains.

Import C++ function into Python program

I'm experimenting with python functions right now. I've found a way to import python functions into c/c++ code, but not the other way around.
I have a c++ program written and it has a certain function in it. I'd like to "import" the compiled c++ program into my python script and call the c++ function.
For simplicity, say the c++ function is as simple as:
int square(x)
{
return x*x;
}
and the compiled program is named Cprog.
I'd like my python script to be something like:
import Cprog
print Cprog.square(4)
Is this possible? I've searched the internet to no avail and I'm hoping one of you gurus might have a clever way of going about this...
Here is a little working completion of the simple example above. Although the thread is old, I think it is helpful to have a simple all-embracing guide for beginners, because I also had some problems before.
function.cpp content (extern "C" used so that ctypes module can handle the function):
extern "C" int square(int x)
{
return x*x;
}
wrapper.py content:
import ctypes
print(ctypes.windll.library.square(4)) # windows
print(ctypes.CDLL('./library.so').square(4)) # linux or when mingw used on windows
Then compile the function.cpp file (by using mingw for example):
g++ -shared -c -fPIC function.cpp -o function.o
Then create the shared object library with the following command (note: not everywhere are blanks):
g++ -shared -Wl,-soname,library.so -o library.so function.o
Then run the wrapper.py an the program should work.
If you build your program as a shared library/DLL, you could use ctypes to call it.
import ctypes
print ctypes.windll.cprog.square(4) # windows
print ctypes.CDLL('cprog.so').square(4) # linux
You need to create a python module with that function in it. There are three main ways:
Using Swig - this reads your c code and creates a python module from it.
Hand coded using the python c api.
Using Boost::Python (often the easiest way).
This pdf covers 1 and 2. This page will tell you how to use Boost::Python.
You cannot (easily) use a function that is in a c/c++ program - it must be in a static library (which you can also link your c/c++ program against).
EDIT -
Cython Is also worth a mention.
You want to extend python with a C/C++ module. The following Python documentation is a good place to start reading: http://docs.python.org/extending/extending.html
There are a lot of different ways to wrap C++ code to be used in Python. Most are listed on the Python wiki here.
I've found a decently easy way to automate it is to use py++ to automatically generate the wrappers, then compile the generated files. But this is more appropriate for larger projects where wrapping everything by hand is just not very feasible and would cause a maintenence nightmare.