Sorry if it's not answering your question, but could you share the exact example on how to compile to emscripten ?
I know there's a thread about compiling to emscripten but it would be nice you could share it too.
@yglukhov Thanks, that makes sense, I can just call GC_step at the start of each emscripten_set_main_loop callback. By the way, thanks for writing jsbind, it has been very helpful! :)
@mashingan I copied most of the nim.cfg from here: https://forum.nim-lang.org/t/2991. Then follow the Emscripten installation instructions: https://kripken.github.io/emscripten-site/docs/getting_started/downloads.html (be sure to source ./emsdk_env.sh in the console before using the Nim compiler).
To compile, run something like nim c -d:emscripten -d:wasm -d:release -o:main-wasm.html main.nim and it will just.. work. If I have time, I'll put together a simple example repo.
FYI, I could only get it to work on Linux (or Windows Linux), the Windows command prompt had some issues.
To complete the picture: the generated HTML file should be run with emrun main-wasm.html.
To learn about GC behaviour in WASM, probably any Nim code for testing the GC (like the one from here) could be run in the browser. If someone already had some in-process code/method for e.g. detecting memory leaks for a 32-bit target, I would be interested.
@rpowers:, or anyone that has tried using Nim and Emscripten to generate asm.js and/or WebAssembly lately.
I am using the following on Windows:
I am sure that the referenced Nim capabilities used to work, but I am having problems with latest versions on Windows, as follows:
I have called emsdk_env.bat in the terminal window to initialize to the expected environment (using some outdated versions of python, java, and node) and have run the emcmdprompt.bat file to be sure this is done in the terminal, which then allowed C files to be compiled with Emscripten successfully.
I found and fixed one issue where the <io.h> header file was not being found in the /sys/ sub directory so a copied it one level up and that error went away.
Now, the new version of Nim seems to be missing a couple of declarations necessary to make emcc happy; the error messages are as follows:
Error: execution of an external compiler program 'emcc.bat -c -w -s WASM=0 -Iemscripten -IC:\nim-0.20.0\lib -I"D:\Haskell Stuff\NimEmscripten\src" -o C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c.o C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c' failed with exit code: 1
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:176:8: error: implicit declaration of function '_fileno' is
invalid in C99 [-Werror,-Wimplicit-function-declaration]
T1_ = _fileno(stdin);
^
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:176:8: note: did you mean 'fileno'?
C:\emsdk\fastcomp\emscripten\system\include\libc\stdio.h:135:5: note: 'fileno' declared here
int fileno(FILE *);
^
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:177:2: error: implicit declaration of function '_setmode' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
_setmode(T1_, _O_BINARY);
^
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:177:16: error: use of undeclared identifier '_O_BINARY'
_setmode(T1_, _O_BINARY);
^
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:181:16: error: use of undeclared identifier '_O_BINARY'
_setmode(T2_, _O_BINARY);
^
C:\Users\Gordon\nimcache\NimEmscripten_d\stdlib_io.nim.c:185:16: error: use of undeclared identifier '_O_BINARY'
_setmode(T3_, _O_BINARY);
^
5 errors generated.
shared:ERROR: compiler frontend failed to generate LLVM bitcode, halting
Looking at the Nim generated C code, these are valid error messages with the functions and _O_BINARY value not declared in the headers.
Am I doing something wrong or should an issue be filed?
The "native" JavaScript backend works, but I would like to compare the speed of outputting asm.js and WebAssembly. I have hand patched the "native' JavaScript file to find that one can get some perhaps 20% speed improvement by using the asm.js ">>> 0" and "| 0" constructs to force unsigned integer and signed integer (from double), respectively, and would like to see if the emscripten asm.js output shows the same gain, and also how much better the WebAssembly speed is if any, although I already know that it should be about 35% better speed from testing output from C using WebAssembly Studio (Beta) (tested on Chrome) and is up to about another twice as fast when using array pointer in Microsoft Edge 44.18362.1.0 than with Chrome due to better optimization of the pointer operations. Firefox is close to the same speed as Chrome (version 75) but perhaps 10% faster. Maximum native speed for this algorithm is about twice again as fast as Microsoft Edge.
I just want to see Nim be able to take advantage of this for web use.
Due to the changes in emscripten you mentioned, my own WASM example code now compiles and runs fine with the following simple nim.cfg:
@if emscripten:
cc = clang
clang.exe = "emcc"
clang.linkerexe = "emcc"
cpu = i386
@end
and this command line:
nim c -d:emscripten -d:release -d:danger -o:<progname>.html <progname>.nim
For ASM.js output,
-t:"-s WASM=0" -l:"-s WASM=0"
is inserted into the command line. I'm running Nim 0.20 and emscripten 1.38.38 on Linux 64bit, so your problem might be specific to Windows or to your code.
I doubt I have a program error as it won't compile "Hello World". The problem is likely with the Windows implementation, as I've seen referenced before. The thing is that Emscripten works fine from C/C++ code, so it seems the Nim is doing something when compiling in a Windows terminal.
I have MSYS2, so I can try running in that terminal. My machine is running out of System space, so I would prefer not to have to install WSL Linux, which I'm sure would work.
I don't think there is anything major wrong, Nim just needs some compiler options set to handle output to Emscripten.
2. Thanks to @yglukhov, we know we have to cross-compile to linux to make it work, especially for Windows, which was what I was missing. This can be used by putting the following "nim.cfg" file into your project directory:
@if emscripten:
cc = clang
@if windows:
clang.exe = "emcc.bat"
clang.linkerexe = "emcc.bat"
@else:
clang.exe = "emcc"
clang.linkerexe = "emcc"
@end
os = linux
cpu = i386
@if asmjs:
passC = "-s WASM=0"
passL = "-s WASM=0"
@end
@end
3. Call the nim compiler with the following for compilation to wasm:
nim c -d:emscripten -d:release -d:danger -o:./index.html -o:<path_to_output_file> <path_to_Nim_source_file>
or the following for compilation to asm.js:
nim c -d:emscripten -d:asmjs -d:release -d:danger -o:./index.html -o:<path_to_output_file> <path_to_Nim_source_file>
Use of wasm is generally at least a little faster than the use of even asm.js, but for many applications it may not be of "killer speed" considering that JavaScript engines such as Chrome's V8 already Just In Time (JIT) optimize "hot spots" in the code quite efficiently.
I haven't tried it yet but plan to but one of the most important reasons to use wasm instead of JavaScript or asm.js output is that one can do single web page multi-threading within the same page with shared data by using the new experimental feature that can be enabled in Chrome since version 70 (now up to version 77), if not other web browsers, (especially Firefox?). Finally, we should be able to make proper web page use of multi-threading and all the cores we have available even in smartphones!