Как я могу определить версию ABI (и другие данные) скомпилированного нативного модуля?

Я работаю над расширением VSCode, для которого используется собственный модуль (последовательный порт). чтобы решение работало стабильно на всех платформах и с течением времени, когда VScode меняет электронные версии, я хотел бы включить предварительно созданные собственные модули.

теперь кажется, что некоторые (не все) из этих предварительно скомпилированных модулей не являются той версией, за которую они претендуют.

для тестирования/проверки я хотел бы программно определить версию ABI и, если возможно, среду выполнения, платформу (darwin, linux, win32) и архитектуру для каждого из собственных модулей, загружаемых с помощью install-prebuild

т.е. при попытке загрузить модуль в электрон 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, когда он был загружен путем предварительной сборки-установки как 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


person Jos Verlinde    schedule 23.08.2019    source источник


Ответы (2)


наткнулся на приличное, но частичное решение, так как мне не удалось найти API или настоящее межплатформенное решение.

Самое близкое, что я мог бы получить, это напрямую использовать process.dlopen, но это все равно дает только успешно или выдает ошибку. базовый загрузчик содержит информацию mp->nm_version, но сообщается только об ошибке.

Таким образом, единственный способ, найденный до сих пор, — это проанализировать это сообщение об ошибке. ограничение заключается в том, что это может работать только на той же платформе и архитектуре процессора, что и текущая среда выполнения, но это лучше, чем ничего.

В приведенном ниже примере будет извлечена версия 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 = [];
 }
person Jos Verlinde    schedule 24.08.2019

process.versions.modules должен предоставить вам правильный ABI для данного узла или среды выполнения электрона.

Ваше собственное решение — единственный способ сделать это без добавления собственного модуля узла, а синтаксический анализ/чтение файла .node не дает вам информацию непосредственно в виде строки или значения int (проверено с помощью шестнадцатеричного редактора) .

Возможные причины:

  • Вы должны быть уверены, что процесс установки модуля не запускает сборку вашего собственного модуля, например: запуск npm install без --ignore-scripts., поскольку при этом используется ваша локально установленная версия узла для перестроения любой зависимости, если содержащий пакет имеет собственный сценарий установки.
  • Ваша предварительная сборка игнорируется другими этапами установки.
  • Пакет загрузил неправильные файлы .node в качестве предварительной сборки.
person Hans Koch    schedule 23.08.2019
comment
ну нет, дело вообще не в этом. во-первых, было бы самонадеянно предполагать, что любой и все пользователи программного обеспечения могут скомпилировать собственный модуль из исходного кода c/c++. - person Jos Verlinde; 23.08.2019
comment
install-prebuild предназначен для предотвращения необходимости сборки исходного кода, как это сделано первоначальными авторами модуля Electron 5.0.10 (ABI-70): модуль, и они доступны для скачивания. но тогда ожидается, что доставленные двоичные файлы будут правильной версией ABI, а это, похоже, не так. также, как указано, это включено - person Jos Verlinde; 23.08.2019
comment
и, наконец, я хочу получить ABI для «загружаемого модуля», а не для среды выполнения - person Jos Verlinde; 23.08.2019
comment
Хорошо, я действительно неправильно понял ваш вопрос. Но все же ваша загрузка должна быть перезаписана после того, как вы вручную установили свой пакет, иначе вы бы не загрузили ABI 47. Что касается вашей проблемы, разбор жала, как вы сделали в своем собственном awnser, - единственный способ получить эту информацию без написания другой родной библиотеки или искать метаинформацию, читая/анализируя файл узла, но я не нашел int или строку, содержащую версию ABI, в .node на первый взгляд. - person Hans Koch; 24.08.2019
comment
Также из того, что я вижу, есть проблема с последовательным портом github.com/serialport/node-serialport /issues/1884 возможно, кэшированный файл node содержит неправильную сборку. - person Hans Koch; 24.08.2019
comment
другими словами: предположение, что ваша загрузка должна быть перезаписана после того, как вы вручную установили свой пакет, иначе вы бы не загрузили ABI 47. оказалось неверным. Спасибо за другую проблему, хотя я пропустил это, но это действительно та же проблема. - person Jos Verlinde; 30.08.2019
comment
Это действительно сложно заметить, по крайней мере, это отличный пример того, почему данным (из любого источника) никогда не следует доверять вслепую :) - person Hans Koch; 30.08.2019