From b1024662eafddd5560fbfbac29333e5e967ca0f8 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Fri, 21 Dec 2012 14:41:48 -0500 Subject: [PATCH] Port leveldb to MinGW32 Several changes to make the native windows leveldb code compile with mingw32 and run on 32-bit Windows: * Remove -std=c++0x dependency (modified code to use NULL instead of nullptr) * Link with -lshlwapi * Only #define snprintf/etc if compiling with Visual Studio * Do not link against DbgHelp.lib (wrote a CreateDir instead of using DbgHelp's MakeSureDirectoryPathExists * Define WINVER=0x0500 so MinGW32 can use the 64-bit-filesystem Windows api calls * Define __USE_MINGW_ANSI_STDIO=1 to use MinGW's printf (which supports %ll) I also cleaned up makefile.mingw, assuming that dependencies would be in the standard /usr/local/{include,lib} by default but allowing overriding with make DEPSDIR=... etc --- bitcoin-qt.pro | 5 +-- src/leveldb/build_detect_platform | 6 ++-- src/leveldb/port/port_win.cc | 6 ++-- src/leveldb/port/port_win.h | 4 ++- src/leveldb/util/env_win.cc | 28 +++++++++++---- src/makefile.linux-mingw | 5 +-- src/makefile.mingw | 57 +++++++++++++++++++------------ 7 files changed, 71 insertions(+), 40 deletions(-) diff --git a/bitcoin-qt.pro b/bitcoin-qt.pro index 5274de4265..6c1c4a78cc 100644 --- a/bitcoin-qt.pro +++ b/bitcoin-qt.pro @@ -105,13 +105,14 @@ LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a isEmpty(QMAKE_RANLIB) { QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, ranlib) } - genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$$BOOST_INCLUDE_PATH" LDFLAGS="-L$$BOOST_LIB_PATH" $(MAKE) libleveldb.a libmemenv.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a + LIBS += -lshlwapi + genleveldb.commands = cd $$PWD/src/leveldb && CC=$$QMAKE_CC CXX=$$QMAKE_CXX TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) libleveldb.a libmemenv.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libleveldb.a && $$QMAKE_RANLIB $$PWD/src/leveldb/libmemenv.a } genleveldb.target = $$PWD/src/leveldb/libleveldb.a genleveldb.depends = FORCE PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a QMAKE_EXTRA_TARGETS += genleveldb -# Gross ugly hack that depends on qmake internals, unfortunately there's no other way to do it. +# Gross ugly hack that depends on qmake internals, unfortunately there is no other way to do it. QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean # regenerate src/build.h diff --git a/src/leveldb/build_detect_platform b/src/leveldb/build_detect_platform index caf2352f93..1080df77f4 100755 --- a/src/leveldb/build_detect_platform +++ b/src/leveldb/build_detect_platform @@ -129,11 +129,9 @@ case "$TARGET_OS" in ;; OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) PLATFORM=OS_WINDOWS - COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS" - PLATFORM_SHARED_CFLAGS="" + COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1" PLATFORM_SOURCES="util/env_win.cc" - PLATFORM_CXXFLAGS="-std=c++0x" - PLATFORM_LIBS="-lshlwapi -ldbghelp" + PLATFORM_LIBS="-lshlwapi" PORT_FILE=port/port_win.cc CROSS_COMPILE=true ;; diff --git a/src/leveldb/port/port_win.cc b/src/leveldb/port/port_win.cc index 15dfde1f27..99c1d8e346 100644 --- a/src/leveldb/port/port_win.cc +++ b/src/leveldb/port/port_win.cc @@ -37,7 +37,7 @@ namespace leveldb { namespace port { Mutex::Mutex() : - cs_(nullptr) { + cs_(NULL) { assert(!cs_); cs_ = static_cast(new CRITICAL_SECTION()); ::InitializeCriticalSection(static_cast(cs_)); @@ -48,7 +48,7 @@ Mutex::~Mutex() { assert(cs_); ::DeleteCriticalSection(static_cast(cs_)); delete static_cast(cs_); - cs_ = nullptr; + cs_ = NULL; assert(!cs_); } @@ -128,7 +128,7 @@ void InitOnce(OnceType* once, void (*initializer)()) { } void* AtomicPointer::Acquire_Load() const { - void * p = nullptr; + void * p = NULL; InterlockedExchangePointer(&p, rep_); return p; } diff --git a/src/leveldb/port/port_win.h b/src/leveldb/port/port_win.h index 849b01705f..45bf2f0ea7 100644 --- a/src/leveldb/port/port_win.h +++ b/src/leveldb/port/port_win.h @@ -31,9 +31,11 @@ #ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ #define STORAGE_LEVELDB_PORT_PORT_WIN_H_ +#ifdef _MSC_VER #define snprintf _snprintf #define close _close #define fread_unlocked _fread_nolock +#endif #include #include @@ -120,7 +122,7 @@ class AtomicPointer { private: void * rep_; public: - AtomicPointer() : rep_(nullptr) { } + AtomicPointer() : rep_(NULL) { } explicit AtomicPointer(void* v); void* Acquire_Load() const; diff --git a/src/leveldb/util/env_win.cc b/src/leveldb/util/env_win.cc index 384331aec5..f1a7610624 100644 --- a/src/leveldb/util/env_win.cc +++ b/src/leveldb/util/env_win.cc @@ -20,9 +20,7 @@ #include #include #include -#include #include -#pragma comment(lib,"DbgHelp.lib") #ifdef max #undef max @@ -908,18 +906,34 @@ uint64_t Win32Env::NowMicros() return (uint64_t)(GetTickCount64()*1000); } -Status Win32Env::CreateDir( const std::string& dirname ) +static Status CreateDirInner( const std::string& dirname ) { Status sRet; + DWORD attr = ::GetFileAttributes(dirname.c_str()); + if (attr == INVALID_FILE_ATTRIBUTES) { // doesn't exist: + std::size_t slash = dirname.find_last_of("\\"); + if (slash != std::string::npos){ + sRet = CreateDirInner(dirname.substr(0, slash)); + if (!sRet.ok()) return sRet; + } + BOOL result = ::CreateDirectory(dirname.c_str(), NULL); + if (result == FALSE) { + sRet = Status::IOError(dirname, "Could not create directory."); + return sRet; + } + } + return sRet; +} + +Status Win32Env::CreateDir( const std::string& dirname ) +{ std::string path = dirname; if(path[path.length() - 1] != '\\'){ path += '\\'; } ModifyPath(path); - if(!::MakeSureDirectoryPathExists( path.c_str() ) ){ - sRet = Status::IOError(dirname, "Could not create directory."); - } - return sRet; + + return CreateDirInner(path); } Status Win32Env::DeleteDir( const std::string& dirname ) diff --git a/src/makefile.linux-mingw b/src/makefile.linux-mingw index efbce1f047..c3cbe90bcd 100644 --- a/src/makefile.linux-mingw +++ b/src/makefile.linux-mingw @@ -21,6 +21,7 @@ LIBPATHS= \ -L"$(DEPSDIR)/openssl-1.0.1c" LIBS= \ + $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a \ -l boost_system-mt-s \ -l boost_filesystem-mt-s \ -l boost_program_options-mt-s \ @@ -91,11 +92,10 @@ OBJS= \ all: bitcoind.exe -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a DEFS += -I"$(CURDIR)/leveldb/include" DEFS += -I"$(CURDIR)/leveldb/helpers" leveldb/libleveldb.a: - @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="-I$(INCLUDEPATHS)" LDFLAGS="-L$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd .. + @echo "Building LevelDB ..." && cd leveldb && CC=i586-mingw32msvc-gcc CXX=i586-mingw32msvc-g++ TARGET_OS=OS_WINDOWS_CROSSCOMPILE CXXFLAGS="$(INCLUDEPATHS)" LDFLAGS="$(LIBPATHS)" $(MAKE) libleveldb.a libmemenv.a && i586-mingw32msvc-ranlib libleveldb.a && i586-mingw32msvc-ranlib libmemenv.a && cd .. obj/leveldb.o: leveldb/libleveldb.a obj/build.h: FORCE @@ -124,5 +124,6 @@ clean: -rm -f obj-test/*.o -rm -f test_bitcoin.exe -rm -f obj/build.h + cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) clean && cd .. FORCE: diff --git a/src/makefile.mingw b/src/makefile.mingw index a7a57a2a24..366d32bd86 100644 --- a/src/makefile.mingw +++ b/src/makefile.mingw @@ -2,25 +2,41 @@ # Distributed under the MIT/X11 software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. -USE_UPNP:=0 +# Makefile for the MinGW g++ compiler/toolchain +# +# Assumes Berkeley DB, Boost, and OpenSSL have all been compiled and installed +# into /usr/local (/usr/local/include, /usr/local/lib). +# +# If dependencies are somewhere else, run 'make DEPSDIR=/path/' +# +# Boost libraries are given wacky names that include the particular version of +# boost you're using; set BOOST_SUFFIX appropriately. +# +# 'make clean' assumes it is running inside a MSYS shell, and uses 'rm' +# to remove files. + +USE_UPNP:=- USE_IPV6:=1 +DEPSDIR?=/usr/local +BOOST_SUFFIX?=-mgw46-mt-sd-1_52 + INCLUDEPATHS= \ - -I"C:\boost-1.50.0-mgw" \ - -I"C:\db-4.8.30.NC-mgw\build_unix" \ - -I"C:\openssl-1.0.1c-mgw\include" + -I"$(CURDIR)" \ + -I"$(DEPSDIR)/include" LIBPATHS= \ - -L"C:\boost-1.50.0-mgw\stage\lib" \ - -L"C:\db-4.8.30.NC-mgw\build_unix" \ - -L"C:\openssl-1.0.1c-mgw" + -L"$(CURDIR)/leveldb" \ + -L"$(DEPSDIR)/lib" LIBS= \ - -l boost_system-mgw45-mt-s-1_50 \ - -l boost_filesystem-mgw45-mt-s-1_50 \ - -l boost_program_options-mgw45-mt-s-1_50 \ - -l boost_thread-mgw45-mt-s-1_50 \ - -l boost_chrono-mgw45-mt-s-1_50 \ + -l leveldb \ + -l memenv \ + -l boost_system$(BOOST_SUFFIX) \ + -l boost_filesystem$(BOOST_SUFFIX) \ + -l boost_program_options$(BOOST_SUFFIX) \ + -l boost_thread$(BOOST_SUFFIX) \ + -l boost_chrono$(BOOST_SUFFIX) \ -l db_cxx \ -l ssl \ -l crypto @@ -37,8 +53,6 @@ ifndef USE_UPNP override USE_UPNP = - endif ifneq (${USE_UPNP}, -) - INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw" - LIBPATHS += -L"C:\miniupnpc-1.6-mgw" LIBS += -l miniupnpc -l iphlpapi DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) endif @@ -94,12 +108,12 @@ test check: test_bitcoin.exe FORCE # # LevelDB support # -LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) -# TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a + leveldb/libleveldb.a: - cd leveldb && $(MAKE) libleveldb.a libmemenv.a && cd .. + cd leveldb && $(MAKE) OPT="$(DEBUGFLAGS)" TARGET_OS=NATIVE_WINDOWS libleveldb.a libmemenv.a && cd .. + obj/leveldb.o: leveldb/libleveldb.a obj/%.o: %.cpp $(HEADERS) @@ -114,11 +128,12 @@ obj-test/%.o: test/%.cpp $(HEADERS) g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) - g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework $(LIBS) + g++ $(CFLAGS) $(LDFLAGS) -o $@ $(LIBPATHS) $^ -lboost_unit_test_framework$(BOOST_SUFFIX) $(LIBS) clean: - -del /Q bitcoind test_bitcoin - -del /Q obj\* - -del /Q obj-test\* + rm -f bitcoind.exe test_bitcoin.exe + rm -f obj/* + rm -f obj-test/* + cd leveldb && $(MAKE) TARGET_OS=NATIVE_WINDOWS clean && cd .. FORCE: