Compiling GMP/MPFR with Emscripten
Asked Answered
T

3

6

Alright, this has been driving me insane. I've been trying this for at least a month, and no where on the internet is helping.

I followed the steps of this. Not even the example works when I do these steps, because when I do it, I get this.

bitcode ==> javascript
warning: unresolved symbol: __gmpz_cmp
warning: unresolved symbol: __gmpz_mul_ui
warning: unresolved symbol: __gmpz_submul_ui
warning: unresolved symbol: __gmpz_init_set_ui
warning: unresolved symbol: __gmpz_mul_2exp
warning: unresolved symbol: __gmpz_init
warning: unresolved symbol: __gmpz_fdiv_qr
warning: unresolved symbol: __gmpz_add

And when I run the resulting complete.js file -

missing function: __gmpz_init
-1
-1

/home/ubuntu/workspace/gmp.js/complete.js:117
      throw ex;
      ^
abort(-1) at Error
    at jsStackTrace (/home/ubuntu/workspace/gmp.js/complete.js:1045:13)
    at stackTrace (/home/ubuntu/workspace/gmp.js/complete.js:1062:22)
    at abort (/home/ubuntu/workspace/gmp.js/complete.js:6743:44)
    at ___gmpz_init (/home/ubuntu/workspace/gmp.js/complete.js:1744:56)
    at Object._main (/home/ubuntu/workspace/gmp.js/complete.js:4978:2)
    at Object.callMain (/home/ubuntu/workspace/gmp.js/complete.js:6627:30)
    at doRun (/home/ubuntu/workspace/gmp.js/complete.js:6681:60)
    at run (/home/ubuntu/workspace/gmp.js/complete.js:6695:5)
    at Object.<anonymous> (/home/ubuntu/workspace/gmp.js/complete.js:6769:1)
    at Module._compile (module.js:541:32)
If this abort() is unexpected, build with -s ASSERTIONS=1 which can give more information.
Tinsel answered 10/12, 2016 at 22:6 Comment(2)
If you need just slightly better precision of float number you can use double.js or bigfloat libraries. Maybe you don't need to compile c++ to js.Iridissa
My use case is a very deep Mandelbrot zoom, so slightly better precision falls short after a few iterations. Also, I need the native speed provided by compiled libraries.Tinsel
T
2

I found out to do it, you need to be using a 32 bit machine. I had a 64 bit machine so I chroot'ed into a 32 bit filesystem using this tutorial.

After that, everything worked well. I was making a Mandelbrot program using GMP and MPFR, and I posted the compiling script (along with the program itself) online on GitHub. Here it is. Adapt it for your own projects.

Tinsel answered 24/12, 2016 at 12:20 Comment(0)
A
10

These instructions are for a host running amd64 Debian Buster. It seems that GMP no longer needs 32bit to work with Emscripten (and in any case 32bit Emscripten seems no longer supported?), but I used a chroot for clean environment. After installing, my chroot was 1.6GB large. But I wouldn't recommend using it for compute-intensive code if you can avoid it, in one benchmark my native code was 15 times faster than the same code compiled with Emscripten running in nodejs...

Debian Buster chroot

mkdir emscripten
sudo debootstrap buster emscripten
sudo chroot emscripten /bin/bash
echo "deb http://security.debian.org/debian-security buster/updates main" >> /etc/apt/sources.list
apt update
apt install python cmake g++ git lzip wget nodejs m4
echo "none /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0" >> /etc/fstab
mount /dev/shm
echo "none /proc proc defaults 0 0" >> /etc/fstab
mount /proc
adduser emscripten
su - emscripten

emsdk latest

At time of writing this installed releases-upstream-b024b71038d1291ed7ec23ecd553bf2c0c8d6da6-64bit and node-12.9.1-64bit:

git clone https://github.com/juj/emsdk.git
cd emsdk
./emsdk install latest
./emsdk activate latest
source ./emsdk_env.sh
mkdir -p ${HOME}/opt/src
cd ${HOME}/opt/src

gmp 6.1.2

wget https://gmplib.org/download/gmp/gmp-6.1.2.tar.lz
tar xf gmp-6.1.2.tar.lz
cd gmp-6.1.2
emconfigure ./configure --disable-assembly --host none --enable-cxx --prefix=${HOME}/opt
make
make install
cd ..

mpfr 4.0.2

wget https://www.mpfr.org/mpfr-current/mpfr-4.0.2.tar.xz
wget https://www.mpfr.org/mpfr-current/allpatches
tar xf mpfr-4.0.2.tar.xz
cd mpfr-4.0.2
patch -N -Z -p1 < ../allpatches 
emconfigure ./configure --host none --prefix=${HOME}/opt --with-gmp=${HOME}/opt
make
make install
cd ..

mpc 1.1.0

wget https://ftp.gnu.org/gnu/mpc/mpc-1.1.0.tar.gz
tar xf mpc-1.1.0.tar.gz
cd mpc-1.1.0
emconfigure ./configure --host none --prefix=${HOME}/opt --with-gmp=${HOME}/opt --with-mpfr=${HOME}/opt
make
make install
cd ..

hello world

Your favourite program using GMP/MPFR/MPC:

emcc -o hello.js hello.c \
  ${HOME}/opt/lib/libmpc.a ${HOME}/opt/lib/libmpfr.a ${HOME}/opt/lib/libgmp.a
nodejs hello.js
Antifouling answered 24/4, 2017 at 8:24 Comment(1)
My men ! All your stuff work, incredible. Just add -I${HOME}/opt/include in the emcc command and all work as expected, thank you so much !Tutty
T
2

I found out to do it, you need to be using a 32 bit machine. I had a 64 bit machine so I chroot'ed into a 32 bit filesystem using this tutorial.

After that, everything worked well. I was making a Mandelbrot program using GMP and MPFR, and I posted the compiling script (along with the program itself) online on GitHub. Here it is. Adapt it for your own projects.

Tinsel answered 24/12, 2016 at 12:20 Comment(0)
C
2

I packaged it into a NPM library called gmp-wasm. You can find a Dockerized code which builds the library within the source. It exports both low-level functions and an immutable high-level wrapper:

<script src="https://cdn.jsdelivr.net/npm/gmp-wasm"></script>
<script>
  gmp.init().then(({
    calculate
  }) => {
    // calculate() automatically deallocates all objects
    // created within the callback function
    const result = calculate((g) => {
      const six = g.Float(1).add(5);
      const res = g.Pi().div(six).sin();
      return res;
    });
    document.write(`sin(Pi/6) = ` + result);
  });
</script>

Using low-level functions:

<script src="https://cdn.jsdelivr.net/npm/gmp-wasm"></script>
<script>
  gmp.init().then(({
    calculate, binding
  }) => {
    const result = calculate((g) => {
      const a = g.Float(1);
      const b = g.Float(2);
      const c = g.Float(0);
      // c = a + b
      binding.mpfr_add(c.mpfr_t, a.mpfr_t, b.mpfr_t, 0);
      return c;
    });
    document.write(`1 + 2 = ` + result);
  });
</script>
Cruiser answered 29/11, 2021 at 11:38 Comment(1)
An asynchronous MATH library? Why??Attila

© 2022 - 2024 — McMap. All rights reserved.