使用 CMake 编写 Windows 静态库
最近有一个多个 .h .cc .cpp 编译成静态库的需求,故记录下过程
静态库不同于动态库,它不需要 main 入口,只要各个源文件与头文件能对应,也就是源文件和头文件引用的头文件能够找到函数的符号文件,即可编译成功
新手教程参考:
因为只需要用到部分源文件,故单独列出,我的 CMakeLists 写法:
cmake_minimum_required(VERSION 3.12) project(MyLibrary) # 设置编译选项 set(CMAKE_GENERATOR_PLATFORM x86) set(SOURCES cuteui/base/base64.cc cuteui/base/md5.cc cuteui/base/sha1_portable.cc cuteui/base/counter.cc cuteui/base/windows_version.cc cuteui/base/at_exit.cc cuteui/base/debug/alias.cc cuteui/base/debug/debugger.cc cuteui/base/debug/debugger_win.cc cuteui/base/debug/stack_trace.cc cuteui/base/debug/stack_trace_win.cc cuteui/base/win/event_trace_provider.cc cuteui/base/lock.cc cuteui/base/lock_impl_win.cc cuteui/base/event.cc cuteui/base/callback.cc cuteui/base/lazy_instance.cc cuteui/base/memory/singleton.cc cuteui/base/threading/platform_thread.cc cuteui/base/rand_util.cc cuteui/base/rand_util_win.cc cuteui/base/vlog.cc cuteui/base/logging.cc cuteui/base/logging_win.cc cuteui/base/json/values.cc cuteui/base/json/values_op.cc cuteui/base/json/json_reader.cc cuteui/base/json/json_writer.cc cuteui/base/json/string_escape.cc cuteui/base/file/file.cc cuteui/base/file/filedata.cc cuteui/base/file/file_path.cc cuteui/base/file/file_path_constants.cc cuteui/base/string/string_util.cc cuteui/base/string/stringprintf.cc cuteui/base/string/string_number_conversions.cc cuteui/base/string/utf_string_conversion_utils.cc cuteui/base/string/string_piece.cc cuteui/base/string/utf_string_conversions.cc cuteui/base/string/string_split.cc cuteui/base/operation/fileselect.cc cuteui/base/operation/threadpool.cc cuteui/base/third_party/dmg_fp/dtoa.cc cuteui/base/third_party/dmg_fp/g_fmt.cc cuteui/base/third_party/icu/icu_utf.cc cuteui/base/third_party/modp_b64/modp_b64.cc common/bbiconv.cc common/Buffer.cpp common/properties.cpp common/strconv.cpp common/string_easy_conv.cc common/Urlcode.cpp common/wiseint.cc ) # Add a library with the above sources add_library(${PROJECT_NAME} STATIC ${SOURCES}) # 添加头文件搜索路径 include_directories(common cuteui)
在 windows 上 cmake 后会出现 .sln 文件,打开后,项目默认为 x64,并且很多配置都是默认值,直接编译的话会出现很多错误,可以按照自己的需求来手动配置
可能 CMakeLists 里能设置这些选项,我目前还不太会,所以就在项目中手动配置的
编译过程中会遇到很多奇怪的错误,不过都能解决,这边总结一下:
- 出现头文件找不到的情况,可能是存在目录路径的问题,建议加上相对路径
- 明明这个函数有声明,却显示未声明,可能是需要添加预处理器定义,比如我遇到找不到 rand_s 的情况,最后加上 _CRT_RAND_S 解决的(在 C/C++->Preprocessor->Preprocessor Definitions 中添加)
- 可能出现 sdk 中的函数冲突的问题,这个问题经常出现,可以添加一个 stdafx.h 通用头文件,在该头文件添加 winsock2.h 和 windows.h
- 某些函数找不到声明,需要仔细找到该函数的声明文件的位置,使用全局搜索(比如 notepad++ 的文件查找)一般能找到,在项目配置中添加头文件路径即可
- 编译静态库有 debug 和 release 之分,建议两种都编译一下
一些文章参考:
更新:
上面的 CMakeLists.txt 只是简单的将源文件加入VS 工程中,并没有设置 VS 的编译参数,比如设置预处理定义,设置 Unicode 字节,多线程编译等等
cmake_minimum_required(VERSION 3.12) # STREQUAL 比较函数 if(WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") # 创建 win32 工程 # 以 x86 工程架构构建 set(CMAKE_GENERATOR_PLATFORM Win32) set(CMAKE_GENERATOR_TOOLSET "host=x86" CACHE STRING "Platform Toolset" FORCE) endif() project(FrLibrary) if (WIN32 OR CMAKE_SYSTEM_NAME STREQUAL "Windows") # 不构建 ZEROCHECK 工程 set(CMAKE_SUPPRESS_REGENERATION true) # 以 MFC 标志构建 set(CMAKE_MFC_FLAG 1) # 只构建 Debug 和 Release,/Zi 参数表示生成 pdb 文件 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MTd /Zi") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MT /Zi") # 添加预处理定义参数 add_compile_definitions(_CRT_RAND_S NOMINMAX) # 以 Unicode 字节构建 add_definitions(-D_UNICODE) elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux") # Linux-specific configuration endif() # 设置宏路径 set(BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/cuteui/base) set(COMMON_DIR ${CMAKE_CURRENT_SOURCE_DIR}/common) set(SOURCES ${BASE_DIR}/base64.cc ${BASE_DIR}/md5.cc ${BASE_DIR}/sha1_portable.cc ${BASE_DIR}/counter.cc ${BASE_DIR}/windows_version.cc ${BASE_DIR}/at_exit.cc ${BASE_DIR}/debug/alias.cc ${BASE_DIR}/debug/debugger.cc ${BASE_DIR}/debug/debugger_win.cc ${BASE_DIR}/debug/stack_trace.cc ${BASE_DIR}/debug/stack_trace_win.cc ${BASE_DIR}/win/event_trace_provider.cc ${BASE_DIR}/lock.cc ${BASE_DIR}/lock_impl_win.cc ${BASE_DIR}/event.cc ${BASE_DIR}/callback.cc ${BASE_DIR}/lazy_instance.cc ${BASE_DIR}/memory/singleton.cc ${BASE_DIR}/threading/platform_thread.cc ${BASE_DIR}/rand_util.cc ${BASE_DIR}/rand_util_win.cc ${BASE_DIR}/vlog.cc ${BASE_DIR}/logging.cc ${BASE_DIR}/logging_win.cc ${BASE_DIR}/json/values.cc ${BASE_DIR}/json/values_op.cc ${BASE_DIR}/json/json_reader.cc ${BASE_DIR}/json/json_writer.cc ${BASE_DIR}/json/string_escape.cc ${BASE_DIR}/file/file.cc ${BASE_DIR}/file/filedata.cc ${BASE_DIR}/file/file_path.cc ${BASE_DIR}/file/file_path_constants.cc ${BASE_DIR}/string/string_util.cc ${BASE_DIR}/string/stringprintf.cc ${BASE_DIR}/string/string_number_conversions.cc ${BASE_DIR}/string/utf_string_conversion_utils.cc ${BASE_DIR}/string/string_piece.cc ${BASE_DIR}/string/utf_string_conversions.cc ${BASE_DIR}/string/string_split.cc ${BASE_DIR}/operation/fileselect_win.cc ${BASE_DIR}/operation/threadpool.cc ${BASE_DIR}/third_party/dmg_fp/dtoa.cc ${BASE_DIR}/third_party/dmg_fp/g_fmt.cc ${BASE_DIR}/third_party/icu/icu_utf.cc ${BASE_DIR}/third_party/modp_b64/modp_b64.cc ${COMMON_DIR}/bbiconv.cc ${COMMON_DIR}/Buffer.cpp ${COMMON_DIR}/properties.cpp ${COMMON_DIR}/strconv.cpp ${COMMON_DIR}/string_easy_conv.cc ${COMMON_DIR}/Urlcode.cpp ${COMMON_DIR}/wiseint.cc ) # 如果是以 Debug 方式构建,输出的文件末尾加 'd' if(NOT CMAKE_DEBUG_POSTFIX) set(CMAKE_DEBUG_POSTFIX d) endif() # 添加头文件 include_directories(${CMAKE_CURRENT_SOURCE_DIR} common cuteui) # 输出 lib 静态库 add_library(${PROJECT_NAME} STATIC ${SOURCES})
参考: