将 Boost 与 Emscripten 结合使用

Using Boost with Emscripten

本文关键字:结合 Emscripten Boost      更新时间:2023-10-16

我有一个 c++ 项目,我想转换为 Web 应用程序。为此,我想使用 Emscripten 来构建项目。

该项目使用一些外部库。我设法编译或找到了大多数库的JavaScript版本,现在我被Boost版本困住了。实际上,我什至不知道如何开始Boost:他们使用boostrap脚本来生成文件以构建库。可以将工具集传递给此脚本,但显然不支持 Emscripten。

我的项目使用Boost的以下部分:线程,正则表达式,文件系统,信号,系统。如何使用 Emscripten 编译这些库?

编辑

按照 npclaudiu 的回答,我使用 gcc 工具包引导库,然后我编辑project-config.jam来配置编译器,替换:

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc ;
}

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : : "/full/path/to/em++" ;
}

现在,键入./b2可以有效地构建库。Boost.Signals和Boost.System编译得很好。其他人有一些错误。

Boost.Thread抱怨:

libs/thread/src/pthread/thread.cpp:503:27: error: use of undeclared identifier 'pthread_yield'
        BOOST_VERIFY(!pthread_yield());
                      ^

Boost.Regex抱怨很多关于未声明CHAR_BIT,但这似乎是emscripten中的一个问题:

In file included from libs/regex/build/../src/c_regex_traits.cpp:28:
In file included from ./boost/regex/v4/c_regex_traits.hpp:26:
In file included from ./boost/regex/v4/regex_workaround.hpp:35:
/path/to/emscripten/system/include/libcxx/vector:1989:92: error: use of undeclared identifier 'CHAR_BIT'
static const unsigned __bits_per_word = static_cast<unsigned>(sizeof(__storage_type) * CHAR_BIT);
                                                                                       ^

Boost.FileSystem似乎也由于emscripten而失败:

In file included from libs/filesystem/src/windows_file_codecvt.cpp:21:
/path/to/emscripten/system/include/libcxx/cwchar:117:9: error: no member named 'FILE' in the global namespace
using ::FILE;
      ~~^

我终于设法用 emscripten 编译了所需的库。以下是我遵循的步骤。

Emscripten 中的更改

编辑system/include/libcxx/climits以添加以下定义(请参阅 http://github.com/kripken/emscripten/issues/531(:

#ifndef CHAR_BIT
# define CHAR_BIT __CHAR_BIT__
#endif
#ifndef CHAR_MIN
# define CHAR_MIN (-128)
#endif
#ifndef CHAR_MAX
# define CHAR_MAX 127
#endif
#ifndef SCHAR_MIN
# define SCHAR_MIN (-128)
#endif
#ifndef SCHAR_MAX
# define SCHAR_MAX 127
#endif
#ifndef UCHAR_MAX
# define UCHAR_MAX 255
#endif
#ifndef SHRT_MIN
# define SHRT_MIN (-32767-1)
#endif
#ifndef SHRT_MAX
# define SHRT_MAX 32767
#endif
#ifndef USHRT_MAX
# define USHRT_MAX 65535
#endif
#ifndef INT_MAX
# define INT_MAX __INT_MAX__
#endif
#ifndef INT_MIN
# define INT_MIN (-INT_MAX-1)
# define INT_MIN (-INT_MAX-1)
#endif
#ifndef UINT_MAX
# define UINT_MAX (INT_MAX * 2U + 1)
#endif
#ifndef LONG_MAX
# define LONG_MAX __LONG_MAX__
#endif
#ifndef LONG_MIN
# define LONG_MIN (-LONG_MAX-1)
#endif
#ifndef ULONG_MAX
# define ULONG_MAX (LONG_MAX * 2UL + 1)
#endif

system/include/libcxx/cwchar中添加以下行

#include <cstdio>

将 Boost 编译为共享库

正如 npclaudiu 所建议的,使用 gcc 工具包引导库。然后编辑project-config.jam以配置编译器并替换:

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc ;
}

