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 目录下。
到此为止,应该就可以编译并运行出来了。
没写过博客,写的不好,纯粹个人学习总结,分享出来,需要可以参考,感兴趣的可以一起交流。
https://my.oschina.net/u/3364259/blog/1503532