省略一些 C++ 子系统

Omit some C++ subsystems

我注意到使用 emscripten,即使是相对较小的 C++ 文件也可以很快变成相当大的 JavaScript 文件。示例:

#include <memory>
int main(int argc, char** argv) {
  std::shared_ptr<int> sp(new int);
}

使用像

这样的命令用最近的 emsdk 编译它
em++ -std=c++11 -s DISABLE_EXCEPTION_CATCHING=1 -s NO_FILESYSTEM=1 \
     -s NO_BROWSER=1 -s NO_EXIT_RUNTIME=1 -O3 -o foo.js foo.cc

生成的文件超过 400k。加上 -g 我可以做到

grep -n '^function _' foo.js | c++filt -_

看看我们有哪些功能。以下是一些示例:

std::__1::moneypunct<char, false>::do_thousands_sep() const
std::__1::locale::~locale()
std::__1::basic_string<wchar_t, …>::~basic_string()
std::__1::time_get<…>::__get_day(…) const
std::__1::codecvt<wchar_t, char, __mbstate_t>::codecvt(unsigned int)
std::__1::locale::__imp::install(std::__1::locale::facet*, long)
_printf_core

我自己并没有调用任何一个,但是所有的功能都包含在内。可能其中很多都包含在某个虚函数中 table。其他的可能是由于一些静态初始化器。

如果这是针对我硬盘上某处的单个共享库链接的普通代码;我不会反对的。但是要传输 JavaScript 代码中的半兆字节,仅用于单个共享指针?必须有办法避免这种情况。

实施的一个解决方案 here 只是将 C++ 库分成几个部分。通过将处理 I/O 和区域设置的代码移动到一个单独的库中,所有可以在没有它的情况下工作的代码都可以避免 I/O 子系统的静态初始化程序导致对上述功能的依赖。不幸的是,这也会影响 strstream,原因很明显。


更新: 自上游 commit 301e4ad(首次包含在版本 1.30.6 中)以来,系统库不再编译为单个 *.bc 文件,而是作为包含几个不同对象的 *.a 静态库。其中,只有需要的才会真正链接进来,这大大减少了简单情况下的代码大小。