我无法通过对内存和布局的完全控制来构建独立的Web程序集。我不想使用emscripten,因为,正如下面的帖子所述,它不能满足我所需的所有编译时选项(例如,堆栈大小控制,能够选择以独立模式导入内存等)。 )我一直关注以下页面:How to generate standalone webassembly with emscripten另外,emscripten太过分了。
到目前为止,我已经做了:我有一个可以通过自制软件下载的完全正常工作的llvm 9工具链(我在macOS 10.14上。)我正在混用https://aransentin.github.io/cwasm/和https://depth-first.com/articles/2019/10/16/compiling-c-to-webassembly-and-running-it-without-emscripten/我使用wasi来获取C标准库。使用-Wl,-z,stack-size=$[1024 * 1024]
这样的链接器标记,我可以控制堆栈的大小。编译成功。太好了!
但是,我需要使用C ++标准库来支持我自己的库和其他第三方库。据我所知,似乎没有任何简单的方法来获取libc ++和libc ++ abi。
我尝试了一个“ hack”,在其中下载了Emscripten,并让它构建了自己的libc ++和libc ++ abi文件。然后,我尝试将那些文件和标头复制到正确的位置。然后,我收到了有关缺少线程API的错误消息,这显然是由于未使用EMSCRIPTEN进行编译引起的。因此,我定义了EMSCRIPTEN宏并进行了这种工作。然后我以为也许可以删除wasi依赖项,并使用emscripten的libc版本保持一致,但随后也会出现冲突/缺少标头。
简而言之,我认为我已经接近需要的位置,但是事情变得非常混乱。我怀疑我采用了最简单的非脚本化方法。
有没有人成功地为独立的Webassembly创建了一个构建系统,可让您使用c和c ++标准库?
编辑:
这是我现在拥有的超级hacky构建脚本(它是我在网上找到的东西的重大修改版本:]
DEPS = OBJ = library.o STDLIBC_OBJ = $(patsubst %.cpp,%.o,$(wildcard stdlibc/*.cpp)) OUTPUT = library.wasm DIR := ${CURDIR} COMPILE_FLAGS = -Wall \ --target=wasm32-unknown-wasi \ -Os \ -D __EMSCRIPTEN__ \ -D _LIBCPP_HAS_NO_THREADS \ -flto \ --sysroot ./ \ -std=c++17 \ -ffunction-sections \ -fdata-sections \ -I./libcxx/ \ -I./libcxx/support/xlocale \ -I./libc/include \ -DPRINTF_DISABLE_SUPPORT_FLOAT=1 \ -DPRINTF_DISABLE_SUPPORT_LONG_LONG=1 \ -DPRINTF_DISABLE_SUPPORT_PTRDIFF_T=1 $(OUTPUT): $(OBJ) $(NANOLIBC_OBJ) Makefile wasm-ld \ -o $(OUTPUT) \ --no-entry \ --export-all \ --initial-memory=131072 \ --stack-size=$[1024 * 1024] \ -error-limit=0 \ --lto-O3 \ -O3 \ -lc -lc++ -lc++abi \ --gc-sections \ -allow-undefined-file ./stdlibc/wasm.syms \ $(OBJ) \ $(LIBCXX_OBJ) \ $(STDLIBC_OBJ) %.o: %.cpp $(DEPS) Makefile clang++ \ -c \ $(COMPILE_FLAGS) \ -fno-exceptions \ -o $@ \ $< library.wat: $(OUTPUT) Makefile ~/build/wabt/wasm2wat -o library.wat $(OUTPUT) wat: library.wat clean: rm -f $(OBJ) $(STDLIBC_OBJ) $(OUTPUT) library.wat
我从emscripten中插入了libc,libc ++和libc ++ abi(但老实说,这是一个糟糕的安装过程。)
我一直在逐步尝试填补我猜emscripten通常会做的空白,但现在我再次陷入困境:
./libcxx/type_traits:4837:57: error: use of undeclared identifier 'byte' constexpr typename enable_if<is_integral_v<_Integer>, byte>::type & ^ ./libcxx/type_traits:4837:64: error: definition or redeclaration of 'type' cannot name the global scope constexpr typename enable_if<is_integral_v<_Integer>, byte>::type &
由于系统可能会意外地编译特定于平台的内容,因此我不再确定这是否还会起作用。我真正想要的是一个垫片,该垫片将仅使我主要使用标准容器。这已经变得难以管理。接下来我该怎么办?
编辑2:是的,因此缺少C ++ 17类型特征内容,当我使用C ++ 14(我仍然想要C ++ 17)时,我最终会遇到更多丢失的东西。绝对卡住了。
编辑3:
我有点重新开始。库正在链接,我可以使用标准,但是如果尝试使用例如,我会看到类似以下的错误。一个std :: chrono的方法(我可以实例化该对象):
wasm-ld: error: /var/folders/9k/zvv02vlj007cc0pm73769y500000gn/T/library-4ff1b5.o: undefined symbol: std::__1::chrono::system_clock::now()
我目前正在使用emscripten的静态库abi和我的llvm自制安装中的静态库C ++标准库(我尝试了emscripten,但是那也不起作用。
我不确定这是否与名称修改有关。我目前正在从webasm导出所有符号,所以malloc和co。也要出口。
这是我的构建脚本:
clang++ \ --target=wasm32-unknown-wasi \ --std=c++11 \ -stdlib=libc++ \ -O3 \ -flto \ -fno-exceptions \ -D WASM_BUILD \ -D _LIBCPP_HAS_NO_THREADS \ --sysroot /usr/local/opt/wasi-libc \ -I/usr/local/opt/wasi-libc/include \ -I/usr/local/opt/glm/include \ -I./libcxx/ \ -L./ \ -lc++ \ -lc++abi \ -nostartfiles \ -Wl,-allow-undefined-file wasm.syms \ -Wl,--import-memory \ -Wl,--no-entry \ -Wl,--export-all \ -Wl,--lto-O3 \ -Wl,-lc++, \ -Wl,-lc++abi, \ -Wl,-z,stack-size=$[1024 * 1024] \ -o library.wasm \ library.cpp
我的代码:
#include "common_header.h" #include <glm/glm.hpp> #include <unordered_map> #include <vector> #include <string> #include <chrono> template <typename T> struct BLA { T x; }; template <typename T> BLA<T> make_BLA() { BLA<T> bla; std::unordered_map<T, T> map; std::vector<T> bla2; std::string str = "WEE"; //str = str.substr(0, 2); return bla; } #ifdef __cplusplus extern "C" { #endif char* malloc_copy(char* input) { usize len = strlen(input) + 1; char* result = (char*)malloc(len); if (result == NULL) { return NULL; } strncpy(result, input, len); return result; } void malloc_free(char* input) { free(input); } float32 print_num(float val); float32 my_sin(float32 val) { float32 result = sinf(val); float32 result_times_2 = print_num(result); print_num(result_times_2); return result; } long fibonacci(unsigned n) { if (n < 2) return n; return fibonacci(n-1) + fibonacci(n-2); } void set_char(char* input) { input[0] = '\''; uint8 fibonacci_series[] = { 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89 }; for (uint8 number : fibonacci_series) { input[0] = number; } auto WEE = make_BLA<int>(); WEE.x = 18; glm::vec4 v(100.0f, 200.0f, 300.0f, 1.0f); glm::vec4 v_out = glm::mat4(1.0f) * v; input[0] = 5 + static_cast<int>(v_out.x) * input[1]; auto start = std::chrono::system_clock::now(); long out = fibonacci(42); auto end = std::chrono::system_clock::now(); std::chrono::duration<double> elapsed_seconds = end-start; std::time_t end_time = std::chrono::system_clock::to_time_t(end); auto elapsed = elapsed_seconds.count(); } #ifdef __cplusplus } #endif
[当我尝试仅对没有C ++的函数使用“ visible”属性动态导出时,项目进行了编译,但是wasm模块无法在JavaScript中加载,因此我认为问题仍然存在。
据我所知。问题可能与我使用的编译器不同于用于创建静态库的编译器有关吗? (我正在使用自制的c 9)。希望不会。那时候我会很困惑,因为我找不到其他获取库的方法。手动llvm编译似乎失败。
我无法通过对内存和布局的完全控制来构建独立的Web程序集。我不想使用emscripten,因为,正如下面的帖子所述,它不能给我全部...
[自从我发现全局重载new
,delete
和具有我自己的分配功能的公司(例如WASI的malloc的包装器和自由或线性堆栈分配器)后,我发现问题与C ++的默认分配器有关。更多的C ++容器开始工作。但是string
似乎不太适合此功能。我认为它的实现会带来一些wasm所不喜欢的特定于平台的狡猾魔术。太糟糕了,但至少我离想要的东西越来越近了。编写自己的基本字符串类型并不难。