nodejs mysql-libmysqlclient on windows

当前使用node-mysql-libmysqlclient的版本为1.5.2 虽然作者曾表示要支持Windows,但是已经很久没有动静了…… 由于笔者在Windows、Linux、MacOSX上都有开发环境,所以不得不让他们都支持…… 废话不多说,开始动手。 由于这个node-mysql-libmysqlclient编译的有个依赖库,我们先安装一下node-gyp [code]npm install node-gyp -gd[/code] 之后装mysql-libmysqlclient,我们不直接用npm,我们找到node_modules目录,git clone一下 [code]git clone git://github.com/Sannis/node-mysql-libmysqlclient.git[/code] 然后把 node-mysql-libmysqlclient 目录的名字改成 mysql-libmysqlclient [code] cd mysql-libmysqlclient node-gyp rebuild [/code] 然后我们大概能看到如下的错误消息 [code] gyp info it worked if it ends with ok gyp info using node-gyp@0.9.5 gyp info using node@0.10.4 | win32 | ia32 gyp info spawn python gyp info spawn args [ 'D:\\Users\\TengAttack\\AppData\\Roaming\\npm\\node_module s\\node-gyp\\gyp\\gyp', gyp info spawn args 'binding.gyp', gyp info spawn args '-f', gyp info spawn args 'msvs', gyp info spawn args '-G', gyp info spawn args 'msvs_version=auto', gyp info spawn args '-I', gyp info spawn args 'D:\\Users\\TengAttack\\AppData\\Roaming\\npm\\node_module s\\mysql-libmysqlclient\\build\\config.gypi', gyp info spawn args '-I', gyp info spawn args 'D:\\Users\\TengAttack\\AppData\\Roaming\\npm\\node_module s\\node-gyp\\addon.gypi', gyp info spawn args '-I', gyp info spawn args 'D:\\Users\\TengAttack\\.node-gyp\\0.10.4\\common.gypi', gyp info spawn args '-Dlibrary=shared_library', gyp info spawn args '-Dvisibility=default', gyp info spawn args '-Dnode_root_dir=D:\\Users\\TengAttack\\.node-gyp\\0.10.4' , gyp info spawn args '-Dmodule_root_dir=D:\\Users\\TengAttack\\AppData\\Roaming \\npm\\node_modules\\mysql-libmysqlclient', gyp info spawn args '--depth=.', gyp info spawn args '--generator-output', gyp info spawn args 'D:\\Users\\TengAttack\\AppData\\Roaming\\npm\\node_module s\\mysql-libmysqlclient\\build', gyp info spawn args '-Goutput_dir=.' ] gyp info spawn C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe gyp info spawn args [ 'build/binding.sln', gyp info spawn args '/clp:Verbosity=minimal', gyp info spawn args '/nologo', gyp info spawn args '/p:Configuration=Release;Platform=Win32' ] 在此解决方案中一次生成一个项目。若要启用并行生成,请添加“/m”开关。 mysql_bindings_connection.cc mysql_bindings_statement.cc mysql_bindings_result.cc mysql_bindings.cc d:\users\tengattack\appdata\roaming\npm\node_modules\mysql-libmysqlclient\src\. /mysql_bindings_connection.h(11): fatal error C1083: 无法打开包括文件:“mysql.h ”: No suc h file or directory [D:\Users\TengAttack\AppData\Roaming\npm\node_modules\mysql -libmysqlclient\build\mysql_bindings.vcxproj] d:\users\tengattack\appdata\roaming\npm\node_modules\mysql-libmysqlclient\src\. /mysql_bindings_connection.h(11): fatal error C1083: 无法打开包括文件:“mysql.h ”: No suc h file or directory [D:\Users\TengAttack\AppData\Roaming\npm\node_modules\mysql -libmysqlclient\build\mysql_bindings.vcxproj] d:\users\tengattack\appdata\roaming\npm\node_modules\mysql-libmysqlclient\src\. /mysql_bindings_connection.h(11): fatal error C1083: 无法打开包括文件:“mysql.h ”: No suc h file or directory [D:\Users\TengAttack\AppData\Roaming\npm\node_modules\mysql -libmysqlclient\build\mysql_bindings.vcxproj] d:\users\tengattack\appdata\roaming\npm\node_modules\mysql-libmysqlclient\src\. /mysql_bindings_connection.h(11): fatal error C1083: 无法打开包括文件:“mysql.h ”: No suc h file or directory [D:\Users\TengAttack\AppData\Roaming\npm\node_modules\mysql -libmysqlclient\build\mysql_bindings.vcxproj] gyp ERR! build error gyp ERR! stack Error: `C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe ` failed with exit code: 1 gyp ERR! stack at ChildProcess.onExit (D:\Users\TengAttack\AppData\Roaming\n pm\node_modules\node-gyp\lib\build.js:267:23) gyp ERR! stack at ChildProcess.EventEmitter.emit (events.js:98:17) gyp ERR! stack at Process.ChildProcess._handle.onexit (child_process.js:784: 12) gyp ERR! System Windows_NT 6.2.9200 gyp ERR! command "node" "D:\\Users\\TengAttack\\AppData\\Roaming\\npm\\node_modu les\\node-gyp\\bin\\node-gyp.js" "rebuild" gyp ERR! cwd D:\Users\TengAttack\AppData\Roaming\npm\node_modules\mysql-libmysql client gyp ERR! node -v v0.10.4 gyp ERR! node-gyp -v v0.9.5 gyp ERR! not ok [/code] 这时我们进入目录 mysql-libmysqlclient\build 下,会发现有个叫做 binding.sln 的VS项目文件,用VS打开,选Release模式。 然后我们在项目选项中添加上mysql的include目录和lib目录,这里需要注意我们的node在官网上下的安装包是x86的,所以我们的mysql的lib也需要是x86的(这个和你运行的MySQL的位数不一定要相同),从官网上下一个zip包就好了。 之后就是在选项里链接器中加入libmysql.lib和mysqlclient.lib。 接着就是需要改一些代码,来适应VS的编译器,大概修改和添加的代码如下: pthread-win.cc [code lang="cpp"] #include "pthread-win.h" int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr) { *mutex = CreateMutex( NULL, // default security attributes FALSE, // initially not owned NULL); // unnamed mutex return 0; } int pthread_mutex_lock(pthread_mutex_t *mutex) { WaitForSingleObject(*mutex, INFINITE); return 0; } int pthread_mutex_unlock(pthread_mutex_t *mutex) { ReleaseMutex(*mutex); return 0; } int pthread_mutex_destroy(pthread_mutex_t *mutex) { CloseHandle(*mutex); return 0; } [/code] pthread-win.h [code lang="cpp"] #ifndef _PTHREAD_WIN_H_ #define _PTHREAD_WIN_H_ #include <windows.h> typedef HANDLE pthread_mutex_t; int pthread_mutex_init(pthread_mutex_t *mutex, const void *attr); int pthread_mutex_lock(pthread_mutex_t *mutex); int pthread_mutex_unlock(pthread_mutex_t *mutex); int pthread_mutex_destroy(pthread_mutex_t *mutex); #endif [/code] 把 mysql_bindings_connection.h [code lang="cpp"] #include <unistd.h> #include <pthread.h> [/code] 改成 [code lang="cpp"] #ifndef WIN32 #include <unistd.h> #include <pthread.h> #else #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctime> #include "pthread-win.h" #undef errno #define snprintf _snprintf #define strtok_r strtok_s #define gmtime_r(timep, result) gmtime_s(result, timep) #endif [/code] 把 mysql_bindings_statement.cc [code lang="cpp"] unsigned long length[field_count]; my_bool is_null[field_count]; // actual binded buffers void** buffers; buffers = (void **) malloc(field_count * sizeof(void *)); MYSQL_BIND bind[field_count]; [/code] 改成 [code lang="cpp"] // actual binded buffers void** buffers; buffers = (void **) malloc(field_count * sizeof(void *)); #ifndef WIN32 unsigned long length[field_count]; my_bool is_null[field_count]; MYSQL_BIND bind[field_count]; memset(bind, 0, sizeof(bind)); #define _FREE_ALLOC() #else unsigned long *length = (unsigned long *)malloc(field_count * sizeof(unsigned long)); my_bool *is_null = (my_bool *)malloc(field_count * sizeof(my_bool)); MYSQL_BIND *bind = (MYSQL_BIND *)malloc(field_count * sizeof(MYSQL_BIND)); #define _FREE_ALLOC() { free(length); free(is_null); free(bind); } #endif [/code] 并在该函数后面的每一个(一共有 4 处) [code lang="cpp"] return scope.Close( ... [/code] 前面加上一行 [code lang="cpp"] _FREE_ALLOC(); [/code] 注意还有个地方可能需要改的就是在 mysql 的 include 的一个文件 mysql_com.h,他可能会报错,关于my_socket类型的一个问题,我们在 [code lang="cpp"] #ifndef _mysql_com_h #define _mysql_com_h [/code] 之后加上如下代码即可: [code lang="cpp"] #ifdef WIN32 #undef my_socket #define my_socket int #endif [/code] 然后就是编译,编译完成后 Release 目录下就会有个 mysql_bindings.node 文件(DLL),这时我们还需要把链接的 libmysql.lib 对应的 libmysql.dll 文件也放到这个目录下就可以了。 如果是在一个其他的工作目录中也需要用到 mysql-libmysqlclient ,我们只需要先在 node_modules 目录下 git 之后,改目录名,去掉前面的 node- ,然后把现在的 build 目录下的 Release 目录拷到那个工作目录下 node_modules/mysql-libmysql/build 目录下就可以了。 Windows下使用也一样很棒! 这里有编译好的程序(VS2012) mysql_bindings.node-win (等有空再详细整理一下