使用Emscripten编译GMP/MPFR

6

好的,这件事让我疯了。我已经尝试了至少一个月,但网络上没有任何帮助。

我按照这个的步骤进行操作。即使我按照这些步骤进行,示例也无法正常工作,因为当我这样做时,会出现以下情况。

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

当我运行生成的complete.js文件时 -

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.

如果您需要稍微更好的浮点数精度,可以使用double.jsbigfloat库。也许您不需要将C++编译为JS。 - Pavel Melnikov
我的使用案例是一个非常深的曼德博集合缩放,因此稍微更好的精度在几次迭代后就会不够用。此外,我需要编译库提供的本地速度。 - Flarp
3个回答

10

以下说明适用于运行amd64 Debian Buster的主机。似乎GMP不再需要32位来与Emscripten配合使用(在任何情况下,32位的Emscripten似乎已经不再受支持?),但我仍然使用chroot以获得干净的环境。安装后,我的chroot占用了1.6GB的空间。但如果您可以避免使用它进行计算密集型代码,则我不建议使用它,在一个基准测试中,我的本地代码比在nodejs中运行的使用Emscripten编译的相同代码快15倍...

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 最新版

写作时,已安装以下版本:releases-upstream-b024b71038d1291ed7ec23ecd553bf2c0c8d6da6-64bitnode-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 ..

你好,世界

您最喜欢的程序使用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

我的朋友们! 你们的所有东西都能正常工作,太不可思议了。 只需在emcc命令中添加-I${HOME}/opt/include,一切都能按预期工作,非常感谢你们! - Chr

2
我发现要这样做,您需要使用32位机器。我有一台64位机器,所以我使用此教程将chroot进入32位文件系统。
之后,一切都很顺利。我正在使用GMP和MPFR制作Mandelbrot程序,并在GitHub上发布了编译脚本(以及程序本身)。这里是它。为您自己的项目进行适应。

2

我将其打包成了一个名为 gmp-wasm 的NPM库。您可以在源代码中找到可构建库的Docker化代码。它导出了低级函数和不可变的高级包装器:

<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>

使用低级函数:

<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>


一个异步的MATH库?为什么? - Dave Burton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接