zoukankan      html  css  js  c++  java
  • 移植 libuv 至 Visual C++ 6.0 并支持 Windows XP 编译系统


    移植版本 libuv:https://github.com/liigo/libuv-vc6 (支持VC6和XP。作者Liigo)。


    我从一年前(大概2013年6,7月份)開始在业余时间做这项移植工作,走走停停,陆续用了一两个月的时间。才基本完毕。这期间做了具体的移植记录。如今公布出来,希望对某些人实用。就在昨天(2014年7月12日)。我又把移植的代码同步到最新的libuv(https://github.com/joyent/libuv)并公布到Github上;可是之前的移植记录没有变更,也许在一定程度上已经部分失效了。

    我(Liigo)当初做这项移植工作的原始意图。是打算做一个封装 libuv 的易语言支持库。然而终究还没有做。

    理由是没有时间呢,缺乏需求呢,还是懒呢?我临时不想下结论。

    此移植版 libuv-vc6 的完整性和准确性尚未得到证明。

    可是我的tinyweb 已经基于该移植版编译,而且在Windows XP系统下运作正常。我想这能证明至少它是“基本可用”的。





    VC6系统文件 MSWSOCK.H 编译时报错,说不认识“SOCKET”类型:
    解决的方法,在前面添加 typedef unsigned int  SOCKET;


    uv-win.h 报错说 SRWLOCK 没有定义,解决的方法是在前面添加:
    //http://blog.csdn.net/xiewneqi/article/details/4787156
    typedef struct SRWLOCK {
    void* ptr;
    } SRWLOCK, *PSRWLOCK;



    uv.h 没有定义 sockaddr_storage,解决的方法是在前面添加:
    //http://stackoverflow.com/questions/1345109/why-sockaddr-storage-structure-defined-as-the-way-it-is-defined
    struct sockaddr_storage {
    short   ss_family;
    char    __ss_pad1[6];
    int64_t __ss_align;
    char    __ss_pad2[112];
    };


    uv.h 报错说标识符 LPFN_CONNECTEX 语法错误。解决的方法:
    将 uv-win.h 内全部 " PASCAL (*" 替换为 " (PASCAL *" 。


    把 LPFN_CONNECTEX 的定义从 uv-win.h 拷贝到 uv.h 报错行之前。




    uvsrcwinapi.h '_REPARSE_DATA_BUFFER'重定义,解决的方法:删除定义,或凝视掉/*defined(_MSC_VER) ||*/
    ULONG_PTR 没有定义,增加 typedef unsigned int* ULONG_PTR;


    uvsrcwinapi.h 没有定义LPOVERLAPPED_ENTRY?增加下面代码:
    typedef struct _OVERLAPPED_ENTRY {
      ULONG_PTR    lpCompletionKey;
      LPOVERLAPPED lpOverlapped;
      ULONG_PTR    Internal;
      DWORD        dwNumberOfBytesTransferred;
    } OVERLAPPED_ENTRY, *LPOVERLAPPED_ENTRY;


    缺少文件iptypes.h? 在以下链接下载后放到uvsrcwin
    http://stuff.mit.edu/afs/athena/astaff/project/opssrc/nmap-2.54BETA34/mswin32/IPTypes.h


    ERROR_INVALID_REPARSE_DATA没有定义?改动为 0x00001128/*ERROR_INVALID_REPARSE_DATA*/


    INVALID_FILE_ATTRIBUTES没有定义?改动为 (DWORD)-1/*INVALID_FILE_ATTRIBUTES*/


    'bad suffix on number'?把数值后面的ULL删除就可以(10000000ULL -> 10000000)


    EAI_BADFLAGS等EAI_*没有定义?增加下面代码:
    /* Error codes from getaddrinfo() */
    #define EAI_AGAIN           WSATRY_AGAIN
    #define EAI_BADFLAGS        WSAEINVAL
    #define EAI_FAIL            WSANO_RECOVERY
    #define EAI_FAMILY          WSAEAFNOSUPPORT
    #define EAI_MEMORY          WSA_NOT_ENOUGH_MEMORY
    #define EAI_NOSECURENAME    WSA_SECURE_HOST_NOT_FOUND
    //#define EAI_NODATA        WSANO_DATA
    #define EAI_NONAME          WSAHOST_NOT_FOUND
    #define EAI_SERVICE         WSATYPE_NOT_FOUND
    #define EAI_SOCKTYPE        WSAESOCKTNOSUPPORT
    #define EAI_IPSECPOLICY     WSA_IPSEC_NAME_POLICY_ERROR


    addrinfo/addrinfoW没有定义?在uv.h前面增加下面代码:
    //http://msdn.microsoft.com/en-us/library/windows/desktop/ms737530(v=vs.85).aspx
    typedef struct addrinfo {
      int             ai_flags;
      int             ai_family;
      int             ai_socktype;
      int             ai_protocol;
      size_t          ai_addrlen;
      char            *ai_canonname;
      struct sockaddr  *ai_addr;
      struct addrinfo  *ai_next;
    } ADDRINFOA, *PADDRINFOA;
    //http://msdn.microsoft.com/en-us/library/windows/desktop/ms737529(v=vs.85).aspx
    typedef struct addrinfoW {
      int              ai_flags;
      int              ai_family;
      int              ai_socktype;
      int              ai_protocol;
      size_t           ai_addrlen;
      PWSTR            ai_canonname;
      struct sockaddr  *ai_addr;
      struct addrinfoW  *ai_next;
    } ADDRINFOW, *PADDRINFOW;


    WT_EXECUTELONGFUNCTION没有定义?替换为 0x00000010/*WT_EXECUTELONGFUNCTION*/
    WT_EXECUTEONLYONCE没有定义?替换为 0x00000008/*WT_EXECUTEONLYONCE*/


    in6_addr没有定义?在错误提示行前增加下面代码:
    struct in6_addr {
      u_char  s6_addr[16];
    };


    FILE_FLAG_FIRST_PIPE_INSTANCE没有定义?替换为 0x00080000/*FILE_FLAG_FIRST_PIPE_INSTANCE*/


    JOBOBJECT_EXTENDED_LIMIT_INFORMATION没有定义?在前面增加下面代码:
    typedef struct _JOBOBJECT_EXTENDED_LIMIT_INFORMATION {
      JOBOBJECT_BASIC_LIMIT_INFORMATION BasicLimitInformation;
      IO_COUNTERS                       IoInfo;
      SIZE_T                            ProcessMemoryLimit;
      SIZE_T                            JobMemoryLimit;
      SIZE_T                            PeakProcessMemoryUsed;
      SIZE_T                            PeakJobMemoryUsed;
    } JOBOBJECT_EXTENDED_LIMIT_INFORMATION, *PJOBOBJECT_EXTENDED_LIMIT_INFORMATION;


    IO_COUNTERS没有定义?在前面增加下面代码:
    typedef struct _IO_COUNTERS {
      ULONGLONG ReadOperationCount;
      ULONGLONG WriteOperationCount;
      ULONGLONG OtherOperationCount;
      ULONGLONG ReadTransferCount;
      ULONGLONG WriteTransferCount;
      ULONGLONG OtherTransferCount;
    } IO_COUNTERS, *PIO_COUNTERS;


    JOB_OBJECT_LIMIT_BREAKAWAY_OK等没有定义?在前面增加下面代码:
    #define JOB_OBJECT_LIMIT_SCHEDULING_CLASS       0x80
    #define JOB_OBJECT_LIMIT_PROCESS_MEMORY         0x100
    #define JOB_OBJECT_LIMIT_JOB_MEMORY             0x200
    #define JOB_OBJECT_LIMIT_DIE_ON_UNHANDLED_EXCEPTION 0x400
    #define JOB_OBJECT_LIMIT_BREAKAWAY_OK           0x800
    #define JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK    0x1000
    #define JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE      0x2000


    NOINLINE未被识别?替换为 /*NOINLINE*/


    ((ULONG_PTR) req->event_handle | 1) 语法错误? 改为 ((DWORD) req->event_handle | 1)


    IPPROTO_IPV6没有定义?替换为 41/*IPPROTO_IPV6*/


    IPV6_MULTICAST_HOPS没有定义?替换为 10/*IPV6_MULTICAST_HOPS*/
    IPV6_MULTICAST_LOOP没有定义?替换为 11/*IPV6_MULTICAST_LOOP*/


    WSAID_CONNECTEX没有定义?替换为 {0x25a207b9,0xddf3,0x4660,{0x8e,0xe9,0x76,0xe5,0x8c,0x74,0x06,0x3e}}/*WSAID_CONNECTEX*/


    JobObjectExtendedLimitInformation没有定义?替换为 9/*JobObjectExtendedLimitInformation*/


    UnregisterWait,UnregisterWaitEx,RegisterWaitForSingleObject等没有定义?在winapi.h中增加下面代码:
    typedef BOOL (WINAPI* sUnregisterWait) (HANDLE WaitHandle);
    typedef BOOL (WINAPI* sUnregisterWaitEx) (HANDLE WaitHandle, HANDLE CompletionEvent);
    typedef VOID (CALLBACK* WAITORTIMERCALLBACK) (PVOID lpParameter, BOOLEAN TimerOrWaitFired);
    typedef BOOL (WINAPI* sRegisterWaitForSingleObject)
                 (PHANDLE phNewWaitObject,
                  HANDLE hObject,
                  WAITORTIMERCALLBACK Callback,
                  PVOID Context,
                  ULONG dwMilliseconds,
                  ULONG dwFlags);
    然后在winapi.h/.c中參考原有代码补充必需的代码(定义函数指针变量、对其赋值等),然后把对UnregisterWait的调用改为pUnregisterWait(其它类推)。
    对于其它在链接时找不到符号的Windows API函数,一并做如上处理。

    对于GetProcessMemoryInfo函数要做特殊处理。在两个系统DLL去找事实上现函数地址:
    -----------------------------------------------------
      //http://msdn.microsoft.com/en-us/library/windows/desktop/ms683219(v=vs.85).aspx
      pGetProcessMemoryInfo = (sGetProcessMemoryInfo)
        GetProcAddress(kernel32_module, "GetProcessMemoryInfo");
      if(pGetProcessMemoryInfo == NULL) {
        pGetProcessMemoryInfo = (sGetProcessMemoryInfo)
          GetProcAddress(GetModuleHandleA("Psapi.dll"), "GetProcessMemoryInfo");
      }
    -----------------------------------------------------


    找不到IPHlpApi.h?在这里下载:
    https://docs.google.com/file/d/0B-VpknkVIm1fdnNabE1ScmlLazQ/edit?usp=sharing
    为防止“反复定义IN6_ADDR”的编译错误,须要在 #include "Iphlpapi/iphlpapi.h" 之前先 #define s6_addr 。


    找不到psapi.h?在这里下载:
    https://docs.google.com/file/d/0B-VpknkVIm1fU3pDRTBDM3JXOWM/edit?usp=sharing


    GlobalMemoryStatusEx没有定义?在winapi.h增加下面代码:
    typedef struct _MEMORYSTATUSEX {
      DWORD     dwLength;
      DWORD     dwMemoryLoad;
      DWORDLONG ullTotalPhys;
      DWORDLONG ullAvailPhys;
      DWORDLONG ullTotalPageFile;
      DWORDLONG ullAvailPageFile;
      DWORDLONG ullTotalVirtual;
      DWORDLONG ullAvailVirtual;
      DWORDLONG ullAvailExtendedVirtual;
    } MEMORYSTATUSEX, *LPMEMORYSTATUSEX;
    typedef BOOL (WINAPI* sGlobalMemoryStatusEx) (LPMEMORYSTATUSEX lpBuffer);
    然后在winapi.h/.c中參考原有代码补充必需的代码(定义函数指针变量、对其赋值等),然后把对GlobalMemoryStatusEx的调用改为pGlobalMemoryStatusEx。


    IP_ADAPTER_UNICAST_ADDRESS_XP没有定义?替换为IP_ADAPTER_UNICAST_ADDRESS,然后
    #include "Iphlpapi/iptypes.h" (来源见上文)
    由于该头文件里定义的IP_ADAPTER_UNICAST_ADDRESS实质上就是IP_ADAPTER_UNICAST_ADDRESS_XP。


    wmemcmp没有定义?把原代码 wmemcmp(data_block->Signature, L"PERF", 4) 改动为:
    memcmp(data_block->Signature, L"PERF", 4 * sizeof(TCHAR))


    IF_TYPE_SOFTWARE_LOOPBACK没有定义?替换为 24/*IF_TYPE_SOFTWARE_LOOPBACK*/


    'sin6_scope_id' : is not a member of 'sockaddr_in6'?

    凝视掉 uv-win.h 内的宏定义 UV_PLATFORM_HAS_IP6_LINK_LOCAL_ADDRESS。
    或者增加以下的定义:
    /* The ws2tcpip.h header included in VC6 doesn't define the
     * sin6_scope_id member of sockaddr_in6.  We define our own
     * version and redefine sockaddr_in6 to point to this one.
     */
    struct liigo_sockaddr_in6 {
      short sin6_family;
      u_short sin6_port;
      u_long sin6_flowinfo;
      struct in6_addr sin6_addr;
      u_long sin6_scope_id;
    };
    #define sockaddr_in6 liigo_sockaddr_in6


    调用swprintf參数过多?swprintf(path2, len + 3, fmt, pathw)改为swprintf(path2, fmt, pathw)


    _set_invalid_parameter_handler是VC2005才增加到CRT函数,VC6里面没有。

    在libuv源码里面直接凝视掉对该函数的调用就可以。


    _BitScanReverse没有定义?在前面增加下面代码,然后删除VC下对_BitScanReverse的调用,统一用GCC版代码就可以:
    //http://stackoverflow.com/questions/355967/how-to-use-msvc-intrinsics-to-get-the-equivalent-of-this-gcc-code
    #ifndef __GNUC__
    static unsigned int __declspec(inline) popcnt( unsigned int x )
    {
        x -= ((x >> 1) & 0x55555555);
        x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
        x = (((x >> 4) + x) & 0x0f0f0f0f);
        x += (x >> 8);
        x += (x >> 16);
        return x & 0x0000003f;
    }
    static unsigned int __declspec(inline) __builtin_clz( unsigned int x )
    {
        x |= (x >> 1);
        x |= (x >> 2);
        x |= (x >> 4);
        x |= (x >> 8);
        x |= (x >> 16);
        return 32 - popcnt(x);
    }
    static unsigned int __declspec(inline) __builtin_ctz( unsigned int x )
    {
        return popcnt((x & -x) - 1);
    }
    #endif
    另外一个模拟实现_BitScanReverse的思路也是可行的:http://bbs.csdn.net/topics/350202744


    _InterlockedOr8没有定义?又一次实现uv__atomic_exchange_set例如以下:
    static char __declspec(inline) uv__atomic_exchange_set(char volatile* target) {
      //return _InterlockedOr8(target, 1);
      __asm mov ecx, target
      __asm mov al, byte ptr [ecx]
      __asm lock or byte ptr [ecx], 1
    }


    _aligned_malloc, _aligned_free, 等函数没有定义?自己实现这两个函数,代码例如以下:
    static void* _aligned_malloc(unsigned int size, unsigned int align) {
      unsigned int rem;
      unsigned char *op, *np;
      op = (unsigned char*) malloc(size + align);
      if(op == NULL) return NULL;
      rem = (unsigned int)op % align;
      np = op + align - rem;
      *(np-1) = (unsigned char)align - rem;
      return np;
    }
    static void _aligned_free(void* p) {
      if(p) {
        unsigned char n = *((unsigned char*)p - 1);
        free((unsigned char*)p - n);
      }
    }


    InterlockedCompareExchangePointer在新版VC中是编译器生成的函数。并不存在于kernel.dll里面,而VC6显然不可能生成该函数。解决的方法:
    pInterlockedCompareExchangePointer = (sInterlockedCompareExchangePointer) GetProcAddress(kernel32_module, "InterlockedCompareExchange");
    //VC6 always create x86 programs. 由于VC6总是生成32位程序。不可能调用64位版的函数。


    缺少常量IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP?在前面增加例如以下代码:
    #ifndef IPPROTO_IPV6
    #define IPPROTO_IPV6 41
    #endif


    #ifndef IPV6_MULTICAST_IF
    #define IPV6_MULTICAST_IF 9
    #endif
    #ifndef IPV6_ADD_MEMBERSHIP
    #define IPV6_ADD_MEMBERSHIP 12
    #endif
    #ifndef IPV6_DROP_MEMBERSHIP
    #define IPV6_DROP_MEMBERSHIP 13
    #endif


    常量ERROR_INVALID_REPARSE_DATA没定义?改成以下这样:
    4392/*ERROR_INVALID_REPARSE_DATA*/


    版权声明:这篇文章的博客Liigo原版的,不得擅自转载。

  • 相关阅读:
    create-react-app搭建的项目中添加bootstrap
    用es6的Array.reduce()方法计算一个字符串中每个字符出现的次数
    为Docker配置阿里加速器,系统为Debian8
    基于Spring Boot,使用JPA动态调用Sql查询数据
    基于Spring Boot,使用JPA调用Sql Server数据库的存储过程并返回记录集合
    基于Spring Boot,使用JPA操作Sql Server数据库完成CRUD
    ES6,Array.includes()函数的用法
    【编程风格】c++命名约定
    【转】吴恩达的视频课程做成了文字版 ~~~
    【专业学习】常用的技术网站
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4862096.html
Copyright © 2011-2022 走看看