libevent在windows下使用步驟詳解及使用libevent編譯失敗的解決方案(轉)

轉自: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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章