# Compiler configuration. This definition will be used unless
# you already have defined some toolsets in your user-config.jam
# file.
if ! gcc in [ feature.values <toolset> ]
{
    using gcc : : "/full/path/to/emscripten/em++" ;
}

boost/config/posix_features.hpp,在67号线附近强制BOOST_HAS_SCHER_YIELD

然后编译库:./b2 thread regex filesystem signals system

将 Boost 编译为静态库

执行上述所有步骤,然后编辑tools/build/v2/tools/gcc.jam并替换:

toolset.flags gcc.archive .AR $(condition) : $(archiver[1]) ;

toolset.flags gcc.archive .AR $(condition) : "/full/path/to/emscripten/emar" ;

toolset.flags gcc.archive .RANLIB $(condition) : $(ranlib[1]) ;

toolset.flags gcc.archive .RANLIB $(condition) :
  "/full/path/to/emscripten/emranlib" ;

编译库:./b2 link=static variant=release threading=single runtime-link=static thread signals system filesystem regex

作为记录,Boost现在包含一个"emscripten"工具集,它(根据我的经验(使上述过程变得不必要。

使用时,boostrap boost 像往常一样,然后像这样使用 b2(或 bjam(编译:

b2 toolset=emscripten 

在较新版本的 emscripten 中,您只需使用端口添加 Boost 库即可。现在,只需将此标志添加到编译器链接器即可: -s USE_BOOST_HEADERS=1

如果您使用的是 CMake,则可以像这样添加标志:

set_target_properties(your_targets_name_here PROPERTIES COMPILE_FLAGS "-s USE_BOOST_HEADERS=1" LINK_FLAGS "-s USE_BOOST_HEADERS=1")

问题中的更多详细信息

您可以尝试配置将gcc指定为工具集的 Boost 库,因为 Emscripten 建议自己作为 gcc 的直接替代品。另外,我认为在这种情况下,最好将 Boost 构建为静态库。请记住,大多数 Boost 库都是仅标头的,因为它们只定义模板类/函数。

UPDATE for emsdk:

经过大量的试验和错误,我能够通过以下方式获得 emscripten 1.39 来编译 Boost 1.71:

安装 emsdk 如果您还没有从 https://emscripten.org/docs/getting_started/downloads.html

导航到 emsdk 安装文件夹并执行

./emsdk install latest && ./emsdk activate latest && source ./emsdk_env.sh

导航到要克隆提升存储库并运行的目录

git clone --recursive https://github.com/boostorg/boost.git

您可以添加参数 '--jobs N',其中 N 是克隆子模块的进程数(如果这样做,这将加快速度(。

cd boost

现在使用引导脚本创建提升构建可执行文件 b2

./bootstrap.sh

最后,由于您的 emsdk 已经从上述步骤中激活,因此您可以使用 emconfigure 构建 Boost,以配置所有内容,因为它需要调用 gcc 以使用 emscripten 代替

emconfigure ./b2 toolset=gcc --prefix=<directory_to_install_to> --build-dir=<directory_for_intermediate_build_files>

现在要将包含和库安装到您选择的前缀目录,请运行

emconfigure ./b2 toolset=gcc --prefix=<directory_to_install_to> --build-dir=<directory_for_intermediate_build_files> install
我不知道

您是否碰巧在常见问题解答中看到过这个特定问题,但如果您没有:

问。如何链接到 SDL、boost 等系统库?

答:包含在 emscripten 中的系统库 - libc、libc++ (C++ STL( 和 SDL - 在您编译时会自动包含(以及它们的必要部分(。与其他编译器不同,您甚至不需要 -lSDL(但 -lSDL 也不会受到伤害(。

其他不包含在 emscripten 中的库,如 boost,您需要自己编译并与程序链接,就像它们是项目中的模块一样。例如,看看BananaBread如何在libz中链接。(请注意,在 boost 的特定情况下,如果您只需要 boost 标头,则无需编译任何内容。

未包含的库的另一个选项是将它们实现为 JS 库,就像 emscripten 对 libc(减去 malloc(和 SDL(但不是 libc++ 或 malloc(所做的那样。请参见 EMCC 中的 --js-library。