当前位置:首页 » 电脑基础知识

win10+vs2008编译比特币1.0版源码总结

2017-08-06 23:43 本站整理 浏览(6)

https://zhuanlan.zhihu.com/p/25074960

https://zhuanlan.zhihu.com/p/25095222

总体上是参考这两个链接,感谢大神的分享,但是中间遇到很多问题,也学到很多,现总结如下:

以下是基于win10 64 位& Visual Studio 2008平台(不是标配,我电脑就是win10,vs2008也是之前项目用到装的)

一、源码

这里用的是bitcoin-0.1.0版本

二、配置依赖库

a)         wxWidgets (3.0.3版本)

http://blog.csdn.net/sxhelijian/article/details/26163791安装参考链接

没有为什么,上面大神用的3.1.0版本,我只是之前学习的时候安装过这个版本的。

安装方法:到http://www.wxwidgets.org/downloads/下载Windows ZIP版本,解压,

接下来对wxwidgets文件进行编译,这里用到了mingw32-make命令,由于我之前安装过codeblocks-13.12mingw-setup的缘故,这一步我直接可以进行,总结就不写,codeblocks安装还是比较简单的。不过这里有一些环境变量配置的问题。环境变量设置就不说了,C:\Program Files (x86)\CodeBlocks\MinGW\bin

命令行进入wxwidgets的解压目录,输入以下命令:

mingw32-make -f makefile.gcc MONOLITHIC=1 SHARED=1 UNICODE=1 BUILD=debug

这可能需要很久

b)         openssl (1.0.2版本)

上面大神说的1.0.2后会出问题我没有试,还不清楚,现在的目的是编译通过。

安装方法就是上面提到的取巧的方法

c)         Berkeley DB (4.8.30 版本)

这里我下载是Windows安装版,所以没有编译源码的过程,还是很简单的。下载地址:http://www.oracle.com/technetwork/cn/products/berkeleydb/downloads/index-086374-zhs.html

d)         Boost (1.63.0 版本)

下载及介绍:

http://www.boost.org/doc/libs/1_63_0/more/getting_started/windows.html#header-only-libraries

三、使用vs的从“源码导入”导入bitcoin源码

这里我们把src/ 目录当作根目录。

新建立一个目录,比如叫做bitcoin什么的随便好啦。然后把src/目录下的所有文件都拷贝到这个新的目录下。我们现在把这个新的目录当做 / 。之后的描述都针对 / 作为根目录进行。

打开vs

点击新建

从现有代码创建项目

弹出对话框,选择默认的Visual C++ ,点击下一步

项目位置填写上刚才的 / 目录的位置,项目名称取名 bitcoin-v0.1或者其他你喜欢的项目名字,点击下一步

使用visual studio ->项目类型选择“Windows 应用程序项目” (就是说直接使用默认),其他的不动,点击下一步

点击完成

此时就已经新创建了项目,并导入的源码。

四、配置

这步是很关键的第一步

现在我们先假设把刚才配置好的4个依赖库都设置成环境变量(如果不设置环境变量也行,那么等会在配置项目的依赖的时候就填写路径就好了。)

回到桌面->对“此电脑”右键->属性->高级系统设置->环境变量->在系统变量的部分开始创建环境变量

点击新建:

举例:wsWidgets =>那么就在变量名写上WXWidgetsPath,然后变量值填写刚才安装(解压)widgets的根目录

其他3个依赖库同理,则总共配置了4个环境变量:

WXWidgetsPath

OpenSSLPath

BDBPath

BoostPath

当然上面这4个环境变量的名字是我乱取的,并没有什么约定,你可以根据自己想象取想取的名字。这里取这4个变量等会我们就会在项目的配置中引用这4个变量,自己取的名字等会就换成自己取的就好了。

此时先关闭刚才创建的项目,然后再重新启动(这个是为了让vs加载刚才取的环境变量,如果没配置环境变量用不着重启vs)

在解决方案中右键刚才创建的项目,选择属性。

a)         设置unicode字符集

注意,这步的配置不是必须,如果你的wxWidgets是老版本(似乎是小于2.8?)或者你在编译wxWidgets库的时候选择关闭unicode开关,编译除了非unicode的wxWidgets的库时,可以直接跳过这步,不设置unicode字符集。否则在等会启动编译的时候会出现wxWidgets的setup.h找不到路径。

如果你是vs编译的,那么一定要设置unicode字符集。

在配置属性-常规中找到项目默认值 - 字符集

点击下拉框,选择使用 Unicode 字符集

b)         设置VC++依赖项

在配置属性-VC++目录下找到包含目录和库目录,点击包含目录,填写

$(WXWidgetsPath)\include

$(WXWidgetsPath)\include\msvc

(注意这里的WXWidgetsPath就是刚才配置的环境变量,如果没有配置,就直接填写wxWidgets的路径加上include路径,以下同理)

这样就引入了wxWidgets库的头文件路径以及 lib 路径。

注:因为wxWidgets库是和windows应用程序绑定的,不是普通的c++依赖库,所以必须在VC++的部分设置,否则,wxWidgets会不能通过编译。

c)         设置C++依赖

在配置属性 - c/c++ - 常规中找到“附加包含目录”,点击编辑,填写:

$(BoostPath)

$(OpenSSLPath)\include

$(BDBPath)\include

这样就引入了 boost,openssl, bdb的头文件路径

在配置属性 - 链接器 -常规中找到“附加库目录”,点击编辑,填写:

$(OpenSSLPath)\lib

$(BDBPath)\lib  // 注意这条可能根据你的环境改变

(加粗|醒目) oracle神坑的地方在这里就体现出来了。$(BDBPath)\lib指代的bdb的 libs 的路径,但是!因为我们编译的是 debug 项目,所以等会只能引入 debug 的dll(lib) (如果正常应该是可以引入release的lib的,但是对于bdb来说,debug项目使用release的dll在运行free()的时候会崩溃/(ㄒoㄒ)/~~)。

但是引入debug后,源安装包中的 debug的dll似乎是有问题的(加粗),会直接引起程序崩溃!!(不清楚我是不是个例。如果出现了这个问题,请重新在自己的电脑上编译debug版本的bdb,把$(BDBPath)\lib换成新的路径,参考下一篇文章)

在配置属性 - 链接器 -输入中找到“附加依赖项”,点击编辑,填写:

libeay32.lib

libdb48d.lib  // 注意这个是带 'd' 的,也就是 debug 的dll库

然后打开资源管理器(就是点我的电脑。。),找到这个项目的目录,在本项目根目录 / 下创建 libs/ 目录,拷贝

$(OpenSSLPath) 目录下的 libeay32.dll

$(BDBPath)\bin\debug 目录下的libdb48d.dll

进入 libs 目录。

注意,刚才描述的问题的dll就是这个 libdb48d.dll,如果出问题了,很可能需要替换成自己编译的dll

然后回到 VS 的项目配置中

在配置属性 - 生成事件 - 后期生成事件中找到“命令行”

填写上:

xcopy /y /d  "$(ProjectDir)libs\*.dll" "$(OutDir)"

这个command的 libs 就是刚才在项目的根目录下创建的 libs/ 目录。所以这句话的意思就是把 libs/ 目录下的dll都拷贝到输出目录中(这里指代的就是 Debug 目录)

五、修改源码

错误

1. headers.h

vc6++ 与 vc9以上平台冲突

因为源码应该是在vc6++的平台下编译完成的,所以首先要先移除对于winnt的预定义,否则会产生兼容性问题。

找到headers.h文件,在第10行发现:

#ifdef _WIN32_WINNT

#undef _WIN32_WINNT

#endif

#define _WIN32_WINNT 0x0400 // 删除这4行

将这4行都注释掉,或者删除。

windows.h与 winsokc2.h 顺序

找到headers.h文件第23行发现:

#include <windows.h>

#include <winsock2.h>

#include <mswsock.h> // 把windows.h移动到最下面

移动windows.h得到

#include <winsock2.h>

#include <mswsock.h>

#include <windows.h>

或者引入一个宏也可以解决windows.h头文件引入的问题:

#define _WINSOCKAPI_    // stops windows.h including winsock.h

#include <windows.h>

// ...

#include "MyClass.h"    // Which includes <winsock2.h>

之后找到 net.cpp 文件,第5行交换头文件引入

#include "headers.h"

#include <winsock2.h> // 和上面一样互换这两行

// =>

#include <winsock2.h>

#include "headers.h"

2. c++11 与现存代码冲突

net.h/net.c boost::array 与c++11 的std::array 冲突

找到net.h文件,在第419行发现

extern array<bool, 10>vfThreadRunning; // 添加命名空间

//  修改为 =>

extern boost::array<bool, 10>vfThreadRunning; // 添加命名空间

