• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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