I'm trying to learn how to compile CPP into WASM and I can't seem get it to work properly.
I have a simple CPP code that implements a squarer function which squares a given integer:
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
int EMSCRIPTEN_KEEPALIVE squarer(int num) {return num * num;}
I can compile this into WASM but when I try to load it in JS it says there are no exported functions.
Looking at the WAT version (by running wasm2wat from wabt) it is clear that the problem is that the squarer function is not being exported.
(module
(type $t0 (func (param i32) (result i32)))
(import "env" "__linear_memory" (memory $env.__linear_memory 0))
(import "env" "__indirect_function_table" (table $env.__indirect_function_table 0 funcref))
(func $_Z7squareri (type $t0) (param $p0 i32) (result i32)
(i32.mul
(local.get $p0)
(local.get $p0))))
So I tried to compile again with the EXPORTED_FUNCTIONS flag (see the following line), but I get the following warning and the squarer function is still not being exported.
$ emcc squarer.cc -o squarer.wasm -c -O1 -s EXPORTED_FUNCTIONS="_Z7squareri","squarer"
emcc: warning: linker setting ignored during compilation: 'EXPORTED_FUNCTIONS' [-Wunused-command-line-argument]
When I edited the WAT to include an export (by changing func $_Z7squareri to func (export "squarer")) and compiled it back to WASM the JS successfully loaded the function, so it seems that the missing export really is the problem.
I tested it on two linux machines (one running ubuntu 20.04 and the other 18.04, both with the latest version of emsdk downloaded from their github as per the instructions in the MDN website).
I also tried using all of the other emcc flags with "EXPORT" in them but they all got the same warning.
This is my first time building a WASM module, and I learned everything from the internet so I might have missed some crucial step. Am I doing it wrong?
Am I using outdated tools?
Is there a better / newer CPP to WASM compiler I should be using?
Thanks!
Ittai
The -c command line option produces a wasm object file which is not designed to be executed directly. You need to then link that object file using emcc (without -c) to get the final binary.
You can do both compiling and linking in single command by simply removing the -c from the example command line you give above.
If you use EMSCRIPTEN_KEEPALIVE you don't need EXPORTED_FUNCTIONS on the command line as they serve the same purpose.
Related
I'm running g++ compiler on windows 10 with mingw.
On checking compiler version in cmd I get the following:
g++ --version- g++ (MinGW.org GCC Build-2) 9.2.0
same with c++ --version
When I compiled a cpp program making use of structured bindings I got a warning:
warning: structured bindings only available with '-std=c++17' or '-std=gnu++17'
But otherwise the code ran fine.
Does everyone get this warning or am I running a lower version compiler?
I'm using an extension - Competitive programming helper, and this warning interrupts the process.
Hence, if it is the case that everyone gets this warning, is there a way I can block version specific warnings only without having to block all compiler warnings.
TIA.
As the warning itself says:
structured bindings only available with '-std=c++17' or '-std=gnu++17'.
Meaning, you are using cpp version 14 or lower as compiler. However, you also have cpp 17 or higher installed on your system to get such kind of warning.
Your program will still run but with the warning.
For Windows:
If you are using VS code (assuming that you are already using code runner) then,
Open Settings(UI) of VS code (Ctrl + ,)
Search for Code-runner: Executor Map
Click on Edit in settings.json
Something like this will appear:
In cpp section: change it to "cd $dir && g++ -std=c++17 $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt" as in the picture above.
It is finally done now.
Below steps are for linux.
Open .bashrc file using command sudo gedit ~/.bashrc in terminal.
In the .bashrc file, add alias g++="g++ --std=c++2a" at the end of the file.
This will always compile your file in cpp+20 version.
Once done, you will not get any warning.
Note:
It is not mandatory to use cpp+20. You can use any version you like.
Change the version according to this website
https://www.learncpp.com/cpp-tutorial/configuring-your-compiler-choosing-a-language-standard/
I have been reading the tutorials for the Ocaml language and for Jbuilder. The official tutorial indicates that one must compile Ocaml code using the '-g' flag with ocamlc in order to then run ocamldebug.
I cannot find any mention of debug builds on the Jbuilder documentation. The only section that seems close is https://jbuilder.readthedocs.io/en/latest/jbuild.html#ocaml-flags. However, even if I add '-g' as a compilation flag..
(executable
((name [REDACTED])
(public_name [REDACTED])
(libraries ([REDACTED]))
(flags (:standard -w -9+27-30-32-40#8
-safe-string
-linkall
-g))
(modules ([REDACTED]))))
..I still don't seem to get a debug binary:
$ ocamldebug [REDACTED]
OCaml Debugger version 4.04.2
(ocd) r
Loading program... [REDACTED] is not a bytecode file.
Am I doing something wrong? If not, what is the recommended way to produce debug builds from jbuilder?
ocamldebug only works with bytecode builds. You're producing native code. To create a bytecode build, you can invoke jbuilder using prog.bc instead of prog.exe.
Note that this might not be what you're after: you can also debug native programs using plain old gdb, but you'll need to be a bit familiar with the runtime.
I upgraded my ocaml to 4.03.0.
Then, some wrapper libraries failed to build raising "No implemntations provided" Error.
I prepare a small example to explain my situation.
I write a C code in hello_stubs.c
#include<stdio.h>
#include<caml/mlvalues.h>
CAMLprim value caml_print_hello(value unit)
{
printf("Hello\n");
return Val_unit;
}
Next, I prepare the interface file for ocaml, in hello.mli.
external print_hello : unit -> unit = "caml_print_hello"
Then, I code a main program in main.ml
Hello.print_hello();;
To compile these programs, I executed the following commands.
ocamlc -c hello.mli
ocamlc -c hello_stubs.c
ocamlopt -o main main.ml hello_stubs.o
Then, unfortunately, the last command failed with the following error message.
File "_none_", line 1:
Warning 58: no cmx file was found in path for module Hello, and its interface was not compiled with -opaque
File "main.ml", line 1:
Error: No implementations provided for the following modules:
Hello referenced from main.cmx
According to the message,
I've tried ocamlc -opaque hello.mli, but it didn't solve the problem.
I also confirmed that the commands above work fine for ocaml 4.02.3.
Do you know how to compile this example with ocaml 4.03.0?
The fix is easy: create hello.ml of the same contents of hello.mli and compile it and link for main.
I guess this is due to the following change of 4.03.0:
PR#4166, PR#6956: force linking when calling external C primitives
(Jacques Garrigue, reports by Markus Mottl and Christophe Troestler)
The related section of the reference manual should be updated. See http://caml.inria.fr/mantis/view.php?id=7371
I am having trouble compiling Fortran code with references to DISLIN. I have downloaded DISLIN from the website, unzipped the file and ran the setup. I have added an environment variable called DISLIN (C:\dislin) and added C:\dislin\win to the PATH section of my system variables.
I am trying to compile some example code of the DISLIN website which includes line
USE DISLIN
I am using a MinGW shell to compile with command gfortran -o progrname -ldislin EX11_1.f90 and am getting the following error:
Fatal Error: Cant open module file 'dislin.mod' for reading at (1): No such file or directory.
I have tried changing the variable path and even moving the dislin.mod file (which is there) but still get the same message.
Ok I fixed this problem so thought I come back and post what worked for me incase any one else needs it...
Install both DISLIN and MinGW on the c drive
Copy disgf.a from /c/dislin and dislin.f90 from /c/dislin/gf into the directory containing your fortran files
(for me this is /c/MinGW/pnote)
Using the MinGW shell navigate to you files: cd /c/MinGW/pnote
compile dislin.f90 and your fortran program: gfortran -c dislin.f90 progName.f90 (dislin.f90 obviously only needs to be done once)
link libraries etc and compile: gfortran progName.o disgf.a -luser32 -lgdi32 -lopengl32 -o exeName
'run' exeName
You probably need to specify the path to the DISLIN module files:
gfortran EX11_1.f90 -o progrname -ldislin -I/path/to/DISLIN/modules
and, if not already configured like described here, also the path to the library itself:
gfortran EX11_1.f90 -o progrname -ldislin -I/path/to/DISLIN/modules \
-L/path/to/DISLIN/library
They provide a batch file (windows) to do the compiling and linking for you.
f90link -c My_Program
This is located in c:\dislin\Win
Also, if you are having trouble with the dislin.mod file which resides in c:\dislin\gf then recompile that with the -c compile option. I found all of this info in c:\dislin\readme.inf
near as I can tell (Jan 2018) dislin (64 bit) fails miserably with gfortran 7.2, period; and probably with many other newer compilers.
When trying to link, gfortran 7 says 'dislin.mod' is an unrecognizable format.
I think this program is highly dependent on exactly correct version synchronization - something that renders such software useless imho after many years in research.
and no, the correctness of various 'paths' seems not to help.
after all, gnuplot works, "at all". Not sure why I spent so much time on brand x.
jrc
I'm using vmware's web application api in an attempt just to simply retrieve the fields in the "ServiceContent" object. There is an example of how this should be accomplished located at the vmware forum. The example contained there compiles fine for me however I get segfaults when running the simple example - specifically the trace goes back to the soap_serializeheader() function (I believe these are defined in stdsoap2.cpp). My problem is that I do not know how to avoid this segfault and have no idea why this is occurring (as I am following the example almost word for word). I am using OS X tool chain (gcc version 4.0.1 (Apple Inc. build 5465) ) combined with (gsoap release 2.7.16). I tried gsoap 2.8 but got the same result. Below is the procedure I used to get to where I am now.
These are the commands I used to parse the wsdl:
wsdl2h -o vim25.h vimService.wsdl
Once this is parsed, I compiled using the following command:
soapcpp2 -x -C -pvsp vim25.h -I/place/where/stlvector.h/is
this generates files vspC.cpp, vspClient.cpp, and vspVimBindingProxy.cpp. Internally these files have the same prefixes for functions (i.e. ns1/ns2 etc) so my calls are the same as those in the example.
This is the command I am using to compile vspC.cpp and vspClient.cpp:
g++ -DWITH_COOKIES -DWITH_OPENSSL -c vspC.cpp
g++ -DWITH_COOKIES -DWITH_OPENSSL -c vspClient.cpp
This is the command I use to compile stdsoap2.cpp (if I do not compile with -DWITH_NONAMESPACES I get an error about an undefined symbol "_namepspaces" when I link everything):
g++ -DWITH_COOKIES -DWITH_OPENSSL -DWITH_NONAMESPACES -c stdsoap2.cpp
I then link everything together with the test code (again this is copied almost identically from the example, just with the changes to correctly refer to the files I created):
g++ -DWITH_COOKIES -DWITH_OPENSSL vspC.o vcpClient.o stdsoap2.o testcase.cpp -lssl -lcrypto -o doesntwork
This compiles correctly, but of course fails to run. I read about an OS X user in this vmware forum post who was also having trouble. It appears the gsoap guide says you cannot use stdsoap2.cpp's header and fault serialization codes, and you must compile them separately. The user in the OS X post seems to have done this, however I am not sure how to incorporate them into my test file (he creates the empty env.h file and then compiles it with soap2cpp) - if I include the envH.h file i get about naming conflicts with vspH.h. So a second question would be how do I use soap2cpp to compile all the stubs correctly so that there are not namespace conflicts (which is what I appear to be encountering).
I will not provide the source, as it is displayed at the first vwmare forum link by user stumpr. I do not believe the issue is in the source, but in the way I have used either wsdl2h, soap2cpp, or some incorrect combination of flags during compilation with g++.
Thanks for taking a look, and hopefully some one can resolve the issue!
EDIT I think I may have solved this - by using a 64bit system (and one with more memory). I tried compiling with -m32 on the X.6 and it was not able to do it (complaining about memory issues).
Hopefully someone will stumble upon this and be happy to know the answer.