找到net.c文件,第26行进行同样更改

array<bool, 10>vfThreadRunning;

//  修改为 =>

boost::array<bool, 10>vfThreadRunning;

winsock.h的 bind 函数与std::bind 冲突

找到net.c文件,第937行

if (bind(hListenSocket, (structsockaddr*)&sockaddr, sizeof(sockaddr))

== SOCKET_ERROR) // bind函数冲突

// 转变为=>

if (::bind(hListenSocket, (structsockaddr*)&sockaddr,

sizeof(sockaddr)) == SOCKET_ERROR) // 添加上::global 命名空间

3. serialize.h insert函数const char*想要强制转换为const_iterator

找到serialize.h文件,在第 808 行发现一个根据宏的定义

#if !defined(_MSC_VER) || _MSC_VER >= 1300

void insert(iterator it, const char* first, const char* last)

{

insert(it, (const_iterator)first, (const_iterator)last);

}

#endif

修改为

#if !defined(_MSC_VER) || _MSC_VER >= 1300

void insert(iterator it, const char* first, const char* last)

{

vector_type v(first, last);

insert(it, v.begin(), v.end());

}

#endif

4. 似乎是关于MSVC8 allocator的兼容问题(不确定)

文件serialize.h第699行

typedef vector<char,constsecure_allocator<char>>vector_type;

// 修改为=>也就是把作者原来写的这个secure_allocator移除,使用vector自带的。

typedef vector<char>vector_type;

同时因为vector_type的typedef已经等同于vector<char>,所以对于CDataStream类的构造函数也要更改

文件serialize.h第741行, 删除或着注释掉这个构造函数

//CDataStream(const vector<char>&vchIn, intnTypeIn=0, int

VersionIn=VERSION) :vch(vchIn.begin(), vchIn.end())

//{

//    Init(nTypeIn, nVersionIn);

//}

文件key.h第40行

typedef vector<unsigned char, constsecure_allocator<unsigned char>>

CPrivKey;

// =>修改方式同上

typedef vector<unsigned char>CPrivKey;

5. unicode字符的替换

ps: 若使用低版本的wxwidgets,总之就是没开启unicode宏的话不需要替换

util.cpp文件的第74行

long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, "Global", NULL,

NULL, pdata, &nSize);

// 把“Global”字符串该为 win32 支持的unicode =>

long ret = RegQueryValueEx(HKEY_PERFORMANCE_DATA, L"Global", NULL,

NULL, pdata, &nSize);

// 或者换成另一个版本的win API也行

long ret = RegQueryValueExA(HKEY_PERFORMANCE_DATA, "Global", NULL,

ULL, pdata, &nSize);

第173行

GetModuleFileName(NULL, pszModule, sizeof(pszModule));

//在unicode宏定义下的GetModuleFileName是宽字符版本,直接替换成Acsii版本=>

GetModuleFileNameA(NULL, pszModule, sizeof(pszModule));

第272行

returnGetFileAttributes(psz) != -1;

// 与上面同理 =>

returnGetFileAttributesA(psz) != -1;

util.h文件的第274行

OutputDebugString(p1);

// 与上同理  =>

OutputDebugStringA(p1);

6. ui.cpp / ui.h错误

ui.cpp 第254行,关于wsString的迭代器填充构造函数无法自动转化的问题 (或许当wxWidgets版本低的时候不会出现这个问题)

returnCDataStream(strData.begin(), strData.begin() + event.GetInt(), SER_NETWORK);

// 替换成为 =>

const char* s = strData.mb_str();

returnCDataStream(s, s + event.GetInt(), SER_NETWORK);

类似的第2650,wsString到std::string的转换

wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]->GetLabel(),

strValue));

// 把wsString调用ToStdString()  =>

wtx.vOrderForm.push_back(make_pair(m_staticTextLabel[i]-

>GetLabel().ToStdString(), strValue));

ui.cpp 第1245行,字符缺少引号

ps: 强调!这里缺少引号,是因为本来源码中这里是个十分奇怪的字符,在导入vs后打开的时候就被转义了。所以这里的?实际上是代表原来的一个字符。但是这个函数并没什么鸟用,所以这里随便改正就好,不用还原原来的意思。

if (str.Find('?) != wxNOT_FOUND)

str.Remove(str.Find('?), 1);

//  添加上缺失的引号

if (str.Find('?') != wxNOT_FOUND)

str.Remove(str.Find('?'), 1);

2890行,宽字符

_CrtSetReportFile(_CRT_WARN, CreateFile("NUL", GENERIC_WRITE, 0, NULL,

OPEN_EXISTING, 0, 0));

// =>

_CrtSetReportFile(_CRT_WARN, CreateFile(L"NUL", GENERIC_WRITE, 0, NULL,

OPEN_EXISTING, 0, 0));

2913行,同上

HWND hwndPrev = FindWindow("wxWindowClassNR", "Bitcoin");

// =>

HWND hwndPrev = FindWindow(L"wxWindowClassNR", L"Bitcoin");

3148行,对于3.0以上的wxWidgets版本来说AddPendingEvent()函数已废弃,需要依靠eventhandler才能调用。

//pframeMain->AddPendingEvent(event);

pframeMain->GetEventHandler()->AddPendingEvent(event);

7. 去除因跨平台带来的兼容问题

文件util.h第161行

inline string i64tostr(int64 n)

{

returnstrprintf("%"PRId64, n); 

// 其中的PRId64 是为了跨平台带来的,修改为下面的代码

// =>因为这里不关心跨平台问题,只把环境限制在win64上,所以不必担心int64的问题

returnstrprintf("%l", n);

}

8. berkeleydb版本为6.2+后的修改兼容 (使用4.7或4.8版本则无需考虑)

文件db.cpp 第18行

DbEnvdbenv(0);

// =>

DbEnvdbenv((u_int32_t)0);

警告

源码中出现的警告多半是因为符号隐式转换的问题,这个根据自己需要修改就行。

六、解决wx依赖库的问题

http://www.cnblogs.com/waynecheng/archive/2012/04/18/2455765.html

按上述方法修改源码后运行会出现找不到“wx/msw/wx.rc”,这需要引入资源文件,设置资源目录,项目->属性->资源->常规->附加包含目录:E:\wxWidgets-3.0.3\include

接下来会出现一大堆error LNK2019: 无法解析的外部符号,这种错误,这是需要重新编译wx,步骤如下:

进入E:\wxWidgets-3.0.3\build\msw目录,Visual Studio 2008打开wx_vc9.sln,生成解决方案,之后会看到在\lib下生成vc_lib文件夹,其中包括生成的相应的.lib等文件和mswud文件夹。到此,wxWidgets编译完毕。

项目设定

右键单击项目->属性->C/C++->常规

【附加包含目录】 = "$(wxWin)\lib\vc_lib\mswud"

项目属性->连接器->常规

【附加库目录】= "$(wxWin)\lib\vc_lib\"

项目属性->连接器->输入

【附加依赖项】=

wxmsw29ud_core.lib

wxbase29ud.lib

wxtiffd.lib

wxjpegd.lib

wxpngd.lib

wxzlibd.lib

wxregexud.lib

wxexpatd.lib

winmm.lib

comctl32.lib

rpcrt4.lib

wsock32.lib

odbc32.lib

再次编译运行就可以了

七、运行

以上的部分只是解决在编译期出现的问题,大头是需要让bitcoin能够运行起来(惨····)

接下来将详细描述如何修改代码让bitcoin运行起来。

好累。。

这里我只说我遇到的问题,

原因就不说了,我也没看懂,直接来解决办法,

因为安装包中的release和debug都无法运行,所以只能自己编译出Berkeley DB的lib和dll

假设现在的berkeleydb的根目录是 \<bdbroot>

那么在 \<bdbroot>\db-4.8.30\build_windows目录下可以找到 Berkeley_DB.sln

打开它向上兼容后,进行项目构建,然后将一个example项目设为主项目进行运行。如果能运行成功就是构建成功并且能够正常运行。

此时在 \<bdbroot>\db-4.8.30\build_windows\Win32\Debug\ 目录下可以发现 libdb48d.lib 和 libdb48d.dll 这两个文件。而这两个文件就是在自己平台上编译出来的动态链接库。

之后把bitcoin源码的关于Berkeley DB 的依赖库修改为新的路径,然后就可以正常运行了。。。

这里修改的路径就是 $(BDBPath)\db-4.8.30\build_windows\Win32\Debug\ (参照上一篇)

然后把 libdb48d.dll 拷贝到 bitcoin项目的 libs 目录下。

到此为止,应该就可以编译并运行出来了。

没写过博客,写的不好,纯粹个人学习总结,分享出来,需要可以参考,感兴趣的可以一起交流。