windows下使用vs2008编译libuv库

时间:2021-01-05 18:01:07

libuv提供跨平台的事件驱动异步I/O能力,那行,那我们先来看一下libuv的Design overview框图吧。

windows下使用vs2008编译libuv库

图片看上去不错,还特别explicit的强调了对多个平台上的异步I/O的API进行了封装,如Linux下的epoll、FreeBSD下的kqueue、Solaris下的event ports、Windows下的IOCP。网上有很多文章都对各个平台上的异步IO进行了研究,得出哪些是真异步哪些是伪异步,听说windows平台上的IOCP是真异步。当然了高手用伪异步写出来的服务器肯定还是比本屌用真异步堆出来的服务器性能要好的。
本来libuv是为nodejs开发的,然而现在也有很多其他项目(https://github.com/libuv/libuv/wiki/Projects-that-use-libuv)用到了libuv。但是话又说回来,既然它选择了异步IO编程模型,就是说它是追求极致的,也就意味着大型软件只用它来开发一些功能模块,所以到头来还得去找别的c++库用,而且libuv开发出来的模块颜值不好看。


那么如何使用libuv呢?

下载libuv

libuv目前托管在github上(https://github.com/libuv/libuv),找到Downloading,再找到downloads site超链接。github打不开的话就直接点这里吧downloads site.
windows下使用vs2008编译libuv库
进去以后,找到最新的版本,注意:日期最新的才是最新的版本(我就因此上过一次当,本来想下载最新的v1.12.0,结果下载列表的最下面居然是v1.9.1的版本)


好了,好了,来看看我这里的最新版本v1.12.0里面都有些什么玩意吧。看图。
windows下使用vs2008编译libuv库
这样的话,一共有两种方式来使用libuv了。
1,源代码。这个需要编译,体现了跨平台特性。
2,DLL。都提供了DLL了,这样的话window平台连编译都省了,直接用,作品感人。


直接使用DLL

这个比较简单。
如果想使用x86的DLL,那就下载libuv-x86-v1.12.0.build7.exe
如果想使用x64的DLL,那就下载libuv-x64-v1.12.0.build7.exe
不过要对应起来,如果你下载了x84的DLL,那你使用visual studio编译链接自己程序的时候要确保平台使用win32的方式;
windows下使用vs2008编译libuv库
x64的DLL,平台就选择x64方式。不要错搭,不然会报下面那样的错。

1>main.obj : error LNK2019: 无法解析的外部符号 _uv_run,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _uv_loop_new,该符号在函数 _main 中被引用

我当初就错搭了,导致我编译不过去,明显是x86的编译器不认识x64的libuv.lib文件,最后一怒之下跑去编译源代码了。


下载好了以后(我这里以x86的DLL为例),把libuv安装目录中的文件(图中红框所示)拷贝到自己的vs2008项目中。
windows下使用vs2008编译libuv库


然后就是使用DLL的一般步骤了,也就是配置自己的项目属性。
1,包含libuv库的头文件
windows下使用vs2008编译libuv库
ATL+F7打开项目属性,选择C/C++,选择常规,在附加包含目录中输入include。哦,对了,那个配置最好选择所有配置,不然你的release还要继续重复配置。


2,在代码中添加lib文件链接指令

#pragma comment(lib, "libuv.lib")   //这个也可以通过配置项目属性来进行

windows下使用vs2008编译libuv库


3,Demo程序很简单,就一个main函数。

#include <stdio.h>
#include <stdlib.h>
#include "uv.h"

#pragma comment(lib, "libuv.lib")

int main() {
uv_loop_t *loop = uv_loop_new();

printf("Now quitting.\n");
uv_run(loop, UV_RUN_DEFAULT);

getchar();
return 0;
}

然后编译执行,当然了,肯定是编译不过去的,会报下面这个错误。

fatal error C1083: 无法打开包括文件:“stdint-msvc2008.h”: No such file or directory

因为我们的vs2008的_MSC_VER宏是1500,但是libuv要求最低1600也就是vs2010。然后对于vs2008以下的IDE要求提供stdint-msvc2008.h头文件,但是大海茫茫去哪里找那玩意。但是这个好办,用下面那4个宏来替换stdint-msvc2008.h就行了。

#if defined(_MSC_VER) && _MSC_VER < 1600
//# include "stdint-msvc2008.h"
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
# include <stdint.h>
#endif

然后再重新F7编译就行了。
windows下使用vs2008编译libuv库


编译libuv源代码

如果你想调试学习libuv源代码,那就要编译了,源代码在刚才下载的libuv-v1.12.0.tar.gz中,解压下来编译即可。
如果你发现libuv源代码有bug,想去社区贡献的话,那还要去github重新fork然后使用git工具clone到本地,修改好以后编译测试再push,然后pull request到libuv的master。
这都涉及到编译,编译确实复杂了点,因为涉及到一些其他的开源工具,比如gyp,但是gyp是用python写的,所以还要安装python。


1,下载安装python
官网说想编译gyp,python至少要2.6或者2.7版本以上。官网现在有python2和python3,你就去下载安装python2的最高版本就好了。
哦,对了,如果安装好了以后环境变量没有自动设置,那么还有手动设置,在环境变量-系统变量的Path中添加一条:

;C:\Python27

如果这个时候,你按照libuv官方手册直接cmd执行libuv目录中的vcbuild.bat,那么十之八九会发生下面的失败提示:

Failed to download gyp. Make sure you have git installed, or manually install gyp into E:\vs\testLibuv2\libuv-v1.12.0\build\gyp.

我连git工具都没有,我用的是github的图形客户端,就算是有了git工具也会可能会报那个错误。这是因为vcbuild.bat脚本中有下面的语句,意思就是脚本自动用你的git工具去下载gyp。

git clone https://chromium.googlesource.com/external/gyp build/gyp

你*了或者肉身*了无所谓,如果没*那我们必须使用其他方法来获取


2,手动获取gyp源码
gyp就是generate you project的缩写,是chromium团队在开发自己的项目时顺手开发的一个小工具,用来生成各个平台(windows、unix、osx、android…)的的工程文件。
gyp的获取途径在下面。

https://chromium.googlesource.com/external/gyp

但是正常人访问google的开源社区是被墙的,而且国内外镜像网站很少有它的镜像。但是有很多人已经把它搁在了github上,在github上搜索gyp,然后就看到了下面这张图。
windows下使用vs2008编译libuv库
这样的话,就省去了*的麻烦。选择一个靠谱的,直接下载到本地。
windows下使用vs2008编译libuv库
解压然后整个拷贝到我们的libuv源代码目录的build目录下,这样的话,我们就手动的实现了vcbuild.bat中指定的步骤:

git clone https://chromium.googlesource.com/external/gyp build/gyp


3,使用cmd命令重新运行libuv目录(你的目录可能叫libuv-v1.12.0)下的vcbuild.bat
windows下使用vs2008编译libuv库
这样就会生成下面的工程文件,我安装了vs2008和vs2017,所以得到2个工程文件
windows下使用vs2008编译libuv库
用vs2008打开最下面那个uv.sln解决方案,会出现3个项目,下面2个是测试用的。
windows下使用vs2008编译libuv库
好了,现在你终于可以编译libuv了,用它编译出来的是静态库。


如果想使用使用编译出来的libuv静态库,那还是要回到本文的直接使用DLL,但是正常情况下自己的test项目会链接不过去的,也就是链接会报如下的错。

LIBCMT.lib(sprintf.obj) : error LNK2005: _sprintf_s 已经在 msvcrtd.lib(MSVCR90D.dll) 中定义

原因:
我们所有的c程序都要使用crt(C RunTime),就好比如所有的java程序要有java RunTime(jvm),所有的php程序要有php RunTime,所有的javascript程序要有js RunTime一样。没有对应语言的RunTime,我们就用不了这个语言。
1,因为libuv的vs2008工程配置默认是静态链接crt的(debug方式下是/MTd,然后去链接libcmtd.lib;release方式下是/MT,然后去链接libcmt.lib)
2,自己的test工程默认是动态链接crt的(debug方式是/MDd,然后去链接msvcrtd.lib;而release方式是/MD,然后去链接msvcrt.lib)。所以使用的时候要注意避免crt冲突。
解决:
有两种方式:1,自己的test工程采用静态方式去链接crt。2,把libuv工程改为使用动态crt。然后两个工程要么都是release方式,要么都是debug方式,不然还是不匹配。
想知道进一步的原因,要参考本文末尾的文献5,它讲解了windows的链接器(link.exe)行为,非常的nice。

如图
windows下使用vs2008编译libuv库


参考文献:

1,Node.js之异步那些事,http://www.jianshu.com/p/59d8ba0b60ed
2,libuv 在win10vs各个版本编译静态,http://blog.csdn.net/longji/article/details/53954827
3,Cross-platform asynchronous I/O,http://libuv.org/
4,C99 stdint.h header and MS Visual Studio,https://*.com/questions/126279/c99-stdint-h-header-and-ms-visual-studio
5,链接器都干了些什么?http://www.cppblog.com/jacky2019/archive/2007/03/29/20891.html