【问题标题】:How can I determine the ABI version (and other details) of a compiled native module?如何确定已编译本机模块的 ABI 版本(和其他详细信息)?
【发布时间】:2019-12-28 12:01:31
【问题描述】:

我正在合作开发一个使用本机模块(串行端口)的 VSCode 扩展。 为了使解决方案在所有平台上稳定运行,并且随着 VScode 更改电子版本而随时间推移,我想包含预构建的原生模块。

现在看来,这些预编译模块中的一些(不是全部)不是他们声称的版本。

为了测试/验证,我想以编程方式确定 ABI 版本,如果可能的话,为 install-prebuild 下载的每个本机模块确定运行时、平台(darwin、linux、win32)和架构

即当我尝试在电子 5.0.10 (ABI-70) 中加载模块时引发以下错误:

Uncaught Error: The module '\\?\C:\develop\NodeJS\electron-serialport\node_modules\@serialport\bindings\lib\binding\node-v70-win32-x64\bindings.node'
was compiled against a different Node.js version using
NODE_MODULE_VERSION 47. This version of Node.js requires
NODE_MODULE_VERSION 70. Please try re-compiling or re-installing
the module (for instance, using `npm rebuild` or `npm install`).

所以它在下载时报告 ABI 47,通过 prebuild-install 下载为 ABI 70。 注意:将电子绑定存储在节点绑定位置以允许“绑定”检测 ABI、平台和架构

## npx prebuild-install 
Download prebuild native binding for runtime electron : 5.0.5, abi: 70, win32, x64
prebuild-install info begin Prebuild-install version 5.3.0
prebuild-install info looking for cached prebuild @ C:\Users\josverl\AppData\Roaming\npm-cache\_prebuilds\bde028-bindings-v2.0.8-electron-v70-win32-x64.tar.gz
prebuild-install info found cached prebuild
prebuild-install info unpacking @ C:\Users\josverl\AppData\Roaming\npm-cache\_prebuilds\bde028-bindings-v2.0.8-electron-v70-win32-x64.tar.gz
prebuild-install info unpack resolved to C:\develop\NodeJS\electron-serialport\node_modules\@serialport\bindings\build\Release\bindings.node
prebuild-install info install Successfully installed prebuilt binary!

Copy to : 
 -> C:\develop\NodeJS\electron-serialport\noded_modules\@serialport\bindings\lib\binding\node-v70-win32-x64\bindings.node

【问题讨论】:

    标签: node.js visual-studio-code electron vscode-extensions node-serialport


    【解决方案1】:

    我找到了一个不错但部分解决方案,因为我找不到 API 或真正的跨平台解决方案。

    我能得到的最接近的是直接使用process.dlopen,但这仍然只会成功或抛出错误。 底层loader确实有mp->nm_version的信息,但只是报错了。

    因此,目前发现的唯一方法是解析该错误消息。限制是它只能在与当前运行时相同的平台和 CPU 架构上工作,但总比没有好。

    下面将通过捕获错误消息并从中提取 ABI 来提取本机模块的 ABI 版本。

    // try to determine the ABI version for a native module
    const getNativeABI = (filename) => {
        var moduleVersion = 0
        try {
            var test = new Module(filename, null);
            process.dlopen(module, filename) //,os.constants.dlopen.RTLD_NOW);
            // if this works the node version is the same 
            moduleVersion = process.versions['modules']
            // but now we need to unload it :-( 
            return moduleVersion
        } catch (error) {
            var match
            var versionRegexp = /NODE_MODULE_VERSION (\d*)./gm
            var platformRegexp = /(is not a valid Win32 application|invalid ELF header|wrong ELF class)/g
            // check for ABI version mismatch 
                // Uncaught Error: The module '..\bindings.node'
                // was compiled against a different Node.js version using
                // NODE_MODULE_VERSION 47. This version of Node.js requires
                // NODE_MODULE_VERSION 70. Please try re-compiling or re-installing
            match = versionRegexp.exec(error.message)
            if (match != null){
                return match[1] // first version is that of the module 
            } 
            // not for valid on this win32 / linux 
            match = platformRegexp.exec(error.message)
            if (match != null){
                // todo: @linux : use error for elfclass to determine architecture :: wrong ELF class: ELFCLASS32
                return 0 // can't validate cross platform
            } 
            // other error 
            console.debug( error.message)
        }
        return moduleVersion // just in case
    }
    

    您需要传入一个虚拟模块结构。

    /// dummy copy of  internal function
    function Module(id, parent) {
        this.id = id;
        this.exports = {};
        this.parent = parent;
        // updateChildren(parent, this, false);
        this.filename = null;
        this.loaded = false;
        this.children = [];
     }
    

    【讨论】:

      【解决方案2】:

      process.versions.modules 应该为您提供给定节点或电子运行时的正确 ABI。

      您自己的解决方案是在不添加本机节点模块的情况下执行此操作的唯一方法,并且解析/读取 .node 文件不会直接将信息作为字符串或 int 值提供给您(使用十六进制编辑器检查)

      可能的原因有:

      • 您应该确保模块的安装过程不会触发您的本地模块的构建,例如:在没有--ignore-scripts. 的情况下运行npm install,因为如果包含包,这将使用您本地安装的节点版本来重建任何依赖关系有一个自定义安装脚本。
      • 其他安装步骤忽略了您的预构建
      • 软件包上传了错误的 .node 文件作为 prebuild。

      【讨论】:

      • 好吧,不,这根本不是问题。一方面,假设任何和所有软件的用户都能够从 c / c++ 源代码编译本机模块是一种冒昧的假设。
      • install-prebuild 旨在防止需要为源代码构建,因为这是由电子 5.0.10 (ABI-70) 的原作者完成的:模块,并且它们可供下载。但随后交付的二进制文件应该是正确的 ABI 版本,但似乎并非如此。也正如指定的那样,这是在
      • 最后,我想让 ABI 成为“待加载模块”,而不是运行时
      • 另外,从我看来,串行端口 github.com/serialport/node-serialport/issues/1884 存在问题,可能缓存的 node 文件包含错误的构建。
      • 换句话说:假设“在您手动安装软件包后,您的下载仍然必须被覆盖,否则您将不会加载 ABI 47。”已证明不正确。不过感谢另一个问题,我忽略了这一点,但确实是同一个问题。
      猜你喜欢
      • 2011-03-24
      • 1970-01-01
      • 2015-11-02
      • 1970-01-01
      • 2015-01-31
      • 1970-01-01
      • 2019-01-02
      • 1970-01-01
      • 2011-12-15
      相关资源
      最近更新 更多