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
This commit is contained in:
Gavin Andresen 2012-12-21 14:41:48 -05:00
parent 8aef119f43
commit b1024662ea
7 changed files with 71 additions and 40 deletions

View File

@ -105,13 +105,14 @@ LIBS += $$PWD/src/leveldb/libleveldb.a $$PWD/src/leveldb/libmemenv.a
isEmpty(QMAKE_RANLIB) { isEmpty(QMAKE_RANLIB) {
QMAKE_RANLIB = $$replace(QMAKE_STRIP, strip, 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.target = $$PWD/src/leveldb/libleveldb.a
genleveldb.depends = FORCE genleveldb.depends = FORCE
PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a PRE_TARGETDEPS += $$PWD/src/leveldb/libleveldb.a
QMAKE_EXTRA_TARGETS += genleveldb 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 QMAKE_CLEAN += $$PWD/src/leveldb/libleveldb.a; cd $$PWD/src/leveldb ; $(MAKE) clean
# regenerate src/build.h # regenerate src/build.h

View File

@ -129,11 +129,9 @@ case "$TARGET_OS" in
;; ;;
OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS) OS_WINDOWS_CROSSCOMPILE | NATIVE_WINDOWS)
PLATFORM=OS_WINDOWS PLATFORM=OS_WINDOWS
COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS" COMMON_FLAGS="-fno-builtin-memcmp -D_REENTRANT -DOS_WINDOWS -DLEVELDB_PLATFORM_WINDOWS -DWINVER=0x0500 -D__USE_MINGW_ANSI_STDIO=1"
PLATFORM_SHARED_CFLAGS=""
PLATFORM_SOURCES="util/env_win.cc" PLATFORM_SOURCES="util/env_win.cc"
PLATFORM_CXXFLAGS="-std=c++0x" PLATFORM_LIBS="-lshlwapi"
PLATFORM_LIBS="-lshlwapi -ldbghelp"
PORT_FILE=port/port_win.cc PORT_FILE=port/port_win.cc
CROSS_COMPILE=true CROSS_COMPILE=true
;; ;;

View File

@ -37,7 +37,7 @@ namespace leveldb {
namespace port { namespace port {
Mutex::Mutex() : Mutex::Mutex() :
cs_(nullptr) { cs_(NULL) {
assert(!cs_); assert(!cs_);
cs_ = static_cast<void *>(new CRITICAL_SECTION()); cs_ = static_cast<void *>(new CRITICAL_SECTION());
::InitializeCriticalSection(static_cast<CRITICAL_SECTION *>(cs_)); ::InitializeCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
@ -48,7 +48,7 @@ Mutex::~Mutex() {
assert(cs_); assert(cs_);
::DeleteCriticalSection(static_cast<CRITICAL_SECTION *>(cs_)); ::DeleteCriticalSection(static_cast<CRITICAL_SECTION *>(cs_));
delete static_cast<CRITICAL_SECTION *>(cs_); delete static_cast<CRITICAL_SECTION *>(cs_);
cs_ = nullptr; cs_ = NULL;
assert(!cs_); assert(!cs_);
} }
@ -128,7 +128,7 @@ void InitOnce(OnceType* once, void (*initializer)()) {
} }
void* AtomicPointer::Acquire_Load() const { void* AtomicPointer::Acquire_Load() const {
void * p = nullptr; void * p = NULL;
InterlockedExchangePointer(&p, rep_); InterlockedExchangePointer(&p, rep_);
return p; return p;
} }

View File

@ -31,9 +31,11 @@
#ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_ #ifndef STORAGE_LEVELDB_PORT_PORT_WIN_H_
#define STORAGE_LEVELDB_PORT_PORT_WIN_H_ #define STORAGE_LEVELDB_PORT_PORT_WIN_H_
#ifdef _MSC_VER
#define snprintf _snprintf #define snprintf _snprintf
#define close _close #define close _close
#define fread_unlocked _fread_nolock #define fread_unlocked _fread_nolock
#endif
#include <string> #include <string>
#include <stdint.h> #include <stdint.h>
@ -120,7 +122,7 @@ class AtomicPointer {
private: private:
void * rep_; void * rep_;
public: public:
AtomicPointer() : rep_(nullptr) { } AtomicPointer() : rep_(NULL) { }
explicit AtomicPointer(void* v); explicit AtomicPointer(void* v);
void* Acquire_Load() const; void* Acquire_Load() const;

View File

@ -20,9 +20,7 @@
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
#include <io.h> #include <io.h>
#include <dbghelp.h>
#include <algorithm> #include <algorithm>
#pragma comment(lib,"DbgHelp.lib")
#ifdef max #ifdef max
#undef max #undef max
@ -908,18 +906,34 @@ uint64_t Win32Env::NowMicros()
return (uint64_t)(GetTickCount64()*1000); return (uint64_t)(GetTickCount64()*1000);
} }
Status Win32Env::CreateDir( const std::string& dirname ) static Status CreateDirInner( const std::string& dirname )
{ {
Status sRet; 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; std::string path = dirname;
if(path[path.length() - 1] != '\\'){ if(path[path.length() - 1] != '\\'){
path += '\\'; path += '\\';
} }
ModifyPath(path); ModifyPath(path);
if(!::MakeSureDirectoryPathExists( path.c_str() ) ){
sRet = Status::IOError(dirname, "Could not create directory."); return CreateDirInner(path);
}
return sRet;
} }
Status Win32Env::DeleteDir( const std::string& dirname ) Status Win32Env::DeleteDir( const std::string& dirname )

View File

@ -21,6 +21,7 @@ LIBPATHS= \
-L"$(DEPSDIR)/openssl-1.0.1c" -L"$(DEPSDIR)/openssl-1.0.1c"
LIBS= \ LIBS= \
$(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a \
-l boost_system-mt-s \ -l boost_system-mt-s \
-l boost_filesystem-mt-s \ -l boost_filesystem-mt-s \
-l boost_program_options-mt-s \ -l boost_program_options-mt-s \
@ -91,11 +92,10 @@ OBJS= \
all: bitcoind.exe all: bitcoind.exe
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += -I"$(CURDIR)/leveldb/include" DEFS += -I"$(CURDIR)/leveldb/include"
DEFS += -I"$(CURDIR)/leveldb/helpers" DEFS += -I"$(CURDIR)/leveldb/helpers"
leveldb/libleveldb.a: 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/leveldb.o: leveldb/libleveldb.a
obj/build.h: FORCE obj/build.h: FORCE
@ -124,5 +124,6 @@ clean:
-rm -f obj-test/*.o -rm -f obj-test/*.o
-rm -f test_bitcoin.exe -rm -f test_bitcoin.exe
-rm -f obj/build.h -rm -f obj/build.h
cd leveldb && TARGET_OS=OS_WINDOWS_CROSSCOMPILE $(MAKE) clean && cd ..
FORCE: FORCE:

View File

@ -2,25 +2,41 @@
# Distributed under the MIT/X11 software license, see the accompanying # Distributed under the MIT/X11 software license, see the accompanying
# file COPYING or http://www.opensource.org/licenses/mit-license.php. # 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 USE_IPV6:=1
DEPSDIR?=/usr/local
BOOST_SUFFIX?=-mgw46-mt-sd-1_52
INCLUDEPATHS= \ INCLUDEPATHS= \
-I"C:\boost-1.50.0-mgw" \ -I"$(CURDIR)" \
-I"C:\db-4.8.30.NC-mgw\build_unix" \ -I"$(DEPSDIR)/include"
-I"C:\openssl-1.0.1c-mgw\include"
LIBPATHS= \ LIBPATHS= \
-L"C:\boost-1.50.0-mgw\stage\lib" \ -L"$(CURDIR)/leveldb" \
-L"C:\db-4.8.30.NC-mgw\build_unix" \ -L"$(DEPSDIR)/lib"
-L"C:\openssl-1.0.1c-mgw"
LIBS= \ LIBS= \
-l boost_system-mgw45-mt-s-1_50 \ -l leveldb \
-l boost_filesystem-mgw45-mt-s-1_50 \ -l memenv \
-l boost_program_options-mgw45-mt-s-1_50 \ -l boost_system$(BOOST_SUFFIX) \
-l boost_thread-mgw45-mt-s-1_50 \ -l boost_filesystem$(BOOST_SUFFIX) \
-l boost_chrono-mgw45-mt-s-1_50 \ -l boost_program_options$(BOOST_SUFFIX) \
-l boost_thread$(BOOST_SUFFIX) \
-l boost_chrono$(BOOST_SUFFIX) \
-l db_cxx \ -l db_cxx \
-l ssl \ -l ssl \
-l crypto -l crypto
@ -37,8 +53,6 @@ ifndef USE_UPNP
override USE_UPNP = - override USE_UPNP = -
endif endif
ifneq (${USE_UPNP}, -) ifneq (${USE_UPNP}, -)
INCLUDEPATHS += -I"C:\miniupnpc-1.6-mgw"
LIBPATHS += -L"C:\miniupnpc-1.6-mgw"
LIBS += -l miniupnpc -l iphlpapi LIBS += -l miniupnpc -l iphlpapi
DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP) DEFS += -DSTATICLIB -DUSE_UPNP=$(USE_UPNP)
endif endif
@ -94,12 +108,12 @@ test check: test_bitcoin.exe FORCE
# #
# LevelDB support # LevelDB support
# #
LIBS += $(CURDIR)/leveldb/libleveldb.a $(CURDIR)/leveldb/libmemenv.a
DEFS += $(addprefix -I,$(CURDIR)/leveldb/include) DEFS += $(addprefix -I,$(CURDIR)/leveldb/include)
DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers) DEFS += $(addprefix -I,$(CURDIR)/leveldb/helpers)
# TODO: If this fails, try adding a ranlib libleveldb.a && ranlib libmemenv.a
leveldb/libleveldb.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/leveldb.o: leveldb/libleveldb.a
obj/%.o: %.cpp $(HEADERS) obj/%.o: %.cpp $(HEADERS)
@ -114,11 +128,12 @@ obj-test/%.o: test/%.cpp $(HEADERS)
g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $< g++ -c $(TESTDEFS) $(CFLAGS) -o $@ $<
test_bitcoin.exe: $(TESTOBJS) $(filter-out obj/init.o,$(OBJS:obj/%=obj/%)) 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: clean:
-del /Q bitcoind test_bitcoin rm -f bitcoind.exe test_bitcoin.exe
-del /Q obj\* rm -f obj/*
-del /Q obj-test\* rm -f obj-test/*
cd leveldb && $(MAKE) TARGET_OS=NATIVE_WINDOWS clean && cd ..
FORCE: FORCE: