• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Ubuntu 12.04 LTS has CMake 2.8.7, and is an important target since
2# several CI services, such as Travis and Drone, use it.  Solaris 11
3# has 2.8.6, and it's not difficult to support if you already have to
4# support 2.8.7.
5cmake_minimum_required(VERSION 2.8.6)
6
7project(brotli)
8
9# If Brotli is being bundled in another project, we don't want to
10# install anything.  However, we want to let people override this, so
11# we'll use the BROTLI_BUNDLED_MODE variable to let them do that; just
12# set it to OFF in your project before you add_subdirectory(brotli).
13get_directory_property(BROTLI_PARENT_DIRECTORY PARENT_DIRECTORY)
14if(BROTLI_BUNDLED_MODE STREQUAL "")
15  # Bundled mode hasn't been set one way or the other, set the default
16  # depending on whether or not we are the top-level project.
17  if(BROTLI_PARENT_DIRECTORY)
18    set(BROTLI_BUNDLED_MODE OFF)
19  else()
20    set(BROTLI_BUNDLED_MODE ON)
21  endif()
22endif()
23mark_as_advanced(BROTLI_BUNDLED_MODE)
24
25include(CMakeDependentOption)
26CMAKE_DEPENDENT_OPTION(BUILD_SHARED_LIBS "Build shared libraries" ON "NOT BROTLI_BUNDLED_MODE" OFF)
27
28include(GNUInstallDirs)
29
30# When building shared libraries it is important to set the correct rpath.
31# See https://cmake.org/Wiki/CMake_RPATH_handling#Always_full_RPATH
32if (BUILD_SHARED_LIBS)
33  add_definitions(-DBROTLI_SHARED_COMPILATION)
34  set(CMAKE_SKIP_BUILD_RPATH FALSE)
35  set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE)
36  set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
37  list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_LIBDIR}" isSystemDir)
38  if ("${isSystemDir}" STREQUAL "-1")
39    set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_LIBDIR}")
40  endif()
41endif()
42
43# Parse version information from common/version.h. Normally we would
44# define these values here and write them out to configuration file(s)
45# (i.e., config.h), but in this case we parse them from
46# common/version.h to be less intrusive.
47function(hex_to_dec HEXADECIMAL DECIMAL)
48  string(TOUPPER "${HEXADECIMAL}" _tail)
49  set(_decimal 0)
50  string(LENGTH "${_tail}" _tail_length)
51  while (_tail_length GREATER 0)
52    math(EXPR _decimal "${_decimal} * 16")
53    string(SUBSTRING "${_tail}" 0 1 _digit)
54    string(SUBSTRING "${_tail}" 1 -1 _tail)
55    if (_digit STREQUAL "A")
56      math(EXPR _decimal "${_decimal} + 10")
57    elseif (_digit STREQUAL "B")
58      math(EXPR _decimal "${_decimal} + 11")
59    elseif (_digit STREQUAL "C")
60      math(EXPR _decimal "${_decimal} + 12")
61    elseif (_digit STREQUAL "D")
62      math(EXPR _decimal "${_decimal} + 13")
63    elseif (_digit STREQUAL "E")
64      math(EXPR _decimal "${_decimal} + 14")
65    elseif (_digit STREQUAL "F")
66      math(EXPR _decimal "${_decimal} + 15")
67    else()
68      math(EXPR _decimal "${_decimal} + ${_digit}")
69    endif()
70    string(LENGTH "${_tail}" _tail_length)
71  endwhile()
72  set(${DECIMAL} ${_decimal} PARENT_SCOPE)
73endfunction(hex_to_dec)
74
75# Version information
76file(STRINGS "common/version.h" _brotli_version_line REGEX "^#define BROTLI_VERSION (0x[0-9a-fA-F]+)$")
77string(REGEX REPLACE "^#define BROTLI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_version_hex "${_brotli_version_line}")
78hex_to_dec("${_brotli_version_hex}" _brotli_version)
79math(EXPR BROTLI_VERSION_MAJOR "${_brotli_version} >> 24")
80math(EXPR BROTLI_VERSION_MINOR "(${_brotli_version} >> 12) & 4095")
81math(EXPR BROTLI_VERSION_REVISION "${_brotli_version} & 4095")
82mark_as_advanced(BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_REVISION)
83
84if (ENABLE_SANITIZER)
85  set(CMAKE_C_FLAGS " ${CMAKE_C_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
86  set(CMAKE_CXX_FLAGS " ${CMAKE_CXX_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
87  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=${ENABLE_SANITIZER}")
88
89  # By default, brotli depends on undefined behavior, but setting
90  # BROTLI_BUILD_PORTABLE should result in a build which does not.
91  if(ENABLE_SANITIZER STREQUAL "undefined")
92    add_definitions(-DBROTLI_BUILD_PORTABLE)
93  endif()
94endif ()
95
96include(CheckFunctionExists)
97set(LIBM_LIBRARY)
98CHECK_FUNCTION_EXISTS(log2 LOG2_RES)
99if(NOT LOG2_RES)
100  set(orig_req_libs "${CMAKE_REQUIRED_LIBRARIES}")
101  set(CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES};m")
102  CHECK_FUNCTION_EXISTS(log2 LOG2_LIBM_RES)
103  if(LOG2_LIBM_RES)
104    set(LIBM_LIBRARY "m")
105  else()
106    message(FATAL_ERROR "log2() not found")
107  endif()
108
109  set(CMAKE_REQUIRED_LIBRARIES "${orig_req_libs}")
110  unset(LOG2_LIBM_RES)
111  unset(orig_req_libs)
112endif()
113unset(LOG2_RES)
114
115set(BROTLI_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/include")
116set(BROTLI_LIBRARIES_CORE brotlienc brotlidec brotlicommon)
117set(BROTLI_LIBRARIES ${BROTLI_LIBRARIES_CORE} ${LIBM_LIBRARY})
118mark_as_advanced(BROTLI_INCLUDE_DIRS BROTLI_LIBRARIES)
119
120if(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
121  add_definitions(-DOS_LINUX)
122elseif(${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
123  add_definitions(-DOS_FREEBSD)
124elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
125  add_definitions(-DOS_MACOSX)
126endif()
127
128add_library(brotlicommon
129  common/dictionary.c)
130add_library(brotlidec
131  dec/bit_reader.c
132  dec/decode.c
133  dec/huffman.c
134  dec/state.c)
135add_library(brotlienc
136  enc/backward_references.c
137  enc/backward_references_hq.c
138  enc/bit_cost.c
139  enc/block_splitter.c
140  enc/brotli_bit_stream.c
141  enc/cluster.c
142  enc/compress_fragment.c
143  enc/compress_fragment_two_pass.c
144  enc/dictionary_hash.c
145  enc/encode.c
146  enc/entropy_encode.c
147  enc/histogram.c
148  enc/literal_cost.c
149  enc/memory.c
150  enc/metablock.c
151  enc/static_dict.c
152  enc/utf8_util.c)
153
154# Older CMake versions does not understand INCLUDE_DIRECTORIES property.
155include_directories(${BROTLI_INCLUDE_DIRS})
156
157foreach(lib brotlicommon brotlidec brotlienc)
158  target_link_libraries(${lib} ${LIBM_LIBRARY})
159  set_property(TARGET ${lib} APPEND PROPERTY INCLUDE_DIRECTORIES ${BROTLI_INCLUDE_DIRS})
160  set_target_properties(${lib} PROPERTIES
161    SOVERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
162    VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
163    POSITION_INDEPENDENT_CODE TRUE)
164  string(TOUPPER "${lib}" LIB)
165  set_target_properties (${lib} PROPERTIES DEFINE_SYMBOL "${LIB}_SHARED_COMPILATION" )
166
167  set_property(TARGET ${lib} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${BROTLI_INCLUDE_DIRS}")
168endforeach()
169
170target_link_libraries(brotlidec brotlicommon)
171target_link_libraries(brotlienc brotlicommon)
172
173# For projects stuck on older versions of CMake, this will set the
174# BROTLI_INCLUDE_DIRS and BROTLI_LIBRARIES variables so they still
175# have a relatively easy way to use Brotli:
176#
177#   include_directories(${BROTLI_INCLUDE_DIRS})
178#   target_link_libraries(foo ${BROTLI_LIBRARIES})
179if(BROTLI_PARENT_DIRECTORY)
180  set(BROTLI_INCLUDE_DIRS "${BROTLI_INCLUDE_DIRS}" PARENT_SCOPE)
181  set(BROTLI_LIBRARIES "${BROTLI_LIBRARIES}" PARENT_SCOPE)
182endif()
183
184# Build the bro executable
185add_executable(bro tools/bro.c)
186target_link_libraries(bro ${BROTLI_LIBRARIES})
187
188# Installation
189if(NOT BROTLI_BUNDLED_MODE)
190  install (TARGETS bro RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}")
191
192  if(WIN32)
193    install(
194      TARGETS ${BROTLI_LIBRARIES_CORE}
195      LIBRARY DESTINATION "${CMAKE_INSTALL_BINDIR}"
196      ARCHIVE DESTINATION "${CMAKE_INSTALL_BINDIR}"
197    )
198  else()
199    install(TARGETS ${BROTLI_LIBRARIES_CORE}
200      LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
201      ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
202    )
203    install(DIRECTORY ${BROTLI_INCLUDE_DIRS}/brotli DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}")
204  endif()
205
206endif()
207
208# Tests
209
210# If we're targeting Windows but not running on Windows, we need Wine
211# to run the tests...
212if(NOT BROTLI_DISABLE_TESTS)
213  if(WIN32 AND NOT CMAKE_HOST_WIN32)
214    find_program(BROTLI_WINE NAMES wine)
215
216    if(NOT BROTLI_WINE)
217      message(STATUS "wine not found, disabling tests")
218      set(BROTLI_DISABLE_TESTS TRUE)
219    endif()
220  endif()
221endif()
222
223if(NOT BROTLI_DISABLE_TESTS)
224  include(CTest)
225  enable_testing()
226
227  set(ROUNDTRIP_INPUTS
228    tests/testdata/alice29.txt
229    tests/testdata/asyoulik.txt
230    tests/testdata/lcet10.txt
231    tests/testdata/plrabn12.txt
232    enc/encode.c
233    common/dictionary.h
234    dec/decode.c)
235
236  foreach(INPUT ${ROUNDTRIP_INPUTS})
237    get_filename_component(OUTPUT_NAME "${INPUT}" NAME)
238
239    set(OUTPUT_FILE "${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_NAME}")
240    set(INPUT_FILE "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}")
241
242    foreach(quality 1 6 9 11)
243      add_test(NAME "${BROTLI_TEST_PREFIX}roundtrip/${INPUT}/${quality}"
244        COMMAND "${CMAKE_COMMAND}"
245          -DBROTLI_WRAPPER=${BROTLI_WINE}
246          -DBROTLI_CLI=$<TARGET_FILE:bro>
247          -DQUALITY=${quality}
248          -DINPUT=${INPUT_FILE}
249  	  -DOUTPUT=${OUTPUT_FILE}.${quality}
250          -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-roundtrip-test.cmake)
251    endforeach()
252  endforeach()
253
254  file(GLOB_RECURSE
255    COMPATIBILITY_INPUTS
256    RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
257    tests/testdata/*.compressed*)
258
259  foreach(INPUT ${COMPATIBILITY_INPUTS})
260    add_test(NAME "${BROTLI_TEST_PREFIX}compatibility/${INPUT}"
261      COMMAND "${CMAKE_COMMAND}"
262        -DBROTLI_WRAPPER=${BROTLI_WINE}
263        -DBROTLI_CLI=$<TARGET_FILE:bro>
264        -DINPUT=${CMAKE_CURRENT_SOURCE_DIR}/${INPUT}
265        -P ${CMAKE_CURRENT_SOURCE_DIR}/tests/run-compatibility-test.cmake)
266  endforeach()
267endif()
268
269# Generate a pkg-config file
270
271include(CMakeParseArguments)
272
273function(generate_pkg_config_path outvar path)
274  string(LENGTH "${path}" path_length)
275
276  set(path_args ${ARGV})
277  list(REMOVE_AT path_args 0 1)
278  list(LENGTH path_args path_args_remaining)
279
280  set("${outvar}" "${path}")
281
282  while(path_args_remaining GREATER 1)
283    list(GET path_args 0 name)
284    list(GET path_args 1 value)
285
286    get_filename_component(value_full "${value}" ABSOLUTE)
287    string(LENGTH "${value}" value_length)
288
289    if(path_length EQUAL value_length AND path STREQUAL value)
290      set("${outvar}" "\${${name}}")
291      break()
292    elseif(path_length GREATER value_length)
293      # We might be in a subdirectory of the value, but we have to be
294      # careful about a prefix matching but not being a subdirectory
295      # (for example, /usr/lib64 is not a subdirectory of /usr/lib).
296      # We'll do this by making sure the next character is a directory
297      # separator.
298      string(SUBSTRING "${path}" ${value_length} 1 sep)
299      if(sep STREQUAL "/")
300        string(SUBSTRING "${path}" 0 ${value_length} s)
301        if(s STREQUAL value)
302          string(SUBSTRING "${path}" "${value_length}" -1 suffix)
303          set("${outvar}" "\${${name}}${suffix}")
304          break()
305        endif()
306      endif()
307    endif()
308
309    list(REMOVE_AT path_args 0 1)
310    list(LENGTH path_args path_args_remaining)
311  endwhile()
312
313  set("${outvar}" "${${outvar}}" PARENT_SCOPE)
314endfunction(generate_pkg_config_path)
315
316function(generate_pkg_config output_file)
317  set (options)
318  set (oneValueArgs NAME DESCRIPTION URL VERSION PREFIX LIBDIR INCLUDEDIR)
319  set (multiValueArgs DEPENDS_PRIVATE CFLAGS LIBRARIES)
320  cmake_parse_arguments(GEN_PKG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
321  unset (options)
322  unset (oneValueArgs)
323  unset (multiValueArgs)
324
325  if(NOT GEN_PKG_PREFIX)
326    set(GEN_PKG_PREFIX "${CMAKE_INSTALL_PREFIX}")
327  endif()
328
329  if(NOT GEN_PKG_LIBDIR)
330    set(GEN_PKG_LIBDIR "${CMAKE_INSTALL_FULL_LIBDIR}")
331  endif()
332  generate_pkg_config_path(GEN_PKG_LIBDIR "${GEN_PKG_LIBDIR}"
333    prefix "${GEN_PKG_PREFIX}")
334
335  if(NOT GEN_PKG_INCLUDEDIR)
336    set(GEN_PKG_INCLUDEDIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}")
337  endif()
338  generate_pkg_config_path(GEN_PKG_INCLUDEDIR "${GEN_PKG_INCLUDEDIR}"
339    prefix "${GEN_PKG_PREFIX}")
340
341  file(WRITE  "${output_file}" "prefix=${GEN_PKG_PREFIX}\n")
342  file(APPEND "${output_file}" "libdir=${GEN_PKG_LIBDIR}\n")
343  file(APPEND "${output_file}" "includedir=${GEN_PKG_INCLUDEDIR}\n")
344  file(APPEND "${output_file}" "\n")
345
346  if(GEN_PKG_NAME)
347    file(APPEND "${output_file}" "Name: ${GEN_PKG_NAME}\n")
348  else()
349    file(APPEND "${output_file}" "Name: ${CMAKE_PROJECT_NAME}\n")
350  endif()
351
352  if(GEN_PKG_DESCRIPTION)
353    file(APPEND "${output_file}" "Description: ${GEN_PKG_DESCRIPTION}\n")
354  endif()
355
356  if(GEN_PKG_URL)
357    file(APPEND "${output_file}" "URL: ${GEN_PKG_URL}\n")
358  endif()
359
360  if(GEN_PKG_VERSION)
361    file(APPEND "${output_file}" "Version: ${GEN_PKG_VERSION}\n")
362  endif()
363
364  if(GEN_PKG_DEPENDS_PRIVATE)
365    file(APPEND "${output_file}" "Requires.private:")
366    foreach(lib ${GEN_PKG_DEPENDS_PRIVATE})
367      file(APPEND "${output_file}" " ${lib}")
368    endforeach()
369    file(APPEND "${output_file}" "\n")
370  endif()
371
372  if(GEN_PKG_LIBRARIES)
373    set(libs)
374
375    file(APPEND "${output_file}" "Libs: -L\${libdir}")
376    foreach(lib ${GEN_PKG_LIBRARIES})
377      file(APPEND "${output_file}" " -l${lib}")
378    endforeach()
379    file(APPEND "${output_file}" "\n")
380  endif()
381
382  file(APPEND "${output_file}" "Cflags: -I\${includedir}")
383  if(GEN_PKG_CFLAGS)
384    foreach(cflag ${GEN_PKG_CFLAGS})
385      file(APPEND "${output_file}" " ${cflag}")
386    endforeach()
387  endif()
388  file(APPEND "${output_file}" "\n")
389endfunction(generate_pkg_config)
390
391generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
392  NAME libbrotlicommon
393  DESCRIPTION "Shared data used by libbrotlienc and libbrotlidec libraries"
394  URL "https://github.com/google/brotli"
395  VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
396  LIBRARIES brotlicommon)
397
398generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
399  NAME libbrotlidec
400  DESCRIPTION "Brotli decoder library"
401  VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
402  URL "https://github.com/google/brotli"
403  DEPENDS_PRIVATE libbrotlicommon
404  LIBRARIES brotlidec)
405
406generate_pkg_config ("${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
407  NAME libbrotlienc
408  DESCRIPTION "Brotli encoder library"
409  VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_REVISION}"
410  URL "https://github.com/google/brotli"
411  DEPENDS_PRIVATE libbrotlicommon
412  LIBRARIES brotlienc)
413
414if(NOT BROTLI_BUNDLED_MODE)
415  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlicommon.pc"
416    DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
417  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlidec.pc"
418    DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
419  install(FILES "${CMAKE_CURRENT_BINARY_DIR}/libbrotlienc.pc"
420    DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig")
421endif()
422
423if (ENABLE_COVERAGE STREQUAL "yes")
424  SETUP_TARGET_FOR_COVERAGE(coverage test coverage)
425endif ()
426