安装基础配置
安装nvm
nvm下载node版本5.12.0 32
并且切换到该版本。
如果你只用5.12.0版本开发,那么可以跳过这一步。如果安装失败,可以在网上搜索相关资料。(一般都是卸载干净node版本后再进行安装,包括node的缓存目录等等)
nw.js在xp系统上最新的LTS版本为0.14.7
,对应能支持最高的node版本为5.x
。而最新的5.x
node版本为5.12.0。
为了支持在32位系统中也能正常使用,所以建议安装32版本。
对应命令为:
nvm install 5.12.0 32
安装完成后记得切换版本
nvm use 5.12.0 32
5.x版本带来的影响
低版本的node不支持ES6语法,所以直接安装最新的库,很多都会运行不起来。所以后面安装的库都会指定版本,否则会安装失败!
安装nrm
为了提高安装速度,国内用户建议使用nrm管理npm registry
。
安装命令
npm install -g nrm@1.0.1
安装完成之后,切换仓库源
nrm use cnpm
安装node-gyp
node-gyp是用于编译node-ffi模块必需的库。
安装命令
npm install -g node-gyp@3.4.0
node-gyp可能还有各种编译配置,具体大家需要去查看官网配置教程。
安装npm
由于低版本npm构建与高版本npm构建并不一样,所以如果你不安装低版本的npm很可能会构建失败,
比如说你直接安装node-ffi,可能就会报错:
E:\xxx\node_modules\ffi>if not defined npm_config_node_gyp (node "C:\xxx\nvm\v5.12.0\node_modules\npm\bin\node-gyp-bin\\..\..\node_modules\node-gyp\bin\node-gyp.js" rebuild ) else (node "" rebuild )
在此解决方案中一次生成一个项目。若要启用并行生成,请添加“/m”开关。
Building assembly file ..\..\..\deps\libffi\src\x86\win32.asm
Assembling: ..\..\..\deps\libffi\src\x86\win32.asm
prep_cif.c
types.c
raw_api.c
java_raw_api.c
closures.c
ffi.c
win_delay_load_hook.c
C:\xxx\nvm\v5.12.0\node_modules\npm\node_modules\node-gyp\src\win_delay_load_hook.c(34): error
C2373: “__pfnDliNotifyHook2”: 重定义;不同的类型修饰符 [E:\xxx\node_m
odules\ffi\build\deps\libffi\ffi.vcxproj]
这里推荐安装3.10.10版本的npm
安装命令:
npm install -g npm@3.10.10
安装成功之后,可以项目目录中安装node-ffi进行测试,正常情况会安装成功,这说明你的基础库和配置都已经正确了,不过还没结束哦。
适配XP系统
修改ffi源码
文件路径:
E:\xxx\node_modules\ffi\src\win32-dlfcn.cc
源文件内容:
/**
* @file Minimal emulation of POSIX dlopen/dlsym/dlclose on Windows.
* @license Public domain.
*
* This code works fine for the common scenario of loading a
* specific DLL and calling one (or more) functions within it.
*
* No attempt is made to emulate POSIX symbol table semantics.
* The way Windows thinks about dynamic linking is fundamentally
* different, and there's no way to emulate the useful aspects of
* POSIX semantics.
*/
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <windows.h>
#include <stdio.h>
#include <malloc.h>
#include "win32-dlfcn.h"
/**
* Win32 error code from last failure.
*/
static DWORD lastError = 0;
#ifdef __cplusplus
extern "C" {
#endif
/**
* Convert UTF-8 string to Windows UNICODE (UCS-2 LE).
*
* Caller must free() the returned string.
*/
static
WCHAR*
UTF8toWCHAR(
const char* inputString /** UTF-8 string. */
)
{
int outputSize;
WCHAR* outputString;
outputSize = MultiByteToWideChar(CP_UTF8, 0, inputString, -1, NULL, 0);
if (outputSize == 0)
return NULL;
outputString = (WCHAR*) malloc(outputSize * sizeof(WCHAR));
if (outputString == NULL) {
SetLastError(ERROR_OUTOFMEMORY);
return NULL;
}
if (MultiByteToWideChar(CP_UTF8, 0, inputString, -1, outputString, outputSize) != outputSize)
{
free(outputString);
return NULL;
}
return outputString;
}
/**
* Open DLL, returning a handle.
*/
void*
dlopen(
const char* file, /** DLL filename (UTF-8). */
int mode /** mode flags (ignored). */
)
{
WCHAR* unicodeFilename;
UINT errorMode;
void* handle;
UNREFERENCED_PARAMETER(mode);
if (file == NULL)
return (void*) GetModuleHandle(NULL);
unicodeFilename = UTF8toWCHAR(file);
if (unicodeFilename == NULL) {
lastError = GetLastError();
return NULL;
}
errorMode = GetErrorMode();//这里!这里!这里!这里!这里!这里!这一行注释掉
/* Have LoadLibrary return NULL on failure; prevent GUI error message. */
SetErrorMode(errorMode | SEM_FAILCRITICALERRORS);//这里!这里!这里!这里!这一行注释掉
handle = (void*) LoadLibraryW(unicodeFilename);
if (handle == NULL)
lastError = GetLastError();
SetErrorMode(errorMode);
free(unicodeFilename);
return handle;
}
/**
* Close DLL.
*/
int
dlclose(
void* handle /** Handle from dlopen(). */
)
{
int rc = 0;
if (handle != (void*) GetModuleHandle(NULL))
rc = !FreeLibrary((HMODULE) handle);
if (rc)
lastError = GetLastError();
return rc;
}
/**
* Look up symbol exported by DLL.
*/
void*
dlsym(
void* handle, /** Handle from dlopen(). */
const char* name /** Name of exported symbol (ASCII). */
)
{
void* address = (void*) GetProcAddress((HMODULE) handle, name);
if (address == NULL)
lastError = GetLastError();
return address;
}
/**
* Return message describing last error.
*/
char*
dlerror(void)
{
static char errorMessage[64];
if (lastError != 0) {
sprintf(errorMessage, "Win32 error %lu", lastError);
lastError = 0;
return errorMessage;
} else {
return NULL;
}
}
#ifdef __cplusplus
}
#endif
进行注释掉之后,记得保存。
//errorMode = GetErrorMode();
// SetErrorMode(errorMode | SEM_FAILCRITICALERRORS);
替换node-gyp文件
在windows系统中还需要一个操作,就是将全局中node-gyp的
<npm-path>\node_modules\node-gyp\src\win_delay_load_hook.cc
文件,
替换成https://github.com/nwjs/nw.js/blob/nw18/tools/win_delay_load_hook.cc 的文件。
推荐直接打开https://github.com/nwjs/nw.js/blob/nw18/tools/win_delay_load_hook.cc 地址,然后点击raw,将内容直接复制到node-gyp的win_delay_load_hook.c
文件中
注意
- 是
nw18
中的文件,不是nw13
。(有个中文文档上写的就是nw13) - 确认修改的路径。不是
npm>node_modules
中node-gyp。而是与npm同级别的node-gyp
重新编译ffi
进入到ffi目录下,输入命令
node-gyp rebuild
编译成功: