cmake:vs2015/MinGW静态编译leveldb

Love The Way You Lie 2022-06-13 00:27 679阅读 0赞

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标记,可以找到所有添加的代码)

  1. cmake_minimum_required(VERSION 3.0.2 FATAL_ERROR)
  2. project(leveldb CXX)
  3. set(CMAKE_DEBUG_POSTFIX "d")
  4. set(Boost_USE_STATIC_LIBS ON)
  5. set(Boost_USE_MULTITHREAD ON)
  6. set(Boost_USE_STATIC_RUNTIME OFF)
  7. find_package(Boost COMPONENTS
  8. date_time
  9. filesystem
  10. system
  11. REQUIRED)
  12. set(SNAPPY_LIBRARY "")
  13. string(REGEX MATCH "clang" CLANG ${CMAKE_CXX_COMPILER})
  14. if(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
  15. find_library(Pthread_LIBRARY pthread)
  16. find_library(Realtime_LIBRARY rt)
  17. # find library can be problematic with stdc++ which is why we hardwire the link
  18. set(Stdcpp_LIBRARY stdc++)
  19. else(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
  20. set(Pthread_LIBRARY "")
  21. set(Realtime_LIBRARY "")
  22. set(Stdcpp_LIBRARY "")
  23. endif(CMAKE_COMPILER_IS_GNUCXX OR CLANG)
  24. include_directories(${Boost_INCLUDE_DIRS}
  25. ${CMAKE_CURRENT_SOURCE_DIR}
  26. include)
  27. if(MSVC)
  28. add_compile_options(
  29. /D_CRT_SECURE_NO_WARNINGS
  30. /wd4389 # signed/unsigned mismatch
  31. /wd4800 # constructor never returns, potential memory leak because of a singleton pattern
  32. /wd4722 # unreachable code because of singleton pattern
  33. /wd4702 # bool cast performance warning
  34. )
  35. else()
  36. add_compile_options(
  37. -Wno-sign-compare
  38. -std=c++11
  39. )
  40. endif()
  41. add_definitions(
  42. -DLEVELDB_ATOMIC_PRESENT
  43. )
  44. set(LEVEL_DB_FILES
  45. include/leveldb/c.h
  46. include/leveldb/cache.h
  47. include/leveldb/comparator.h
  48. include/leveldb/db.h
  49. include/leveldb/dumpfile.h
  50. include/leveldb/env.h
  51. include/leveldb/iterator.h
  52. include/leveldb/filter_policy.h
  53. include/leveldb/iterator.h
  54. include/leveldb/options.h
  55. include/leveldb/slice.h
  56. include/leveldb/status.h
  57. include/leveldb/table.h
  58. include/leveldb/table_builder.h
  59. include/leveldb/write_batch.h
  60. db/builder.cc
  61. db/builder.h
  62. db/db_impl.cc
  63. db/db_impl.h
  64. db/db_iter.cc
  65. db/db_iter.h
  66. db/dbformat.cc
  67. db/dbformat.h
  68. db/dumpfile.cc
  69. db/filename.cc
  70. db/filename.h
  71. db/log_format.h
  72. db/log_reader.cc
  73. db/log_reader.h
  74. db/log_writer.cc
  75. db/log_writer.h
  76. db/skiplist.h
  77. db/snapshot.h
  78. db/memtable.cc
  79. db/memtable.h
  80. db/repair.cc
  81. db/table_cache.cc
  82. db/table_cache.h
  83. db/version_edit.cc
  84. db/version_edit.h
  85. db/version_set.cc
  86. db/version_set.h
  87. db/write_batch.cc
  88. table/block.cc
  89. table/block.h
  90. table/block_builder.cc
  91. table/block_builder.h
  92. table/filter_block.cc
  93. table/filter_block.h
  94. table/format.cc
  95. table/format.h
  96. table/iterator.cc
  97. table/iterator_wrapper.h
  98. table/merger.cc
  99. table/merger.h
  100. table/table.cc
  101. table/table_builder.cc
  102. table/two_level_iterator.cc
  103. table/two_level_iterator.h
  104. util/arena.cc
  105. util/arena.h
  106. util/bloom.cc
  107. util/cache.cc
  108. util/coding.cc
  109. util/coding.h
  110. util/comparator.cc
  111. util/crc32c.cc
  112. util/crc32c.h
  113. util/env.cc
  114. util/filter_policy.cc
  115. util/hash.cc
  116. util/hash.h
  117. util/histogram.cc
  118. util/histogram.h
  119. util/logging.cc
  120. util/logging.h
  121. util/mutexlock.h
  122. util/options.cc
  123. util/random.h
  124. util/status.cc
  125. port/port.h)
  126. if(WIN32)
  127. list(APPEND LEVEL_DB_FILES
  128. port/port_win.h
  129. port/port_win.cc
  130. util/win_logger.h
  131. util/win_logger.cc
  132. util/env_boost.cc)
  133. else()
  134. list(APPEND LEVEL_DB_FILES
  135. port/port_posix.h
  136. port/port_posix.cc
  137. util/posix_logger.h
  138. util/env_posix.cc)
  139. endif()
  140. add_library(leveldb ${LEVEL_DB_FILES})
  141. target_include_directories(leveldb
  142. PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include
  143. PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}
  144. )
  145. target_link_libraries(leveldb
  146. PRIVATE
  147. ${Boost_LIBRARIES}
  148. ${Pthread_LIBRARY}
  149. )
  150. add_executable(leveldbutil
  151. db/leveldb_main.cc)
  152. target_link_libraries(leveldbutil
  153. leveldb)
  154. set_target_properties(leveldbutil PROPERTIES
  155. DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
  156. # we distribute the leveldbutil as it might be useful
  157. install(TARGETS leveldbutil
  158. RUNTIME DESTINATION bin
  159. LIBRARY DESTINATION lib
  160. ARCHIVE DESTINATION lib)
  161. # modified by guyadong
  162. # 将 leveldb 库安装到 lib下
  163. install(TARGETS leveldb
  164. LIBRARY DESTINATION lib
  165. ARCHIVE DESTINATION lib)
  166. # 复制 include 文件夹
  167. install(DIRECTORY include DESTINATION .)
  168. # end of modified by guyadong
  169. ##################################### TESTS #######################################
  170. # Every leveldb test file has to be compiled as an independant binary
  171. # because of the test framework used by leveldb.
  172. add_library(leveldb_test_rt
  173. util/testutil.h
  174. util/testutil.cc
  175. util/testharness.h
  176. util/testharness.cc)
  177. target_include_directories(leveldb_test_rt
  178. PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include
  179. )
  180. add_custom_target(RUN_LEVELDB_UNIT_TESTS
  181. COMMAND ${CMAKE_CTEST_COMMAND}
  182. --build-config ${CMAKE_CFG_INTDIR}
  183. --output-log LevelDB_test_${CMAKE_CFG_INTDIR}.log
  184. --output-on-failure
  185. --tests-regex leveldb
  186. COMMENT "Running all LevelDB unit tests"
  187. )
  188. function(LEVELDB_ADD_TEST TESTNAME TESTFILE)
  189. if(NOT TESTNAME)
  190. message(SEND_ERROR "Error: LEVELDB_ADD_TEST called without test name")
  191. return()
  192. endif(NOT TESTNAME)
  193. if(NOT TESTFILE)
  194. message(SEND_ERROR "Error: LEVELDB_ADD_TEST called without test file")
  195. return()
  196. endif(NOT TESTFILE)
  197. add_executable(leveldb_${TESTNAME}_test
  198. ${TESTFILE})
  199. target_link_libraries(leveldb_${TESTNAME}_test
  200. leveldb_test_rt
  201. leveldb)
  202. set_target_properties(leveldb_${TESTNAME}_test PROPERTIES
  203. DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
  204. add_test(NAME leveldb_${TESTNAME}_test COMMAND leveldb_${TESTNAME}_test)
  205. add_dependencies(RUN_LEVELDB_UNIT_TESTS leveldb_${TESTNAME}_test)
  206. # modified by guyadong
  207. # 将所有测试程序安装到 bin 下
  208. install(TARGETS leveldb_${TESTNAME}_test RUNTIME DESTINATION bin)
  209. # end of modified by guyadong
  210. endfunction(LEVELDB_ADD_TEST)
  211. LEVELDB_ADD_TEST(env util/env_test.cc)
  212. LEVELDB_ADD_TEST(crc32 util/crc32c_test.cc)
  213. LEVELDB_ADD_TEST(coding util/coding_test.cc)
  214. LEVELDB_ADD_TEST(arena util/arena_test.cc)
  215. LEVELDB_ADD_TEST(cache util/cache_test.cc)
  216. LEVELDB_ADD_TEST(table table/table_test.cc)
  217. # IMPORTANT: Commented a test that fails randomly.
  218. # LEVELDB_ADD_TEST(autocompact db/autocompact_test.cc)
  219. LEVELDB_ADD_TEST(corruption db/corruption_test.cc)
  220. LEVELDB_ADD_TEST(dbformat db/dbformat_test.cc)
  221. LEVELDB_ADD_TEST(filename db/filename_test.cc)
  222. LEVELDB_ADD_TEST(log db/log_test.cc)
  223. LEVELDB_ADD_TEST(skiplist db/skiplist_test.cc)
  224. LEVELDB_ADD_TEST(version_edit db/version_edit_test.cc)
  225. LEVELDB_ADD_TEST(write_batch db/write_batch_test.cc)
  226. LEVELDB_ADD_TEST(version_set db/version_set_test.cc)
  227. LEVELDB_ADD_TEST(filter_block table/filter_block_test.cc)
  228. LEVELDB_ADD_TEST(bloom util/bloom_test.cc)
  229. LEVELDB_ADD_TEST(hash util/hash_test.cc)
  230. LEVELDB_ADD_TEST(db_bench db/db_bench.cc)
  231. 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。下面是脚本编译过程

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

解决MinGW编译报错

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

  1. [ 1%] Building CXX object CMakeFiles/leveldb.dir/port/port_win.cc.obj
  2. In file included from P:/MinGW/mingw64/x86_64-w64-mingw32/include/locale.h:12:0,
  3. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/clocale:42,
  4. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/x86_64-w64-mingw32/bits/c++locale.h:41,
  5. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/bits/localefwd.h:40,
  6. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/string:43,
  7. from D:/caffe-static/source/leveldb-master/port/port_win.h:44,
  8. from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:
  9. 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
  10. _CRTIMP int __cdecl _snprintf(char * __restrict__ _Dest,size_t _Count,const char * __restrict__ _Format,...) __MINGW_ATTRIB_DEPRECATED_SEC_WARN;
  11. ^
  12. In file included from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:0:
  13. D:/caffe-static/source/leveldb-master/port/port_win.h:35:18: note: previous declaration with 'C++' linkage
  14. #define snprintf _snprintf
  15. ^
  16. In file included from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/ext/string_conversions.h:43:0,
  17. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/bits/basic_string.h:5247,
  18. from P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/string:52,
  19. from D:/caffe-static/source/leveldb-master/port/port_win.h:44,
  20. from D:\caffe-static\source\leveldb-master\port\port_win.cc:31:
  21. P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/cstdio:175:11: error: '::snprintf' has not been declared
  22. using ::snprintf;
  23. ^
  24. P:/MinGW/mingw64/x86_64-w64-mingw32/include/c++/cstdio:185:22: error: '__gnu_cxx::snprintf' has not been declared
  25. using ::__gnu_cxx::snprintf;
  26. ^
  27. CMakeFiles\leveldb.dir\build.make:962: recipe for target 'CMakeFiles/leveldb.dir/port/port_win.cc.obj' failed
  28. make[2]: *** [CMakeFiles/leveldb.dir/port/port_win.cc.obj] Error 1
  29. CMakeFiles\Makefile2:141: recipe for target 'CMakeFiles/leveldb.dir/all' failed
  30. make[1]: *** [CMakeFiles/leveldb.dir/all] Error 2
  31. makefile:128: recipe for target 'all' failed
  32. make: *** [all] Error 2

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

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

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

  1. libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x46b): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
  2. libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x64b): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
  3. libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x2a46): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
  4. libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x2be9): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
  5. libleveldb.a(env_boost.cc.obj):env_boost.cc:(.text+0x3235): undefined reference to `std::basic_filebuf<char, std::char_traits<char> >::_close()'
  6. 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,就在我们刚才修改的那段代码下面有一行

  1. #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 条评论,679人围观)

还没有评论,来说两句吧...

相关阅读