cmake:vs2015/MinGW静态编译leveldb

leveldb是google的开源项目(https://github.com/google/leveldb), 在linux下编译很方便,然而官方版本却没有提供在windows下的编译方式,好麻烦。还好,开源的世界热心人很多,同样在github上找到了cmake编译版本(https://github.com/bureau14/leveldb),有了cmake版本,windows下编译的问题就解决了一大半,下载这个版本的源码在windows用vs2015编译通过。但执行nmake install后发现,cmake脚本提供的安装功能不完整,只安装了bin文件夹。于是手工修改了CMakeLists.txt,才能完整安装。

修改CMakeLists.txt

修改后的CMakeLists.txt如下(搜索guyadong标记,可以找到所有添加的代码)

cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)

project(leveldb CXX)    
set(CMAKE_DEBUG_POSTFIX "d")

set(Boost_USE_STATIC_LIBS ON)
set(Boost_USE_MULTITHREAD ON)
set(Boost_USE_STATIC_RUNTIME OFF)

find_package(Boost COMPONENTS 
    date_time
    filesystem
    system
    REQUIRED)

set(SNAPPY_LIBRARY "")

string(REGEX MATCH "clang" CLANG ${CMAKE_CXX_COMPILER})

if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
    find_library(Pthread_LIBRARY pthread)
    find_library(Realtime_LIBRARY rt)
    # find library can be problematic with stdc++ which is why we hardwire the link
    set(Stdcpp_LIBRARY stdc++)
else(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
    set(Pthread_LIBRARY "")
    set(Realtime_LIBRARY "")
    set(Stdcpp_LIBRARY "")
endif(CMAKE_COMPILER_IS_GNUCXX OR CLANG)

include_directories(${Boost_INCLUDE_DIRS}
    ${CMAKE_CURRENT_SOURCE_DIR}
    include)

if(MSVC)
    add_compile_options(
        /D_CRT_SECURE_NO_WARNINGS
        /wd4389 # signed/unsigned mismatch
        /wd4800 # constructor never returns, potential memory leak because of a singleton pattern
        /wd4722 # unreachable code because of singleton pattern
        /wd4702 # bool cast performance warning
    )
else()
    add_compile_options(
        -Wno-sign-compare
        -std=c++11
    )
endif()

add_definitions(
    -DLEVELDB_ATOMIC_PRESENT
)

set(LEVEL_DB_FILES
    include/leveldb/c.h
    include/leveldb/cache.h
    include/leveldb/comparator.h
    include/leveldb/db.h
    include/leveldb/dumpfile.h
    include/leveldb/env.h
    include/leveldb/iterator.h
    include/leveldb/filter_policy.h
    include/leveldb/iterator.h
    include/leveldb/options.h
    include/leveldb/slice.h
    include/leveldb/status.h
    include/leveldb/table.h
    include/leveldb/table_builder.h
    include/leveldb/write_batch.h
    db/builder.cc
    db/builder.h
    db/db_impl.cc
    db/db_impl.h
    db/db_iter.cc
    db/db_iter.h
    db/dbformat.cc
    db/dbformat.h
    db/dumpfile.cc
    db/filename.cc
    db/filename.h
    db/log_format.h
    db/log_reader.cc
    db/log_reader.h
    db/log_writer.cc
    db/log_writer.h
    db/skiplist.h
    db/snapshot.h
    db/memtable.cc
    db/memtable.h
    db/repair.cc
    db/table_cache.cc
    db/table_cache.h
    db/version_edit.cc
    db/version_edit.h
    db/version_set.cc
    db/version_set.h
    db/write_batch.cc
    table/block.cc
    table/block.h
    table/block_builder.cc
    table/block_builder.h
    table/filter_block.cc
    table/filter_block.h
    table/format.cc
    table/format.h
    table/iterator.cc
    table/iterator_wrapper.h
    table/merger.cc
    table/merger.h
    table/table.cc
    table/table_builder.cc
    table/two_level_iterator.cc
    table/two_level_iterator.h
    util/arena.cc
    util/arena.h
    util/bloom.cc
    util/cache.cc
    util/coding.cc
    util/coding.h
    util/comparator.cc
    util/crc32c.cc
    util/crc32c.h
    util/env.cc
    util/filter_policy.cc
    util/hash.cc
    util/hash.h
    util/histogram.cc
    util/histogram.h
    util/logging.cc
    util/logging.h
    util/mutexlock.h
    util/options.cc
    util/random.h
    util/status.cc
    port/port.h)

if(WIN32)
    list(APPEND LEVEL_DB_FILES
        port/port_win.h
        port/port_win.cc
        util/win_logger.h
        util/win_logger.cc
        util/env_boost.cc)
else()
    list(APPEND LEVEL_DB_FILES
        port/port_posix.h
        port/port_posix.cc
        util/posix_logger.h
        util/env_posix.cc)
endif()

add_library(leveldb ${LEVEL_DB_FILES})

target_include_directories(leveldb 
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
    PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} 
)

target_link_libraries(leveldb 
    PRIVATE
    ${Boost_LIBRARIES}
    ${Pthread_LIBRARY}
)

add_executable(leveldbutil
    db/leveldb_main.cc)

target_link_libraries(leveldbutil
    leveldb)

set_target_properties(leveldbutil PROPERTIES
    DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

# we distribute the leveldbutil as it might be useful
install(TARGETS leveldbutil
    RUNTIME DESTINATION bin
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
# modified by guyadong
# 将 leveldb 库安装到 lib下
install(TARGETS leveldb
    LIBRARY DESTINATION lib
    ARCHIVE DESTINATION lib)
# 复制 include 文件夹
install(DIRECTORY include DESTINATION .)
# end of modified by guyadong
##################################### TESTS #######################################
# Every leveldb test file has to be compiled as an independant binary
# because of the test framework used by leveldb.
add_library(leveldb_test_rt 
    util/testutil.h
    util/testutil.cc
    util/testharness.h
    util/testharness.cc)

target_include_directories(leveldb_test_rt
    PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include
)

add_custom_target(RUN_LEVELDB_UNIT_TESTS
    COMMAND ${CMAKE_CTEST_COMMAND}
        --build-config ${CMAKE_CFG_INTDIR}
        --output-log LevelDB_test_${CMAKE_CFG_INTDIR}.log
        --output-on-failure
        --tests-regex leveldb
    COMMENT "Running all LevelDB unit tests"
)

function(LEVELDB_ADD_TEST TESTNAME TESTFILE)
    if(NOT TESTNAME)
        message(SEND_ERROR "Error: LEVELDB_ADD_TEST called without test name")
        return()
    endif(NOT TESTNAME)

    if(NOT TESTFILE)
        message(SEND_ERROR "Error: LEVELDB_ADD_TEST called without test file")
        return()
    endif(NOT TESTFILE)

    add_executable(leveldb_${TESTNAME}_test
        ${TESTFILE})

    target_link_libraries(leveldb_${TESTNAME}_test
        leveldb_test_rt
        leveldb)

    set_target_properties(leveldb_${TESTNAME}_test PROPERTIES
        DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})

    add_test(NAME leveldb_${TESTNAME}_test COMMAND leveldb_${TESTNAME}_test)

    add_dependencies(RUN_LEVELDB_UNIT_TESTS leveldb_${TESTNAME}_test)
    # modified by guyadong
    # 将所有测试程序安装到 bin 下
    install(TARGETS leveldb_${TESTNAME}_test  RUNTIME DESTINATION bin)
    # end of modified by guyadong
endfunction(LEVELDB_ADD_TEST)

LEVELDB_ADD_TEST(env          util/env_test.cc)
LEVELDB_ADD_TEST(crc32        util/crc32c_test.cc)
LEVELDB_ADD_TEST(coding       util/coding_test.cc)
LEVELDB_ADD_TEST(arena        util/arena_test.cc)
LEVELDB_ADD_TEST(cache        util/cache_test.cc)
LEVELDB_ADD_TEST(table        table/table_test.cc)
# IMPORTANT: Commented a test that fails randomly.
# LEVELDB_ADD_TEST(autocompact  db/autocompact_test.cc)
LEVELDB_ADD_TEST(corruption   db/corruption_test.cc)
LEVELDB_ADD_TEST(dbformat     db/dbformat_test.cc)
LEVELDB_ADD_TEST(filename     db/filename_test.cc)
LEVELDB_ADD_TEST(log          db/log_test.cc)
LEVELDB_ADD_TEST(skiplist     db/skiplist_test.cc)
LEVELDB_ADD_TEST(version_edit db/version_edit_test.cc)
LEVELDB_ADD_TEST(write_batch  db/write_batch_test.cc)
LEVELDB_ADD_TEST(version_set  db/version_set_test.cc)
LEVELDB_ADD_TEST(filter_block table/filter_block_test.cc)
LEVELDB_ADD_TEST(bloom        util/bloom_test.cc)
LEVELDB_ADD_TEST(hash         util/hash_test.cc)
LEVELDB_ADD_TEST(db_bench     db/db_bench.cc)
LEVELDB_ADD_TEST(db           db/db_test.cc)

可以从这里下载修改后的CMakeLists.txt https://code.csdn.net/10km/caffe-static/tree/master/patch/leveldb-master/CMakeLists.txt

cmake编译leveldb

修改好CMakeLists.txt后,开始cmake 编译leveldb。下面是脚本编译过程

rem 创建 vs2015 x64编译环境
rem 如果要编译32位版本,则将后面的x86_amd64改为x86
call "%VS140COMNTOOLS%\..\..\VC\vcvarsall.bat" x86_amd64
mkdir build.gcc
cd build.gcc
rem %install_path% 安装路径
rem %boost_root% boost 安装路径
rem 注意这个版本的leveldb需要 boost 支持,编译前请确保有安装boost
rem (我用的boost版本是 1.62) 
rem BOOST_ROOT 用于指定 boost 的安装位置
rem 如果你的boost是默认安装到C:\boost,不指定BOOST_ROOT,cmake也能找到boost的位置
cmake .. -G "NMake Makefiles" -DCMAKE_BUILD_TYPE:STRING=RELEASE ^
    -DBOOST_ROOT=%boost_root% ^
    -DBUILD_SHARED_LIBS=off ^
    -DCMAKE_INSTALL_PREFIX=%install_path%
rem 编译并安装到CMAKE_INSTALL_PREFIX指定的位置
nmake install
cd .. 

解决MinGW编译报错

利用上面的CMakeLists.txt也可以用MinGW编译。 但如果用MinGW编译,会有如下报错:

[  1%] Building CXX object CMakeFiles/leveldb.dir/port/port_win.cc.obj
In file included from P:/MinGW/mingw64/x86_64-w64-mingw32/include/locale.h:12:0,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/clocale:42,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/x86_64-w64-mingw32/bits/c++locale.h:41,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/bits/localefwd.h:40,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/string:43,
                 from D:/caffe-static/source/leveldb-master/port/port_win.h:44,
                 from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:
P:/MinGW/mingw64/x86_64-w64-mingw32/include/stdio.h:528:110: error: conflicting declaration of 'int _snprintf(char*, size_t, const char*, ...)' with 'C' linkage
   _CRTIMP int __cdecl _snprintf(char * __restrict__ _Dest,size_t _Count,const char * __restrict__ _Format,...) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
                                                                                                              ^
In file included from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:0:
D:/caffe-static/source/leveldb-master/port/port_win.h:35:18: note: previous declaration with 'C++' linkage
 #define snprintf _snprintf
                  ^
In file included from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/ext/string_conversions.h:43:0,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/bits/basic_string.h:5247,
                 from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/string:52,
                 from D:/caffe-static/source/leveldb-master/port/port_win.h:44,
                 from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:
P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/cstdio:175:11: error: '::snprintf' has not been declared
   using ::snprintf;
           ^
P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/cstdio:185:22: error: '__gnu_cxx::snprintf' has not been declared
   using ::__gnu_cxx::snprintf;
                      ^
CMakeFiles\leveldb.dir\build.make:962: recipe for target 'CMakeFiles/leveldb.dir/port/port_win.cc.obj' failed
make[2]: *** [CMakeFiles/leveldb.dir/port/port_win.cc.obj] Error 1
CMakeFiles\Makefile2:141: recipe for target 'CMakeFiles/leveldb.dir/all' failed
make[1]: *** [CMakeFiles/leveldb.dir/all] Error 2
makefile:128: recipe for target 'all' failed
make: *** [all] Error 2

原因是port/port_win.h中关于snprintf的宏定义#if判断语句有漏洞,只考虑了MSVC编译的情况,却没有考虑MinGW的情况。所以要做如下修改

// 原来的判断只考虑了MSVC,当用MinGW编译时 _MSC_VER < 1900条件也成立,所以就出错了,
// 所以这里多加一个条件限制 defined(_MSC_VER),MinGW编译时就不会进入这个分支
//#if _MSC_VER < 1900
#if defined(_MSC_VER) && _MSC_VER < 1900
#define snprintf _snprintf
#endif

解决了这个问题,再make,编译是通过了,但连接时会报错:

libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x46b): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x64b): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x2a46): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x2be9): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x3235): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x3b19): more undefined references to `std::basic_filebuf<char, std::char_traits<char> >::_close()' follow

其实问题还是出在port/port_win.h,就在我们刚才修改的那段代码下面有一行

#define close _close

就是它造成的。注释掉这一行代码,即可,并且注释掉这一行代码在MSVC(VS2013,VS2015)也都不会报错

可以从这里下载修改后的port_win.h https://code.csdn.net/10km/caffe-static/tree/master/patch/leveldb-master/port/port_win.h

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Laoqi's Linux运维专列

OpenVPN异地机房互连以及负载均衡高可用解决方案

3216
来自专栏逸鹏说道

★Kali信息收集★8.Nmap :端口扫描

突然发现,微信一次最多推送8篇 参数:(Zenmap是Nmap图形化工具,不想打指令的可以直接使用) 详细:https://nmap.org/man/zh/in...

4134
来自专栏知识分享

Android应用更新-自动检测版本及自动升级

http://www.cnblogs.com/keyindex/articles/1819504.html

772
来自专栏杨建荣的学习笔记

GoldenGate安装简记(r10笔记第78天)

GoldenGate这些年在数据迁移中是大放光彩,简称OGG,对于很多DBA来说,学会这项技能也会给自己加分不少。 Oracle在10g开始推出的GRID的概念...

3507
来自专栏数据和云

RMAN CATALOG命令手动注册磁带库中的备份片

ORACLE 官方文档中介绍 CATALOG 命令只能注册在磁盘中的备份片,在现在多数环境中备份时,备份集都是放到磁带库中,那么 CATALOG 命令真就不支持...

1251
来自专栏贾老师の博客

CMake 使用

763
来自专栏乐沙弥的世界

Failed to create or upgrade OLR

    对于Oracle 11g RAC 的安装,与Oracle 10g(clusterware)类似,grid 安装完毕后需要执行orainstroot.sh...

644
来自专栏10km的专栏

windows下msvc/mingw静态编译 lmdb的CMakeLists.txt

LMDB的全称是Lightning Memory-Mapped Database,闪电般的内存映射数据库,在github可以找到源码 https://git...

2726
来自专栏沃趣科技

ASM 翻译系列第十八弹:ASM Internal ASM file number 5

原作者:Bane Radulovic 译者: 魏兴华 审核: 魏兴华 ASM file number 5 本章讲述ASM的5号文件,5号文件是ASM...

3346
来自专栏BinarySec

一些pwn题目的解题思路[pwnable.kr] II

目录 以下是solution的目录 #mistake #shellshock #coin1 #blackjack #lotto #cmd1 Other 一些pw...

3465

扫码关注云+社区