CMakeLists.txt 13 KB

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