vs2013編譯bitcoin原始碼(bitcoin-0.9.4)
proto下的.h、.cc檔案是用工具Protobuf生成的,後面介紹。
在bitcoin-qt-test工程中新增src\qt\test目錄下的檔案。新增bitcoin-qt的程式碼檔案。工程結構如下:
第四節 設定工程屬性
設定工程屬性,除了設定前面介紹的依賴庫的相關路徑、lib庫外,還有些特殊設定,這裡特別介紹。
1、bitcoin-cli、bitcoind、test_bitcoin工程的字符集從UNICODE改為多字符集。
2、所有工程設定leveldb相關的標頭檔案路徑,包含3個,分別是:
- \leveldb
- \leveldb\include
- \leveldb\helpers\memenv
3、工程新增前處理器定義:
預處理定義分所有工程都需要定義、單個工程需要定義的,在下面會指明。
先說所有工程都需要知名的前處理器定義:
- _WIN32_WINDOWS:程式碼中需要定義_WIN32_WINNT或者_WIN32_WINDOWS,我定義了_WIN32_WINDOWS。
- HAVE_WORKING_BOOST_SLEEP:在src目錄下的util.h檔案的MilliSleep函式中根據巨集定義呼叫不同的BOOST的函式,我不知道該呼叫BOOST的哪個函式,就隨意選擇了HAVE_WORKING_BOOST_SLEEP,這個定義決定了呼叫boost::this_thread::sleep函式。
- LEVELDB_PLATFORM_WINDOWS:leveldb編譯支援windows平臺。
- OS_WIN:leveldb需要,包含windows相關的標頭檔案。
- ENABLE_WALLET:表示是否啟用錢包,因為程式碼不完善,禁用錢包不要取消ENABLE_WALLET的定義,新增引數”-disablewallet”來完成。如果取消ENABLE_WALLET的定義,編譯失敗。
- _CRT_SECURE_NO_WARNINGS:大家都懂了,去掉警告而已,可以不加的。
- _SCL_SECURE_NO_WARNINGS:發現還要加上這個。
- Bitcoin-qt、bitcoin-qt-test工程多加定義:WIN32_LEAN_AND_MEAN,不加時編譯報很多winsock的錯誤。
4、所有工程新增連結lib庫:Shlwapi.lib。
第五節 修改程式碼
編譯、執行過程中發生錯誤,逐條修改,數量很多,但改動很小。
1、工程Bitcoin-cli、Bitcoind
(1)檔案main.cpp編譯release版時,報錯”Bitcoin cannot be compiled without assertions.”。把這句程式碼註釋掉,增加#include <assert.h>,把assert巨集定義為空語句。
(2)在檔案net.h中新增#define __func__ __FUNCTION__,__func__是GCC的,__FUNCTION__是VC的。
(3)檔案addrman.h中的類CAddrMan中的IMPLEMENT_SERIALIZE因為括號不對,編譯報錯,不用IMPLEMENT_SERIALIZE巨集,把巨集IMPLEMENT_SERIALIZE定義的3個函式函式GetSerializeSize、Serialize、Unserialize中的‘{statements} ’替換為IMPLEMENT_SERIALIZE中的引數。就是說把serialize.h中的IMPLEMENT_SERIALIZE對應的函式程式碼替換到addrman.h中CAddrMan的IMPLEMENT_SERIALIZE出現的地方。
因為變數nVersion在函式引數中有定義,且區域性變數中也有定義,重複定義,註釋掉區域性變數中的nVersion。
(4)把檔案core.h中類CTxOutCompressor的IMPLEMENT_SERIALIZE巨集展開,用實際程式碼替換,不用IMPLEMENT_SERIALIZE巨集,用巨集的引數替換巨集定義中的{statements}欄位。同上
(5)把檔案serialize.h中ReadCompactSize函式中的0x100000000LLu改為(unsigned __int64)0×100000000。VC不支援LLu型別的資料。
(6)檔案serialize.h中,類CDataStream的建構函式中: CDataStream(const std::vector& vchIn, int nTypeIn, int nVersionIn) : vch((char*)&vchIn.begin()[0], (char*)&vchIn.end()[0]),執行時報錯,註釋掉”[0]“。VC不允許陣列大小為0。
(7)檔案script.h中的CScriptCompressor中的Serialize函式、Unserialize函式中的陣列越界了,且需要處理大小為0的陣列,共4處。在bitcoin-0.9.4中未發現,可能已修正
Serialize函式中:
if(compr.size() > 0)
s << CFlatData(&compr[0], &compr[compr.size()-1]);
if(script.size() > 0)
s << CFlatData(&script[0], &script[script.size()-1]);
Unserialize函式:
if(vch.size() > 0)
s >> REF(CFlatData(&vch[0], &vch[vch.size()-1]));
if(script.size() > 0)
s >> REF(CFlatData(&script[0], &script[script.size()-1]));
(8)檔案script.h中類CScript中:
#ifndef _MSC_VER
CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { }
#endif
註釋掉_MSC_VER的巨集定義。
因為檔案\qt\walletmodel.cpp中的WalletModel::prepareTransaction函式中的程式碼:
const unsigned char* scriptStr = (const unsigned char*)out.script().data();
CScript scriptPubKey(scriptStr, scriptStr+out.script().size());
編譯錯誤,scriptStr的型別轉換失敗。
(9)在檔案key.cpp中,新增函式:
int CompareBigEndianEx(const unsigned char *c1, size_t c1len) {
while (c1len > 0) {
if (*c1)
return 1;
c1++;
c1len--;
}
return 0;
}
註釋掉const unsigned char vchZero[0] = {};
函式CKey::Check、CKey::CheckSignatureElement中的CompareBigEndian(vch, len, vchZero, 0)改為CompareBigEndianEx(vch, 32)。
GCC允許陣列大小為0,但VC不允許。
在bitcoin-0.9.4中未發現,可能已修正
(10)檔案addrman.cpp中的CAddrMan::Select_函式中的程式碼:
double nCorTried = sqrt(nTried) * (100.0 - nUnkBias);
double nCorNew = sqrt(nNew) * nUnkBias;
改為:
double nCorTried = sqrt((double)nTried) * (100.0 - nUnkBias);
double nCorNew = sqrt((double)nNew) * nUnkBias;
在sqrt函式的引數加入(double)強制型別轉換,VC支援3個sqrt函式,引數型別不同,這裡增加強制型別轉換。
(11)檔案init.cpp中的AppInit2函式中的Setvbuf的最後一個引數0改為INT_MAX。
setvbuf(stdout, NULL, _IOLBF, INT_MAX /*0*/);
VC不允許最後一個引數為0。
(12)把檔案db.h中類CDB的部分程式碼註釋掉,分別是:
- Read函式中的free(datValue.get_data());
- ReadAtCursor函式中的free(datKey.getdata());free(datValue.getdata());
Free地址時報錯,我跟蹤過,在資料庫的pdb->get函式中確實呼叫了malloc函式申請記憶體,按理說free此地址沒問題,但報錯,這個問題暫時解決不了,後續解決。
我暫時沒有進行此步操作,待觀察
(13)檔案db.cpp中,類CDBEnv的CloseDb函式,delete pdb;時報錯,解決不了,暫時註釋掉,可能會產生資料庫操作錯誤。
同步區塊半小時後不在同步,這個問題可以跟與資料庫的這2個修改相關,尚未確定。
我暫時沒有進行此步操作,待觀察
(14)BTC原始碼中有2個bloom檔案,分別是bloom.cpp、\leveldb\util\bloom.cc,編譯時生成的bloom.obj衝突,把其中1個檔案改名即可,把bloom.cc改名為bloomdb.cc。
(15)BTC原始碼中有2個hash檔案,分別是hash.cpp、\leveldb\util\hash.cc,編譯時生成的hash.obj衝突,把其中1個檔案改名即可,把hash.cc改名為hashdb.cc。
(16)把檔案\leveldb\util\env_win.cc中的CreateDirInner函式中的GetFileAttributes改為GetFileAttributesA,CreateDirectory改為CreateDirectoryA,強制使用ASCI函式。
(17)註釋掉\leveldb\db\dbbench.cc、\leveldb\db\leveldbmain.cc中的main函式,衝突了。
(18)在檔案netbase.cpp、\leveldb\db\dbiter.cc中新增語句:”typedef signed int ssize_t;”,VC中沒有定義ssize_t資料型別。
(19)註釋掉檔案\leveldb\db\c.cc中的#include <unistd.h>,這是linux的標頭檔案。新增#pragma warning(disable:4996),解決編譯時候報錯4996錯誤。
(20)函式min()、max()在windef.h、stl中有不同的定義,需要把std::numericlimits::max()改為(std::numericlimits::max)(),否則編譯時max()引數報錯。
需要改的地方包括:
- 檔案serialize.h中的GetSizeOfCompactSize函式
- script.h檔案中的類CScriptNum中的減號過載、加等於、減等於、getint()函式,WriteCompactSize函式
- 檔案core.h中的類CTxIn的3個建構函式,、IsFinal()函式
- \Qt\Qt5.2.0\5.2.0\msvc2010\include\QtCore\qdatetime.h中的類QDate中的nullJd函式
檔案wallet.h中類CWallet的LoadMinVersion函式中的引數std::max加上小括號。
檔案net.h中的類CNode的AskFor函式中的std::max加上小括號。
2、工程bitcoin-qt、bitcoin-qt-test
(1)在CMD中,執行\protobuf-2.5.0\vsprojects\Release目錄下的protoc.exe,生成paymentrequest.proto檔案對應的標頭檔案、原始檔,命令格式為:
protoc --proto_path=e:/bitcoin/qt --cpp_out=e:/bitcoin/qt e:/bitcoin/qt/paymentrequest.proto
把生成的.h、.cc檔案新增到bitcoin-qt、bitcoin-qt-test工程中。
(2)對\qt\locale下的所有檔案執行lrelease操作,在資源管理器中,在locale下的檔案上點選右鍵,執行lrelease操作,生成文字的多國語言版本。
(3)在檔案\qt\winshutdownmonitor.h中語句“#include <windef.h> // for HWND”前面新增
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>。因為編譯時報錯:1>c:\program files (x86)\microsoft sdks\windows\v7.0a\include\winnt.h(6361): error C2146: syntax error : missing ‘;’ before identifier ‘ContextRecord’,多個錯誤。
(4)修改bitcoin-qt、bitcoin-qt-test工程中的某些cpp檔案的編譯方式,把Custom Build Tool改為C/C++ compiler。需要修改的檔案為:rpcconsole.cpp、intro.cpp、overviewpage.cpp、bitcoin.cpp。vs2013操作:選中檔案右鍵屬性->常規->項管理->c/c++編譯器。
(5)註釋掉檔案\qt\test\test_main.cpp的第一行程式碼:#include “bitcoin-config.h”。我已經提交github修改此BUG,已通過,5月22日之後的程式碼沒有這個問題,github上的修改BUG地址:https://github.com/bitcoin/bitcoin/pull/4212。有興趣可以檢視。
(6) 因為連結時報qInitResources_bitcoin無法識別的錯誤,所以遮蔽了bitcoin.cpp 中main函式下Q_INIT_RESOURCE(bitcoin);這句,錯誤原因還不清楚,後續再看
3、工程test_bitcoin
- 移除test_bitcoin工程中COMMON的原始檔目錄下的init.cpp,因為變數pwalletMain等重定義了,衝突。
- 在檔案\test\utiltests.cpp中新增程式碼:typedef signed int ssizet;
- 在MAC系統下編譯bitcoin,把\src\test\data目錄下的所有h檔案複製到相同目錄中。(因為分析makefile,把json檔案轉換成h檔案的方法是通過建立h檔案,輸出字串,字元轉換等完成的,需要新寫程式來做,所以暫時使用MAC編譯後的h檔案。)
在src目錄中的Makefile.include檔案完成此操作,轉換程式碼如下:
%.json.h: %.json
@$(MKDIR_P) $(@D)
@echo "namespace json_tests{" > [email protected]
@echo "static unsigned const char $(*F)[] = {" >> [email protected]
@$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> [email protected]
@echo "};};" >> [email protected]
@echo "Generated [email protected]"
%.raw.h: %.raw
@$(MKDIR_P) $(@D)
@echo "namespace alert_tests{" > [email protected]
@echo "static unsigned const char $(*F)[] = {" >> [email protected]
@$(HEXDUMP) -v -e '8/1 "0x%02x, "' -e '"\n"' $< | $(SED) -e 's/0x ,//g' >> [email protected]
@echo "};};" >> [email protected]
@echo "Generated [email protected]"