本文操作按照《c&c++开源库编译指南》中内容规范编写,编译环境配置、工具下载、目录规划,及更多其他开源库编译方法请参考该文章。
c&c++开源库编译指南:https://blog.csdn.net/binary0006/article/details/144086155
本文章中的源代码已提交到gitee仓库,地址:https://gitee.com/binary0010/depends/tree/master/c/brotli-1.1.0
1.brotli概述
brotli 是 Google 开发的高效无损压缩算法,基于 LZ77 和霍夫曼编码,通过字典优化与灵活压缩级别(0-11),在文本、代码等场景下实现比 gzip 高约 20% 的压缩率,同时保持快速解压速度。其流式处理特性适配现代网络协议,成为 Web 性能优化的核心技术之一。
brotli 广泛用于 Web 服务器(Nginx/Apache)与浏览器(Chrome/Firefox),通过 HTTP 压缩减少传输体积。移动端(如 Android)及文件存储领域(日志、配置)亦依赖其高压缩率降低资源消耗。开源代码支持多语言实现,BSD 许可推动跨平台集成,已成为 HTTPS 场景下提升数据传输效率的标准方案。
2.brotli编译
2.1.源代码下载
brotli源代码可以在github上下载,源代码下载地址:https://github.com/google/brotli/tags,找到最新版1.1.0版本,点击下图所示链接直接下载即可。
也可以自己复制这个地址下载:https://github.com/google/brotli/archive/refs/tags/v1.1.0.tar.gz
2.2.windows编译
先解压源代码到指定目录,brotli源代码中已经提供了CMakeList.txt脚本,后面我们按照规范会对该脚本进行修改。
2.2.1.源代码修改
由于brotil代码是c语言的,在vs2008中只支持c89标准语法,brotil代码中有一部分c99标准语法,为了支持vs2008我们对源代码进行修改。
2.2.2.修改CMake脚本
修改CMake脚本按照我们的设计的编译规范来进行构建和编译,修改源代码根目录下的CMakeLists.txt即可。
脚本涉及的内容主要是使用我们编译规范来对工程命名和输出,以及mt工程的链接库设置。
CMakeLists.txt完整内容:
# Available CMake versions:
# - Ubuntu 20.04 LTS : 3.16.3
# - Solaris 11.4 SRU 15 : 3.15
cmake_minimum_required(VERSION 3.15)
# Since this project's version is loaded from other files, this policy
# will help suppress the warning generated by cmake.
# This policy is set because we can't provide "VERSION" in "project" command.
# Use `cmake --help-policy CMP0048` for more information.
cmake_policy(SET CMP0048 NEW)
project(brotli C)
option(BUILD_SHARED_LIBS "Build shared libraries" ON)
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to Release as none was specified.")
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE)
else()
message(STATUS "Build type is '${CMAKE_BUILD_TYPE}'")
endif()
include(CheckCSourceCompiles)
check_c_source_compiles(
"#if defined(__EMSCRIPTEN__)
int main() {return 0;}
#endif"
BROTLI_EMSCRIPTEN
)
if(BROTLI_EMSCRIPTEN)
message("-- Compiler is EMSCRIPTEN")
else()
message("-- Compiler is not EMSCRIPTEN")
endif()
# If Brotli is being bundled in another project, we don't want to
# install anything. However, we want to let people override this, so
# we'll use the BROTLI_BUNDLED_MODE variable to let them do that; just
# set it to OFF in your project before you add_subdirectory(brotli).
get_directory_property(BROTLI_PARENT_DIRECTORY PARENT_DIRECTORY)
if(NOT DEFINED BROTLI_BUNDLED_MODE)
# Bundled mode hasn't been set one way or the other, set the default
# depending on whether or not we are the top-level project.
if(BROTLI_PARENT_DIRECTORY)
set(BROTLI_BUNDLED_MODE ON)
else()
set(BROTLI_BUNDLED_MODE OFF)
endif()
endif()
mark_as_advanced(BROTLI_BUNDLED_MODE)
include(GNUInstallDirs)
# Reads macro from .h file; it is expected to be a single-line define.
function(read_macro PATH MACRO OUTPUT)
file(STRINGS ${PATH} _line REGEX "^#define +${MACRO} +(.+)$")
string(REGEX REPLACE "^#define +${MACRO} +(.+)$" "\\1" _val "${_line}")
set(${OUTPUT} ${_val} PARENT_SCOPE)
endfunction(read_macro)
# Version information
read_macro("c/common/version.h" "BROTLI_VERSION_MAJOR" BROTLI_VERSION_MAJOR)
read_macro("c/common/version.h" "BROTLI_VERSION_MINOR" BROTLI_VERSION_MINOR)
read_macro("c/common/version.h" "BROTLI_VERSION_PATCH" BROTLI_VERSION_PATCH)
set(BROTLI_VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_PATCH}")
mark_as_advanced(BROTLI_VERSION BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_PATCH)
# ABI Version information
read_macro("c/common/version.h" "BROTLI_ABI_CURRENT" BROTLI_ABI_CURRENT)
read_macro("c/common/version.h" "BROTLI_ABI_REVISION" BROTLI_ABI_REVISION)
read_macro("c/common/version.h" "BROTLI_ABI_AGE" BROTLI_ABI_AGE)
math(EXPR BROTLI_ABI_COMPATIBILITY "${BROTLI_ABI_CURRENT} - ${BROTLI_ABI_AGE}")
mark_as_advanced(BROTLI_ABI_CURRENT BROTLI_ABI_REVISION BROTLI_ABI_AGE BROTLI_ABI_COMPATIBILITY)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../cmake ${CMAKE_MODULE_PATH})
include(${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/third-common.cmake)
set(INSTALL_BIN_DIR "${third-bin}/${PROJECT_NAME}-${BROTLI_VERSION}" CACHE PATH "Installation directory for executables")
set(INSTALL_LIB_DIR "${third-lib}/${PROJECT_NAME}-${BROTLI_VERSION}" CACHE PATH "Installation directory for libraries")
set(INSTALL_INC_DIR "${third-include}/${PROJECT_NAME}-${BROTLI_VERSION}" CACHE PATH "Installation directory for headers")
set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages")
set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
if(ENABLE_SANITIZER)
set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
endif()
include(CheckFunctionExists)
set(LIBM_LIBRARY)
CHECK_FUNCTION_EXISTS(log2 LOG2_RES)
if(NOT LOG2_RES)
set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}")
set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m")
CHECK_FUNCTION_EXISTS(log2 LOG2_LIBM_RES)
if(LOG2_LIBM_RES)
set(LIBM_LIBRARY "m")
add_definitions(-DBROTLI_HAVE_LOG2=1)
else()
add_definitions(-DBROTLI_HAVE_LOG2=0)
endif()
set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}")
unset(LOG2_LIBM_RES)
unset(orig_req_libs)
else()
add_definitions(-DBROTLI_HAVE_LOG2=1)
endif()
unset(LOG2_RES)
set(BROTLI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/c/include")
mark_as_advanced(BROTLI_INCLUDE_DIRS)
# set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon)
# set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY})
# mark_as_advanced(BROTLI_LIBRARIES)
set(BROTLI_LIBRARIES_CORE_DLL brotliencdll brotlidecdll brotlicommondll)
set(BROTLI_LIBRARIES_DLL ${BROTLI_LIBRARIES_CORE_DLL} ${LIBM_LIBRARY})
mark_as_advanced(BROTLI_LIBRARIES_DLL)
set(BROTLI_LIBRARIES_CORE_LIB brotlienclib brotlideclib brotlicommonlib)
set(BROTLI_LIBRARIES_LIB ${BROTLI_LIBRARIES_CORE_LIB} ${LIBM_LIBRARY})
mark_as_advanced(BROTLI_LIBRARIES_LIB)
set(BROTLI_LIBRARIES_CORE_DLL_MT brotliencdllmt brotlidecdllmt brotlicommondllmt)
set(BROTLI_LIBRARIES_DLL_MT ${BROTLI_LIBRARIES_CORE_DLL_MT} ${LIBM_LIBRARY})
mark_as_advanced(BROTLI_LIBRARIES_DLL_MT)
set(BROTLI_LIBRARIES_CORE_LIB_MT brotlienclibmt brotlideclibmt brotlicommonlibmt)
set(BROTLI_LIBRARIES_LIB_MT ${BROTLI_LIBRARIES_CORE_LIB_MT} ${LIBM_LIBRARY})
mark_as_advanced(BROTLI_LIBRARIES_LIB_MT)
if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
add_definitions(-DOS_LINUX)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
add_definitions(-DOS_FREEBSD)
elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
add_definitions(-DOS_MACOSX)
set(CMAKE_MACOS_RPATH TRUE)
set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib")
endif()
if(BROTLI_EMSCRIPTEN)
set(BUILD_SHARED_LIBS OFF)
endif()
file(GLOB_RECURSE BROTLI_COMMON_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/common/*.c)
# add_library(brotlicommon ${BROTLI_COMMON_SOURCES})
file(GLOB_RECURSE BROTLI_DEC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/dec/*.c)
# add_library(brotlidec ${BROTLI_DEC_SOURCES})
file(GLOB_RECURSE BROTLI_ENC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/enc/*.c)
# add_library(brotlienc ${BROTLI_ENC_SOURCES})
add_library(brotlicommondll SHARED ${BROTLI_COMMON_SOURCES})
add_library(brotlidecdll SHARED ${BROTLI_DEC_SOURCES})
add_library(brotliencdll SHARED ${BROTLI_ENC_SOURCES})
add_library(brotlicommonlib STATIC ${BROTLI_COMMON_SOURCES})
add_library(brotlideclib STATIC ${BROTLI_DEC_SOURCES})
add_library(brotlienclib STATIC ${BROTLI_ENC_SOURCES})
# vs编译器特化设置
if(MSVC)
# mt动态库工程
add_library(brotlicommondllmt SHARED ${BROTLI_COMMON_SOURCES})
set_property(TARGET brotlicommondllmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_library(brotlidecdllmt SHARED ${BROTLI_DEC_SOURCES})
set_property(TARGET brotlidecdllmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_library(brotliencdllmt SHARED ${BROTLI_ENC_SOURCES})
set_property(TARGET brotliencdllmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# mt静态库工程
add_library(brotlicommonlibmt STATIC ${BROTLI_COMMON_SOURCES})
set_property(TARGET brotlicommonlibmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_library(brotlideclibmt STATIC ${BROTLI_DEC_SOURCES})
set_property(TARGET brotlideclibmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
add_library(brotlienclibmt STATIC ${BROTLI_ENC_SOURCES})
set_property(TARGET brotlienclibmt PROPERTY
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
# 设置静态库pdb文件
set_lib_pdb_file(brotlicommon lib)
set_lib_pdb_file(brotlidec lib)
set_lib_pdb_file(brotlienc lib)
set_lib_pdb_file(brotlicommon libmt)
set_lib_pdb_file(brotlidec libmt)
set_lib_pdb_file(brotlienc libmt)
endif()
# Older CMake versions does not understand INCLUDE_DIRECTORIES property.
include_directories(${BROTLI_INCLUDE_DIRS})
if(BUILD_SHARED_LIBS)
foreach(lib ${BROTLI_LIBRARIES_CORE})
target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION")
string(TOUPPER "${lib}" LIB)
set_target_properties(${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION")
endforeach()
endif()
# 设置动态库宏定义
target_compile_definitions(brotlicommondll PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotlicommondll PROPERTIES DEFINE_SYMBOL "BROTLICOMMON_SHARED_COMPILATION")
target_compile_definitions(brotlidecdll PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotlidecdll PROPERTIES DEFINE_SYMBOL "BROTLIDEC_SHARED_COMPILATION")
target_compile_definitions(brotliencdll PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotliencdll PROPERTIES DEFINE_SYMBOL "BROTLIENC_SHARED_COMPILATION")
target_compile_definitions(brotlicommondllmt PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotlicommondllmt PROPERTIES DEFINE_SYMBOL "BROTLICOMMON_SHARED_COMPILATION")
target_compile_definitions(brotlidecdllmt PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotlidecdllmt PROPERTIES DEFINE_SYMBOL "BROTLIDEC_SHARED_COMPILATION")
target_compile_definitions(brotliencdllmt PUBLIC "BROTLI_SHARED_COMPILATION")
set_target_properties(brotliencdllmt PROPERTIES DEFINE_SYMBOL "BROTLIENC_SHARED_COMPILATION")
# foreach(lib ${BROTLI_LIBRARIES_CORE_DLL} ${BROTLI_LIBRARIES_CORE_DLL_MT})
# target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION")
# string(TOUPPER "${lib}" LIB)
# set_target_properties(${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION")
# endforeach()
foreach(lib ${BROTLI_LIBRARIES_CORE})
target_link_libraries(${lib} ${LIBM_LIBRARY})
set_property(TARGET ${lib} APPEND PROPERTY INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIRS})
set_target_properties(${lib} PROPERTIES
VERSION "${BROTLI_ABI_COMPATIBILITY}.${BROTLI_ABI_AGE}.${BROTLI_ABI_REVISION}"
SOVERSION "${BROTLI_ABI_COMPATIBILITY}")
if(NOT BROTLI_EMSCRIPTEN)
set_target_properties(${lib} PROPERTIES POSITION_INDEPENDENT_CODE TRUE)
endif()
set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${BROTLI_INCLUDE_DIRS}>")
endforeach()
if(NOT BROTLI_EMSCRIPTEN)
# target_link_libraries(brotlidec brotlicommon)
# target_link_libraries(brotlienc brotlicommon)
target_link_libraries(brotlidecdll brotlicommondll)
add_dependencies(brotlidecdll brotlicommondll)
target_link_libraries(brotliencdll brotlicommondll)
add_dependencies(brotliencdll brotlicommondll)
target_link_libraries(brotlidecdllmt brotlicommondllmt)
add_dependencies(brotlidecdllmt brotlicommondllmt)
target_link_libraries(brotliencdllmt brotlicommondllmt)
add_dependencies(brotliencdllmt brotlicommondllmt)
endif()
# For projects stuck on older versions of CMake, this will set the
# BROTLI_INCLUDE_DIRS and BROTLI_LIBRARIES variables so they still
# have a relatively easy way to use Brotli:
#
# include_directories(${BROTLI_INCLUDE_DIRS})
# target_link_libraries(foo ${BROTLI_LIBRARIES})
if(BROTLI_PARENT_DIRECTORY)
set(BROTLI_INCLUDE_DIRS "${BROTLI_INCLUDE_DIRS}" PARENT_SCOPE)
set(BROTLI_LIBRARIES "${BROTLI_LIBRARIES}" PARENT_SCOPE)
endif()
# Build the brotli executable
add_executable(brotli c/tools/brotli.c)
# target_link_libraries(brotli ${BROTLI_LIBRARIES})
target_link_libraries(brotli ${BROTLI_LIBRARIES_CORE_LIB})
# Installation
if(NOT BROTLI_BUNDLED_MODE)
# install(
# TARGETS brotli
# RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
# )
# install(
# TARGETS ${BROTLI_LIBRARIES_CORE}
# ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
# LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
# RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}"
# )
# install(
# DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli
# DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
# )
install(
DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli
DESTINATION "${INSTALL_INC_DIR}"
)
install(
TARGETS brotli
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
)
install(
TARGETS ${BROTLI_LIBRARIES_CORE_DLL} ${BROTLI_LIBRARIES_CORE_LIB} ${BROTLI_LIBRARIES_CORE_DLL_MT} ${BROTLI_LIBRARIES_CORE_LIB_MT}
RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
LIBRARY DESTINATION "${INSTALL_LIB_DIR}"
)
# 定义一个空列表来存储所有要安装的 PDB 文件
set(PDB_FILES_TO_INSTALL "")
# 遍历 BROTLI_LIBRARIES_CORE_DLL 列表
foreach(TARGET ${BROTLI_LIBRARIES_CORE_DLL})
list(APPEND PDB_FILES_TO_INSTALL $<TARGET_PDB_FILE:${TARGET}>)
endforeach()
# 遍历 BROTLI_LIBRARIES_CORE_DLL_MT 列表
foreach(TARGET ${BROTLI_LIBRARIES_CORE_DLL_MT})
list(APPEND PDB_FILES_TO_INSTALL $<TARGET_PDB_FILE:${TARGET}>)
endforeach()
# 安装所有 PDB 文件
install(FILES ${PDB_FILES_TO_INSTALL}
DESTINATION "${INSTALL_BIN_DIR}"
OPTIONAL
)
# 静态库pdb调用函数安装
install_lib_pdb_file(brotlicommon lib)
install_lib_pdb_file(brotlienc lib)
install_lib_pdb_file(brotlidec lib)
install_lib_pdb_file(brotlicommon libmt)
install_lib_pdb_file(brotlienc libmt)
install_lib_pdb_file(brotlidec libmt)
endif() # BROTLI_BUNDLED_MODE
# Tests
# If we're targeting Windows but not running on Windows, we need Wine
# to run the tests...
if(NOT BROTLI_DISABLE_TESTS)
if(WIN32 AND NOT CMAKE_HOST_WIN32)
find_program(BROTLI_WRAPPER NAMES wine)
if(NOT BROTLI_WRAPPER)
message(STATUS "wine not found, disabling tests")
set(BROTLI_DISABLE_TESTS TRUE)
endif()
endif()
endif()
# If our compiler is a cross-compiler that we know about (arm/aarch64),
# then we need to use qemu to execute the tests.
if(NOT BROTLI_DISABLE_TESTS)
if("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabihf-.*$")
message(STATUS "Detected arm-linux-gnueabihf cross-compilation")
set(BROTLI_WRAPPER "qemu-arm")
set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabihf")
endif()
if("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabi-.*$")
message(STATUS "Detected arm-linux-gnueabi cross-compilation")
set(BROTLI_WRAPPER "qemu-arm")
set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabi")
endif()
if("${CMAKE_C_COMPILER}" MATCHES "^.*/aarch64-linux-gnu-.*$")
message(STATUS "Detected aarch64-linux-gnu cross-compilation")
set(BROTLI_WRAPPER "qemu-aarch64")
set(BROTLI_WRAPPER_LD_PREFIX "/usr/aarch64-linux-gnu")
endif()
endif()
if(NOT BROTLI_DISABLE_TESTS)
include(CTest)
enable_testing()
set(ROUNDTRIP_INPUTS
tests/testdata/alice29.txt
tests/testdata/asyoulik.txt
tests/testdata/lcet10.txt
tests/testdata/plrabn12.txt
c/enc/encode.c
c/common/dictionary.h
c/dec/decode.c)
foreach(INPUT ${ROUNDTRIP_INPUTS})
get_filename_component(OUTPUT_NAME "${INPUT}" NAME)
set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}")
set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
if(EXISTS "${INPUT_FILE}")
foreach(quality 1 6 9 11)
add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
COMMAND "${CMAKE_COMMAND}"
-DBROTLI_WRAPPER=${BROTLI_WRAPPER}
-DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
-DBROTLI_CLI=$<TARGET_FILE:brotli>
-DQUALITY=${quality}
-DINPUT=${INPUT_FILE}
-DOUTPUT=${OUTPUT_FILE}.${quality}
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake)
endforeach()
else()
message(WARNING "Test file ${INPUT} does not exist.")
endif()
endforeach()
file(GLOB_RECURSE
COMPATIBILITY_INPUTS
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
tests/testdata/*.compressed*)
foreach(INPUT ${COMPATIBILITY_INPUTS})
add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
COMMAND "${CMAKE_COMMAND}"
-DBROTLI_WRAPPER=${BROTLI_WRAPPER}
-DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX}
-DBROTLI_CLI=$<TARGET_FILE:brotli>
-DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
-P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
endforeach()
endif()
# Generate a pkg-config files
# function(generate_pkg_config_path outvar path)
# string(LENGTH "${path}" path_length)
# set(path_args ${ARGV})
# list(REMOVE_AT path_args 0 1)
# list(LENGTH path_args path_args_remaining)
# set("${outvar}" "${path}")
# while(path_args_remaining GREATER 1)
# list(GET path_args 0 name)
# list(GET path_args 1 value)
# get_filename_component(value_full "${value}" ABSOLUTE)
# string(LENGTH "${value}" value_length)
# if(path_length EQUAL value_length AND path STREQUAL value)
# set("${outvar}" "\${${name}}")
# break()
# elseif(path_length GREATER value_length)
# # We might be in a subdirectory of the value, but we have to be
# # careful about a prefix matching but not being a subdirectory
# # (for example, /usr/lib64 is not a subdirectory of /usr/lib).
# # We'll do this by making sure the next character is a directory
# # separator.
# string(SUBSTRING "${path}" ${value_length} 1 sep)
# if(sep STREQUAL "/")
# string(SUBSTRING "${path}" 0 ${value_length} s)
# if(s STREQUAL value)
# string(SUBSTRING "${path}" "${value_length}" -1 suffix)
# set("${outvar}" "\${${name}}${suffix}")
# break()
# endif()
# endif()
# endif()
# list(REMOVE_AT path_args 0 1)
# list(LENGTH path_args path_args_remaining)
# endwhile()
# set("${outvar}" "${${outvar}}" PARENT_SCOPE)
# endfunction(generate_pkg_config_path)
# function(transform_pc_file INPUT_FILE OUTPUT_FILE VERSION)
# file(READ ${INPUT_FILE} TEXT)
# set(PREFIX "${CMAKE_INSTALL_PREFIX}")
# string(REGEX REPLACE "@prefix@" "${PREFIX}" TEXT ${TEXT})
# string(REGEX REPLACE "@exec_prefix@" "${PREFIX}" TEXT ${TEXT})
# generate_pkg_config_path(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" prefix "${PREFIX}")
# string(REGEX REPLACE "@libdir@" "${LIBDIR}" TEXT ${TEXT})
# generate_pkg_config_path(INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}" prefix "${PREFIX}")
# string(REGEX REPLACE "@includedir@" "${INCLUDEDIR}" TEXT ${TEXT})
# string(REGEX REPLACE "@PACKAGE_VERSION@" "${VERSION}" TEXT ${TEXT})
# file(WRITE ${OUTPUT_FILE} ${TEXT})
# endfunction()
# transform_pc_file("scripts/libbrotlicommon.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc" "${BROTLI_VERSION}")
# transform_pc_file("scripts/libbrotlidec.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc" "${BROTLI_VERSION}")
# transform_pc_file("scripts/libbrotlienc.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" "${BROTLI_VERSION}")
# if(NOT BROTLI_BUNDLED_MODE)
# install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
# DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
# DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
# DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
# endif() # BROTLI_BUNDLED_MODE
# if(ENABLE_COVERAGE STREQUAL "yes")
# SETUP_TARGET_FOR_COVERAGE(coverage test coverage)
# endif()
2.2.3.vs2008编译
前面我们已经把vs2008编译错误需要处理的代码以及CMakeLists.txt脚本按照规范修改完毕,下面我们将使用cmake来构建vs2008的工程和编译。
2.2.3.1.cmake构建目录设置
选择源代码根目录(CMakeLists.txt文件在这个目录),设置build目录为源代码根目录下的cmake-vs2008绝对路径为D:/x-app/depends/c/brotli-1.1.0/cmake-vs2008,保证源代码目录干净,会生成工程和临时文件,同时也方便后续有其他的构建工具扩展管理。
2.2.3.2.应用CMake配置
点击“Configure”会弹出编译器选择对话框,这里选择“Visual Studio 9 2008”点击“Finish”按钮等待配置参数完成。
2.2.3.3.去掉不需要的编译选项
因为前面CMakLists.txt脚本被我们修改了,所以这里一定要去掉下面截图所示的2个选项,否则构建时CMake会报错。
2.2.3.4.生成vs解决方案
下面的红色警告忽略不用管,意思是未来的cmake版本不再支持生成vs2008的解决方案。
2.2.3.5.编译工程
使用vs2008打开“brotli.sln”解决方案文件,分别编译Debug和RelWithDebInfo配置。
2.2.3.6.安装库文件、头文件
编译Install工程的Debug和RelWithDebInfo配置,.h文件和编译生成.dll、.lib、pdb文件会拷贝CMakeList.txt中设置的路径下。
至此通过一个CMakeLists配置文件将windows下vs2008常用编译类型的库全部编译出来了,最终库的对应关系如下。
库类型 | 运行库类型 | 库文件 |
动态库 | mdd | brotlicommondlld.dll、brotlicommondlld.lib brotlidecdlld.dll、brotlidecdlld.lib brotlidecdlld.dll、brotlidecdlldlld.lib |
md | brotlicommondll.dll、brotlicommondll.lib brotlidecdll.dll、brotlidecdll.lib brotlidecdll.dll、brotlidecdlldll.lib | |
mtd | brotlicommondllmtd.dll、brotlicommondllmtd.lib brotlidecdllmtd.dll、brotlidecdllmtd.lib brotlidecdllmtd.dll、brotlidecdlldllmtd.lib | |
mt | brotlicommondllmt.dll、brotlicommondllmt.lib brotlidecdllmt.dll、brotlidecdllmt.lib brotlidecdllmt.dll、brotlidecdlldllmt.lib | |
静态库 | mdd | brotlicommonlibd.lib Brotlideclibd.dll brotlideclibd.dll |
md | brotlicommonlib.lib brotlideclibd.dll brotlideclibd.dll | |
mtd | brotlicommonlibmtd.lib brotlideclibmtd.dll brotlideclibmtd.dll | |
mt | brotlicommonlibmt.lib brotlideclibmt.dll brotlideclibmt.dll |
2.2.4.vs2015编译
vs2015编译与vs2008相同的,只需要在CMake生成工程时选择vs2015即可,其他版本的vs也是一样的,选择需要使用的vs版本即可,此处只演示一下vs2015的编译。
因为前面生成过vs2008的工程,需要将build目录设置成cmake-vs2015,再“Configure”选择vs2015即可,其他操作就是一样的了。