轉自:https://blog.csdn.net/xufeng0991/article/details/44134005
libevent是一個常用的網絡庫,下面就看看在windows下面編譯測試的過程吧。
一 環境
系統:win8.1編譯器:VS2013
官方下載地址:http://libevent.org/
版本:2.0.22-stable
二 編譯靜態庫
1 解壓把上面下載到libevent-2.0.22-stable.tar.gz解壓,得到libevent-2.0.22-stable文件夾
2 添加宏定義
在libevent-2.0.22-stable文件夾下找到下面三個文件:
event_iocp.c
evthread_win32.c
listener.c
打開並在開頭加上宏定義:
#define _WIN32_WINNT 0x0500
因爲event_iocp.c裏用到<winbase.h>頭文件裏的函數定義,如InitializeCriticalSectionAndSpinCount,
<windows.h>會包含<winbase.h>,而<winbase.h>這個頭文件裏這個函數是這樣定義的:
#if (_WIN32_WINNT >= 0x0403)
WINBASEAPI
BOOL WINAPI
InitializeCriticalSectionAndSpinCount(
__out LPCRITICAL_SECTION lpCriticalSection,
__in DWORD dwSpinCount
);
WINBASEAPI
DWORD
WINAPI
SetCriticalSectionSpinCount(
__inout LPCRITICAL_SECTION lpCriticalSection,
__in DWORD dwSpinCount
);
#endif
所以要定義_WIN32_WINNT這個宏,而且值要大於0x0403。
如果沒有這個宏或不滿足條件,編譯器會假定這個函數沒有定義,
等到鏈接時再尋找它,這樣這個函數的符號就假定返回一個int,
而顯示標準庫文件裏這個函數不是返回int,所以在鏈接時就會找不到這個函數符號。
注意:宏一定要定義在#include <windows.h>之前,不然還是沒有作用。
3 編譯
使用vs的命令行工具,cd到libevent-2.0.22-stable目錄,執行腳本makefile.nmake,命令如下:
nmake /f Makefile.nmake
這樣就會生成三個靜態庫:
libevent_core.lib
libevent_extras.lib
libevent.lib
需要注意的是,在我使用的libevent是2.1.8版本里面的test文件夾缺少print-winsock-errors.c,使得編譯會出錯,可以在https://github.com/libevent/libevent/tree/patches-2.1下載其他的libevent版本,把裏面的print-winsock-errors.c複製到test文件夾裏,這樣便可以編譯成功。具體的print-winsock-errors.c附在文後。
並且啊,真的坑死人。libevent默認編譯的是release版本的,如果需要編譯debug版本的,修改一下makefile.nmake:
#CFLAGS=$(CFLAGS) /Ox /W3 /wd4996 /nologo
修改爲:
#CFLAGS=$(CFLAGS) /D_DEBUG /Od /W3 /wd4996 /nologo
三 使用示例
1 新建項目
新建一個控制檯“空”項目
2 拷貝文件
2.1 在項目目錄下建一個libevent文件夾2.2 在libevent中新建一個lib文件夾,將上面三個lib文件copy到該目錄下。
2.3 在libevent中再新建一個include文件夾,
將libevent-2.0.22-stable\include下的文件和文件夾copy到該目錄下,
將libevent-2.0.22-stable\WIN32-Code下的文件和文件夾copy到該目錄下,
2個event2目錄下的文件合併一起。
3 項目配置
VC++目錄:包含目錄,添加剛剛新建的include目錄
庫目錄,添加剛剛的lib目錄;
C/C++:
代碼生成-->運行庫:
Debug模式下選:多線程調試 (/MTd),
Release下模式下選:多線程 (/MT)
連接器:
輸入->附加依賴項:
ws2_32.lib
wsock32.lib
libevent.lib
libevent_core.lib
libevent_extras.lib
另外兩個庫ws2_32.lib和wsock32.lib是用來編譯Windows網絡相關的程序庫。
4 測試代碼
4.1 新建一個main.c文件4.2 從libevent-2.0.22-stable\sample目錄下拷貝time-test.c文件中的代碼到main中,代碼如下:
#include <sys/types.h>
#include <event2/event-config.h>
#include <sys/stat.h>
#ifndef WIN32
#include <sys/queue.h>
#include <unistd.h>
#endif
#include <time.h>
#ifdef _EVENT_HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <event2/event.h>
#include <event2/event_struct.h>
#include <event2/util.h>
#ifdef WIN32
#include <winsock2.h>
#endif
struct timeval lasttime;
int event_is_persistent;
static void timeout_cb(evutil_socket_t fd, short event, void *arg)
{
struct timeval newtime, difference;
struct event *timeout = arg;
double elapsed;
evutil_gettimeofday(&newtime, NULL);
evutil_timersub(&newtime, &lasttime, &difference);
elapsed = difference.tv_sec +
(difference.tv_usec / 1.0e6);
printf("timeout_cb called at %d: %.3f seconds elapsed.\n",
(int)newtime.tv_sec, elapsed);
lasttime = newtime;
if (!event_is_persistent) {
struct timeval tv;
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(timeout, &tv);
}
}
int main(int argc, char **argv)
{
struct event timeout;
struct timeval tv;
struct event_base *base;
int flags;
#ifdef WIN32
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD(2, 2);
(void)WSAStartup(wVersionRequested, &wsaData);
#endif
if (argc == 2 && !strcmp(argv[1], "-p")) {
event_is_persistent = 1;
flags = EV_PERSIST;
}
else {
event_is_persistent = 0;
flags = 0;
}
/* Initalize the event library */
base = event_base_new();
/* Initalize one event */
event_assign(&timeout, base, -1, flags, timeout_cb, (void*)&timeout);
evutil_timerclear(&tv);
tv.tv_sec = 2;
event_add(&timeout, &tv);
evutil_gettimeofday(&lasttime, NULL);
event_base_dispatch(base);
return (0);
}
libevent編譯文件裏需要的文件test\print-winsock-errors.c:
#include <winsock2.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include "event2/event.h"
#include "event2/util.h"
#include "event2/thread.h"
#define E(x) printf (#x " -> \"%s\"\n", evutil_socket_error_to_string (x));
int main (int argc, char **argv)
{
int i, j;
const char *s1, *s2;
#ifdef EVTHREAD_USE_WINDOWS_THREADS_IMPLEMENTED
evthread_use_windows_threads ();
#endif
s1 = evutil_socket_error_to_string (WSAEINTR);
for (i = 0; i < 3; i++) {
printf ("\niteration %d:\n\n", i);
E(WSAEINTR);
E(WSAEACCES);
E(WSAEFAULT);
E(WSAEINVAL);
E(WSAEMFILE);
E(WSAEWOULDBLOCK);
E(WSAEINPROGRESS);
E(WSAEALREADY);
E(WSAENOTSOCK);
E(WSAEDESTADDRREQ);
E(WSAEMSGSIZE);
E(WSAEPROTOTYPE);
E(WSAENOPROTOOPT);
E(WSAEPROTONOSUPPORT);
E(WSAESOCKTNOSUPPORT);
E(WSAEOPNOTSUPP);
E(WSAEPFNOSUPPORT);
E(WSAEAFNOSUPPORT);
E(WSAEADDRINUSE);
E(WSAEADDRNOTAVAIL);
E(WSAENETDOWN);
E(WSAENETUNREACH);
E(WSAENETRESET);
E(WSAECONNABORTED);
E(WSAECONNRESET);
E(WSAENOBUFS);
E(WSAEISCONN);
E(WSAENOTCONN);
E(WSAESHUTDOWN);
E(WSAETIMEDOUT);
E(WSAECONNREFUSED);
E(WSAEHOSTDOWN);
E(WSAEHOSTUNREACH);
E(WSAEPROCLIM);
E(WSASYSNOTREADY);
E(WSAVERNOTSUPPORTED);
E(WSANOTINITIALISED);
E(WSAEDISCON);
E(WSATYPE_NOT_FOUND);
E(WSAHOST_NOT_FOUND);
E(WSATRY_AGAIN);
E(WSANO_RECOVERY);
E(WSANO_DATA);
E(0xdeadbeef); /* test the case where no message is available */
/* fill up the hash table a bit to make sure it grows properly */
for (j = 0; j < 50; j++) {
int err;
evutil_secure_rng_get_bytes(&err, sizeof(err));
evutil_socket_error_to_string(err);
}
}
s2 = evutil_socket_error_to_string (WSAEINTR);
if (s1 != s2)
printf ("caching failed!\n");
libevent_global_shutdown ();
return EXIT_SUCCESS;
}