简体   繁体   English

如何使用 Emscripten 和 Embind 发出的 .js 和 .wasm 工件?

[英]How to use the .js and .wasm artifacts emitted by Emscripten and Embind?

I have two fairly simple C++ class definitions and their interfaces, uuid.{hpp,cpp} and uuid_util.{hpp,cpp} , and I have one more file uuid_bind.cpp with #include <emscripten/bind.h> to bind the C++ classes, function and static function definitions to JavaScript.我有两个相当简单的 C++ class 定义及其接口uuid.{hpp,cpp}uuid_util.{hpp,cpp} ,我还有一个文件uuid_bind.cpp#include <emscripten/bind.h>绑定。 C++ classes, function and static function definitions to JavaScript.

The two classes are first built as a static library uuid_lib.a , which is then linked against the latter C++ source file and built with em++ --bind -o uuid_module.js uuid_bind.cpp uuid_lib.a (which CMake generates) to generate uuid_module.js and uuid_module.wasm . The two classes are first built as a static library uuid_lib.a , which is then linked against the latter C++ source file and built with em++ --bind -o uuid_module.js uuid_bind.cpp uuid_lib.a (which CMake generates) to generate uuid_module.jsuuid_module.wasm Now, what do I do with these?现在,我该怎么处理这些?

The documentation on Embind is somewhat sparse, and only says Embind 上的文档有些稀疏,只说

The resulting quick_example.js file can be loaded as a node module or via a <script> tag: ...生成的quick_example.js文件可以作为节点模块或通过<script>标签加载: ...

I found this Google tutorial on combining Emscripten/Embind and node.js, and I have replicated it as much as possible (excluding the bit on Docker, as my Linux distribution serves Emscripten directly).我找到了这个关于结合 Emscripten/Embind 和 node.js 的 Google 教程,并且我已经尽可能多地复制了它(不包括 Docker 上的位,因为我的 ZEDC9F0A5A5D57797BF68E3736474383Z 分发直接服务)。 I have both an index.html and a package.json file, and npm test launches http-server , which I run from Chrome.我有一个index.html和一个package.json文件,并且npm test启动 Chrome http-server的 ZBB30E85411B56DF41296726

I was under the impression that Emscripten/Embind would simply serve as a translation layer for any bound classes, functions (static or otherwise), variables, and would be able to be called straightforwardly from JavaScript, but it turns out this is not the case.我的印象是 Emscripten/Embind 将简单地用作任何绑定类、函数(静态或其他)、变量的转换层,并且可以直接从 JavaScript 调用,但事实证明并非如此. Am I missing out on something here?我在这里错过了什么吗? I'm not very familiar with JS.我对JS不是很熟悉。 All I want to do in index.js is something like:我想在index.js中做的就是:

index.js

import uuid_module from './uuid_lib.js';

console.log(uuid_module.uuid_util.generate_type1_uuid("BLA"));
// ... other calls

and run this with node index.js which would print a UUID string to the console.并使用node index.js运行它,它会将 UUID 字符串打印到控制台。


For background, I've provided my CMakeLists.txt and uuid_bind.cpp below.作为背景,我在下面提供了我的CMakeLists.txtuuid_bind.cpp

CMakeLists.txt

cmake_minimum_required(VERSION 3.16)

# Set project file
project(
    uuid_generator
    VERSION 1.0
    DESCRIPTION "A UUID generator"
    LANGUAGES CXX)

# Export compile commands for clangd
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)

# Add Emscripten CMake toolchain file
if(EMSCRIPTEN)
    message("Using Emscripten.")
    set(CMAKE_TOOLCHAIN_FILE
        ${PROJECT_SOURCE_DIR}/deps/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake)
else()
    message("Using system compilers.")
endif(EMSCRIPTEN)

# C++20 guaranteed, no extensions eg. GNU/MSVC
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)

# Strict compilation for MSVC or GCC/Clang
if(MSVC)
    add_compile_options(/W4 /WX)
else()
    add_compile_options(-Wall -Wextra -pedantic)
endif()

# Add uuid_generator as a shared library
add_library(uuid_lib STATIC src/uuid.cpp src/uuid_util.cpp)

# Set C++ library properties: output name, location, etc
set_target_properties(
    uuid_lib
    PROPERTIES OUTPUT_NAME uuid_lib
               PREFIX ""
               ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dist)

# Set JS binding application properties: set bind, output type, etc. Runs only if Emscripten is enabled.
if(DEFINED ENV{EMSDK})
    add_executable(uuid_module src/uuid_bind.cpp)
    set_target_properties(
        uuid_module
        PROPERTIES OUTPUT_NAME uuid_module
                   SUFFIX ".js"
                   RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/dist)
    target_include_directories(uuid_module
                               PRIVATE ${PROJECT_SOURCE_DIR}/deps/emsdk/upstream/emscripten/system/include)
    target_link_libraries(uuid_module uuid_lib)
    target_link_options(
        uuid_module
        PUBLIC
        $<$<CONFIG:DEBUG>:
        -v
        --bind
        -sEXCEPTION_DEBUG=1
        -sDEMANGLE_SUPPORT=1
        -sDISABLE_EXCEPTION_CATCHING=1
        -sWASM_BIGINT=1
        -sMODULARIZE=1
        -sEXPORT_ES6=1
        -sEXPORT_NAME=uuid_module
        >)
endif(DEFINED ENV{EMSDK})

uuid_bind.cpp

#include "uuid.hpp"
#include "uuid_util.hpp"

#include <cstdint>
#include <emscripten.h>
#include <emscripten/bind.h>
#include <string>
#include <iostream>

EMSCRIPTEN_BINDINGS(uuid_generator)
{
    emscripten::constant("UINT29_MAX", uuid_gen::uuid::UINT29_MAX);
    emscripten::constant("ICAO_ADDRESS_MAX", uuid_gen::uuid_util::ICAO_ADDRESS_MAX);
    emscripten::constant("MAC_ADDRESS_MAX", uuid_gen::uuid_util::MAC_ADDRESS_MAX);
    emscripten::constant("RANDOM_NAMESPACE_MAX", uuid_gen::uuid_util::RANDOM_NAMESPACE_MAX);

    emscripten::class_<uuid_gen::uuid>("uuid")
        .property("namespace_type", &uuid_gen::uuid::get_namespace_type)
        .property("namespace_value", &uuid_gen::uuid::get_namespace_value)
        .property("namespace_string", &uuid_gen::uuid::get_namespace_string)
        .property("to_string", &uuid_gen::uuid::to_string)
        .class_function("uniform_int_distr", &uuid_gen::uuid::uniform_int_dist);

    emscripten::class_<uuid_gen::uuid_util>("uuid_util")
        .class_function("generate_type1_uuid", &uuid_gen::uuid_util::generate_type1_uuid)
        .class_function("generate_type2_uuid", &uuid_gen::uuid_util::generate_type2_uuid)
        .class_function("generate_type3_uuid", &uuid_gen::uuid_util::generate_type3_uuid)
        .class_function("generate_type4_uuid", &uuid_gen::uuid_util::generate_type4_uuid)
        .class_function("generate_type5_uuid_str", emscripten::select_overload<uuid_gen::uuid(const std::string &)>(
                                                       &uuid_gen::uuid_util::generate_type5_uuid))
        .class_function("generate_type5_uuid_int", emscripten::select_overload<uuid_gen::uuid(std::uint32_t)>(
                                                       &uuid_gen::uuid_util::generate_type5_uuid))
        .class_function("generate_type6_uuid_str", emscripten::select_overload<uuid_gen::uuid(const std::string &)>(
                                                       &uuid_gen::uuid_util::generate_type6_uuid))
        .class_function("generate_type6_uuid_int", emscripten::select_overload<uuid_gen::uuid(std::uint64_t)>(
                                                       &uuid_gen::uuid_util::generate_type6_uuid))
        .class_function("generate_type7_uuid", &uuid_gen::uuid_util::generate_type7_uuid)
        .class_function("from_string", &uuid_gen::uuid_util::from_string)
        .class_function("is_valid_oper_agency", &uuid_gen::uuid_util::is_valid_oper_agency)
        .class_function("is_valid_loc_atm_id", &uuid_gen::uuid_util::is_valid_loc_atm_id)
        .class_function("is_valid_mac_address_string", &uuid_gen::uuid_util::is_valid_mac_address_string)
        .class_function("namespace_char_encode", &uuid_gen::uuid_util::namespace_char_encode)
        .class_function("namespace_char_decode", &uuid_gen::uuid_util::namespace_char_decode)
        .class_function("namespace_encode", &uuid_gen::uuid_util::namespace_encode)
        .class_function("namespace_decode", &uuid_gen::uuid_util::namespace_decode)
        .class_function("mac_address_encode", &uuid_gen::uuid_util::mac_address_encode)
        .class_function("mac_address_decode", &uuid_gen::uuid_util::mac_address_decode);
};

Am I missing out on something here?我在这里错过了什么吗?

What you're missing is that in -s MODULARIZE=1 mode, the default export is a factory, not the module object itself.您缺少的是在-s MODULARIZE=1模式下,默认导出是工厂,而不是模块 object 本身。

You'll need to create a module first and then you should be able to access the exposed properties:您需要先创建一个模块,然后您应该能够访问公开的属性:

import uuidModuleFactory from './uuid_lib.js';

const uuid_module = uuidModuleFactory(/* optional Emscripten config goes here */);

console.log(uuid_module.uuid_util.generate_type1_uuid("BLA"));
// ... other calls

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM