1. 程式人生 > >vs2013編譯bitcoin原始碼(bitcoin-0.9.4)

vs2013編譯bitcoin原始碼(bitcoin-0.9.4)

proto下的.h、.cc檔案是用工具Protobuf生成的,後面介紹。

在bitcoin-qt-test工程中新增src\qt\test目錄下的檔案。新增bitcoin-qt的程式碼檔案。工程結構如下:

5

第四節 設定工程屬性

設定工程屬性,除了設定前面介紹的依賴庫的相關路徑、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的部分程式碼註釋掉,分別是:

  1. Read函式中的free(datValue.get_data());
  2. 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()引數報錯。
需要改的地方包括:

  1. 檔案serialize.h中的GetSizeOfCompactSize函式
  2. script.h檔案中的類CScriptNum中的減號過載、加等於、減等於、getint()函式,WriteCompactSize函式
  3. 檔案core.h中的類CTxIn的3個建構函式,、IsFinal()函式
  4. \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

  1. 移除test_bitcoin工程中COMMON的原始檔目錄下的init.cpp,因為變數pwalletMain等重定義了,衝突。
  2. 在檔案\test\utiltests.cpp中新增程式碼:typedef signed int ssizet;
  3. 在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]"