1# Available CMake versions: 2# - Ubuntu 20.04 LTS : 3.16.3 3# - Solaris 11.4 SRU 15 : 3.15 4cmake_minimum_required(VERSION 3.15) 5 6# Since this project's version is loaded from other files, this policy 7# will help suppress the warning generated by cmake. 8# This policy is set because we can't provide "VERSION" in "project" command. 9# Use `cmake --help-policy CMP0048` for more information. 10cmake_policy(SET CMP0048 NEW) 11project(brotli C) 12 13option(BUILD_SHARED_LIBS "Build shared libraries" ON) 14 15if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) 16 message(STATUS "Setting build type to Release as none was specified.") 17 set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) 18else() 19 message(STATUS "Build type is '${CMAKE_BUILD_TYPE}'") 20endif() 21 22include(CheckCSourceCompiles) 23check_c_source_compiles( 24 "#if defined(__EMSCRIPTEN__) 25 int main() {return 0;} 26 #endif" 27 BROTLI_EMSCRIPTEN 28) 29if (BROTLI_EMSCRIPTEN) 30 message("-- Compiler is EMSCRIPTEN") 31else() 32 message("-- Compiler is not EMSCRIPTEN") 33endif() 34 35# If Brotli is being bundled in another project, we don't want to 36# install anything. However, we want to let people override this, so 37# we'll use the BROTLI_BUNDLED_MODE variable to let them do that; just 38# set it to OFF in your project before you add_subdirectory(brotli). 39get_directory_property(BROTLI_PARENT_DIRECTORY PARENT_DIRECTORY) 40if(NOT DEFINED BROTLI_BUNDLED_MODE) 41 # Bundled mode hasn't been set one way or the other, set the default 42 # depending on whether or not we are the top-level project. 43 if(BROTLI_PARENT_DIRECTORY) 44 set(BROTLI_BUNDLED_MODE ON) 45 else() 46 set(BROTLI_BUNDLED_MODE OFF) 47 endif() 48endif() 49mark_as_advanced(BROTLI_BUNDLED_MODE) 50 51include(GNUInstallDirs) 52 53# Reads macro from .h file; it is expected to be a single-line define. 54function(read_macro PATH MACRO OUTPUT) 55 file(STRINGS ${PATH} _line REGEX "^#define +${MACRO} +(.+)$") 56 string(REGEX REPLACE "^#define +${MACRO} +(.+)$" "\\1" _val "${_line}") 57 set(${OUTPUT} ${_val} PARENT_SCOPE) 58endfunction(read_macro) 59 60# Version information 61read_macro("c/common/version.h" "BROTLI_VERSION_MAJOR" BROTLI_VERSION_MAJOR) 62read_macro("c/common/version.h" "BROTLI_VERSION_MINOR" BROTLI_VERSION_MINOR) 63read_macro("c/common/version.h" "BROTLI_VERSION_PATCH" BROTLI_VERSION_PATCH) 64set(BROTLI_VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_PATCH}") 65mark_as_advanced(BROTLI_VERSION BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_PATCH) 66 67# ABI Version information 68read_macro("c/common/version.h" "BROTLI_ABI_CURRENT" BROTLI_ABI_CURRENT) 69read_macro("c/common/version.h" "BROTLI_ABI_REVISION" BROTLI_ABI_REVISION) 70read_macro("c/common/version.h" "BROTLI_ABI_AGE" BROTLI_ABI_AGE) 71math(EXPR BROTLI_ABI_COMPATIBILITY "${BROTLI_ABI_CURRENT} - ${BROTLI_ABI_AGE}") 72mark_as_advanced(BROTLI_ABI_CURRENT BROTLI_ABI_REVISION BROTLI_ABI_AGE BROTLI_ABI_COMPATIBILITY) 73 74if (ENABLE_SANITIZER) 75 set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}") 76 set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}") 77 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}") 78endif () 79 80include(CheckFunctionExists) 81set(LIBM_LIBRARY) 82CHECK_FUNCTION_EXISTS(log2 LOG2_RES) 83if(NOT LOG2_RES) 84 set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}") 85 set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m") 86 CHECK_FUNCTION_EXISTS(log2 LOG2_LIBM_RES) 87 if(LOG2_LIBM_RES) 88 set(LIBM_LIBRARY "m") 89 add_definitions(-DBROTLI_HAVE_LOG2=1) 90 else() 91 add_definitions(-DBROTLI_HAVE_LOG2=0) 92 endif() 93 94 set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}") 95 unset(LOG2_LIBM_RES) 96 unset(orig_req_libs) 97else() 98 add_definitions(-DBROTLI_HAVE_LOG2=1) 99endif() 100unset(LOG2_RES) 101 102set(BROTLI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/c/include") 103mark_as_advanced(BROTLI_INCLUDE_DIRS) 104 105set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon) 106set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY}) 107mark_as_advanced(BROTLI_LIBRARIES) 108 109if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") 110 add_definitions(-DOS_LINUX) 111elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") 112 add_definitions(-DOS_FREEBSD) 113elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") 114 add_definitions(-DOS_MACOSX) 115 set(CMAKE_MACOS_RPATH TRUE) 116 set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") 117endif() 118 119if(BROTLI_EMSCRIPTEN) 120 set(BUILD_SHARED_LIBS OFF) 121endif() 122 123file(GLOB_RECURSE BROTLI_COMMON_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/common/*.c) 124add_library(brotlicommon ${BROTLI_COMMON_SOURCES}) 125 126file(GLOB_RECURSE BROTLI_DEC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/dec/*.c) 127add_library(brotlidec ${BROTLI_DEC_SOURCES}) 128 129file(GLOB_RECURSE BROTLI_ENC_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} c/enc/*.c) 130add_library(brotlienc ${BROTLI_ENC_SOURCES}) 131 132# Older CMake versions does not understand INCLUDE_DIRECTORIES property. 133include_directories(${BROTLI_INCLUDE_DIRS}) 134 135if(BUILD_SHARED_LIBS) 136 foreach(lib ${BROTLI_LIBRARIES_CORE}) 137 target_compile_definitions(${lib} PUBLIC "BROTLI_SHARED_COMPILATION" ) 138 string(TOUPPER "${lib}" LIB) 139 set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION") 140 endforeach() 141endif() 142 143foreach(lib ${BROTLI_LIBRARIES_CORE}) 144 target_link_libraries(${lib} ${LIBM_LIBRARY}) 145 set_property(TARGET ${lib} APPEND PROPERTY INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIRS}) 146 set_target_properties(${lib} PROPERTIES 147 VERSION "${BROTLI_ABI_COMPATIBILITY}.${BROTLI_ABI_AGE}.${BROTLI_ABI_REVISION}" 148 SOVERSION "${BROTLI_ABI_COMPATIBILITY}") 149 if(NOT BROTLI_EMSCRIPTEN) 150 set_target_properties(${lib} PROPERTIES POSITION_INDEPENDENT_CODE TRUE) 151 endif() 152 set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "$<BUILD_INTERFACE:${BROTLI_INCLUDE_DIRS}>") 153endforeach() 154 155if(NOT BROTLI_EMSCRIPTEN) 156target_link_libraries(brotlidec brotlicommon) 157target_link_libraries(brotlienc brotlicommon) 158endif() 159 160# For projects stuck on older versions of CMake, this will set the 161# BROTLI_INCLUDE_DIRS and BROTLI_LIBRARIES variables so they still 162# have a relatively easy way to use Brotli: 163# 164# include_directories(${BROTLI_INCLUDE_DIRS}) 165# target_link_libraries(foo ${BROTLI_LIBRARIES}) 166if(BROTLI_PARENT_DIRECTORY) 167 set(BROTLI_INCLUDE_DIRS "${BROTLI_INCLUDE_DIRS}" PARENT_SCOPE) 168 set(BROTLI_LIBRARIES "${BROTLI_LIBRARIES}" PARENT_SCOPE) 169endif() 170 171# Build the brotli executable 172add_executable(brotli c/tools/brotli.c) 173target_link_libraries(brotli ${BROTLI_LIBRARIES}) 174 175# Installation 176if(NOT BROTLI_BUNDLED_MODE) 177 install( 178 TARGETS brotli 179 RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 180 ) 181 182 install( 183 TARGETS ${BROTLI_LIBRARIES_CORE} 184 ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" 185 LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" 186 RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" 187 ) 188 189 install( 190 DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli 191 DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" 192 ) 193endif() # BROTLI_BUNDLED_MODE 194 195# Tests 196 197# If we're targeting Windows but not running on Windows, we need Wine 198# to run the tests... 199if(NOT BROTLI_DISABLE_TESTS) 200 if(WIN32 AND NOT CMAKE_HOST_WIN32) 201 find_program(BROTLI_WRAPPER NAMES wine) 202 203 if(NOT BROTLI_WRAPPER) 204 message(STATUS "wine not found, disabling tests") 205 set(BROTLI_DISABLE_TESTS TRUE) 206 endif() 207 endif() 208endif() 209 210# If our compiler is a cross-compiler that we know about (arm/aarch64), 211# then we need to use qemu to execute the tests. 212if(NOT BROTLI_DISABLE_TESTS) 213 if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabihf-.*$") 214 message(STATUS "Detected arm-linux-gnueabihf cross-compilation") 215 set(BROTLI_WRAPPER "qemu-arm") 216 set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabihf") 217 endif() 218 219 if ("${CMAKE_C_COMPILER}" MATCHES "^.*/arm-linux-gnueabi-.*$") 220 message(STATUS "Detected arm-linux-gnueabi cross-compilation") 221 set(BROTLI_WRAPPER "qemu-arm") 222 set(BROTLI_WRAPPER_LD_PREFIX "/usr/arm-linux-gnueabi") 223 endif() 224 225 if ("${CMAKE_C_COMPILER}" MATCHES "^.*/aarch64-linux-gnu-.*$") 226 message(STATUS "Detected aarch64-linux-gnu cross-compilation") 227 set(BROTLI_WRAPPER "qemu-aarch64") 228 set(BROTLI_WRAPPER_LD_PREFIX "/usr/aarch64-linux-gnu") 229 endif() 230endif() 231 232if(NOT BROTLI_DISABLE_TESTS) 233 include(CTest) 234 enable_testing() 235 236 set(ROUNDTRIP_INPUTS 237 tests/testdata/alice29.txt 238 tests/testdata/asyoulik.txt 239 tests/testdata/lcet10.txt 240 tests/testdata/plrabn12.txt 241 c/enc/encode.c 242 c/common/dictionary.h 243 c/dec/decode.c) 244 245 foreach(INPUT ${ROUNDTRIP_INPUTS}) 246 get_filename_component(OUTPUT_NAME "${INPUT}" NAME) 247 248 set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}") 249 set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}") 250 251 if (EXISTS "${INPUT_FILE}") 252 foreach(quality 1 6 9 11) 253 add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}" 254 COMMAND "${CMAKE_COMMAND}" 255 -DBROTLI_WRAPPER=${BROTLI_WRAPPER} 256 -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX} 257 -DBROTLI_CLI=$<TARGET_FILE:brotli> 258 -DQUALITY=${quality} 259 -DINPUT=${INPUT_FILE} 260 -DOUTPUT=${OUTPUT_FILE}.${quality} 261 -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake) 262 endforeach() 263 else() 264 message(WARNING "Test file ${INPUT} does not exist.") 265 endif() 266 endforeach() 267 268 file(GLOB_RECURSE 269 COMPATIBILITY_INPUTS 270 RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 271 tests/testdata/*.compressed*) 272 273 foreach(INPUT ${COMPATIBILITY_INPUTS}) 274 add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}" 275 COMMAND "${CMAKE_COMMAND}" 276 -DBROTLI_WRAPPER=${BROTLI_WRAPPER} 277 -DBROTLI_WRAPPER_LD_PREFIX=${BROTLI_WRAPPER_LD_PREFIX} 278 -DBROTLI_CLI=$<TARGET_FILE:brotli> 279 -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT} 280 -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake) 281 endforeach() 282endif() 283 284# Generate a pkg-config files 285 286function(generate_pkg_config_path outvar path) 287 string(LENGTH "${path}" path_length) 288 289 set(path_args ${ARGV}) 290 list(REMOVE_AT path_args 0 1) 291 list(LENGTH path_args path_args_remaining) 292 293 set("${outvar}" "${path}") 294 295 while(path_args_remaining GREATER 1) 296 list(GET path_args 0 name) 297 list(GET path_args 1 value) 298 299 get_filename_component(value_full "${value}" ABSOLUTE) 300 string(LENGTH "${value}" value_length) 301 302 if(path_length EQUAL value_length AND path STREQUAL value) 303 set("${outvar}" "\${${name}}") 304 break() 305 elseif(path_length GREATER value_length) 306 # We might be in a subdirectory of the value, but we have to be 307 # careful about a prefix matching but not being a subdirectory 308 # (for example, /usr/lib64 is not a subdirectory of /usr/lib). 309 # We'll do this by making sure the next character is a directory 310 # separator. 311 string(SUBSTRING "${path}" ${value_length} 1 sep) 312 if(sep STREQUAL "/") 313 string(SUBSTRING "${path}" 0 ${value_length} s) 314 if(s STREQUAL value) 315 string(SUBSTRING "${path}" "${value_length}" -1 suffix) 316 set("${outvar}" "\${${name}}${suffix}") 317 break() 318 endif() 319 endif() 320 endif() 321 322 list(REMOVE_AT path_args 0 1) 323 list(LENGTH path_args path_args_remaining) 324 endwhile() 325 326 set("${outvar}" "${${outvar}}" PARENT_SCOPE) 327endfunction(generate_pkg_config_path) 328 329function(transform_pc_file INPUT_FILE OUTPUT_FILE VERSION) 330 file(READ ${INPUT_FILE} TEXT) 331 332 set(PREFIX "${CMAKE_INSTALL_PREFIX}") 333 string(REGEX REPLACE "@prefix@" "${PREFIX}" TEXT ${TEXT}) 334 string(REGEX REPLACE "@exec_prefix@" "${PREFIX}" TEXT ${TEXT}) 335 336 generate_pkg_config_path(LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}" prefix "${PREFIX}") 337 string(REGEX REPLACE "@libdir@" "${LIBDIR}" TEXT ${TEXT}) 338 339 generate_pkg_config_path(INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}" prefix "${PREFIX}") 340 string(REGEX REPLACE "@includedir@" "${INCLUDEDIR}" TEXT ${TEXT}) 341 342 string(REGEX REPLACE "@PACKAGE_VERSION@" "${VERSION}" TEXT ${TEXT}) 343 344 file(WRITE ${OUTPUT_FILE} ${TEXT}) 345endfunction() 346 347transform_pc_file("scripts/libbrotlicommon.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc" "${BROTLI_VERSION}") 348 349transform_pc_file("scripts/libbrotlidec.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc" "${BROTLI_VERSION}") 350 351transform_pc_file("scripts/libbrotlienc.pc.in" "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" "${BROTLI_VERSION}") 352 353if(NOT BROTLI_BUNDLED_MODE) 354 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc" 355 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 356 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc" 357 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 358 install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc" 359 DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") 360endif() # BROTLI_BUNDLED_MODE 361 362if (ENABLE_COVERAGE STREQUAL "yes") 363 SETUP_TARGET_FOR_COVERAGE(coverage test coverage) 364endif () 365