From 9cbdf962a0ffa7f819bf52cefffceb39324a4f87 Mon Sep 17 00:00:00 2001 From: Evgenii Kliuchnikov Date: Wed, 26 Jul 2023 02:08:06 -0700 Subject: [PATCH] simplify CMake build PiperOrigin-RevId: 551135631 --- CMakeLists.txt | 80 +++++----------- c/common/version.h | 25 +++-- c/include/brotli/decode.h | 2 +- c/include/brotli/encode.h | 2 +- c/tools/brotli.c | 6 +- docs/decode.h.3 | 2 +- docs/encode.h.3 | 2 +- scripts/sources.lst | 111 ---------------------- setup.py | 187 +++++++++++++++++++------------------- 9 files changed, 142 insertions(+), 275 deletions(-) delete mode 100644 scripts/sources.lst diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c391f604..bf5204d00 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -50,55 +50,23 @@ mark_as_advanced(BROTLI_BUNDLED_MODE) include(GNUInstallDirs) -# Parse version information from common/version.h. Normally we would -# define these values here and write them out to configuration file(s) -# (i.e., config.h), but in this case we parse them from -# common/version.h to be less intrusive. -function(hex_to_dec HEXADECIMAL DECIMAL) - string(TOUPPER "${HEXADECIMAL}" _tail) - set(_decimal 0) - string(LENGTH "${_tail}" _tail_length) - while (_tail_length GREATER 0) - math(EXPR _decimal "${_decimal} * 16") - string(SUBSTRING "${_tail}" 0 1 _digit) - string(SUBSTRING "${_tail}" 1 -1 _tail) - if (_digit STREQUAL "A") - math(EXPR _decimal "${_decimal} + 10") - elseif (_digit STREQUAL "B") - math(EXPR _decimal "${_decimal} + 11") - elseif (_digit STREQUAL "C") - math(EXPR _decimal "${_decimal} + 12") - elseif (_digit STREQUAL "D") - math(EXPR _decimal "${_decimal} + 13") - elseif (_digit STREQUAL "E") - math(EXPR _decimal "${_decimal} + 14") - elseif (_digit STREQUAL "F") - math(EXPR _decimal "${_decimal} + 15") - else() - math(EXPR _decimal "${_decimal} + ${_digit}") - endif() - string(LENGTH "${_tail}" _tail_length) - endwhile() - set(${DECIMAL} ${_decimal} PARENT_SCOPE) -endfunction(hex_to_dec) +# 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 -file(STRINGS "c/common/version.h" _brotli_version_line REGEX "^#define BROTLI_VERSION (0x[0-9a-fA-F]+)$") -string(REGEX REPLACE "^#define BROTLI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_version_hex "${_brotli_version_line}") -hex_to_dec("${_brotli_version_hex}" _brotli_version) -math(EXPR BROTLI_VERSION_MAJOR "${_brotli_version} >> 24") -math(EXPR BROTLI_VERSION_MINOR "(${_brotli_version} >> 12) & 4095") -math(EXPR BROTLI_VERSION_PATCH "${_brotli_version} & 4095") -set(BROTLI_VERSION "${BROTLI_VERSION_MAJOR}.${BROTLI_VERSION_MINOR}.${BROTLI_VERSION_PATCH}") +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) mark_as_advanced(BROTLI_VERSION BROTLI_VERSION_MAJOR BROTLI_VERSION_MINOR BROTLI_VERSION_PATCH) # ABI Version information -file(STRINGS "c/common/version.h" _brotli_abi_info_line REGEX "^#define BROTLI_ABI_VERSION (0x[0-9a-fA-F]+)$") -string(REGEX REPLACE "^#define BROTLI_ABI_VERSION 0x([0-9a-fA-F]+)$" "\\1" _brotli_abi_info_hex "${_brotli_abi_info_line}") -hex_to_dec("${_brotli_abi_info_hex}" _brotli_abi_info) -math(EXPR BROTLI_ABI_CURRENT "${_brotli_abi_info} >> 24") -math(EXPR BROTLI_ABI_REVISION "(${_brotli_abi_info} >> 12) & 4095") -math(EXPR BROTLI_ABI_AGE "${_brotli_abi_info} & 4095") +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) @@ -147,24 +115,18 @@ elseif(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") set(CMAKE_INSTALL_NAME_DIR "${CMAKE_INSTALL_PREFIX}/lib") endif() -function(transform_sources_list INPUT_FILE OUTPUT_FILE) - file(READ ${INPUT_FILE} TEXT) - string(REGEX REPLACE "\\\\\n" "~continuation~" TEXT ${TEXT}) - string(REGEX REPLACE "([a-zA-Z_][a-zA-Z0-9_]*)[\t ]*=[\t ]*([^\n]*)" "SET(\\1 \\2)" TEXT ${TEXT}) - string(REPLACE "~continuation~" "\n" TEXT ${TEXT}) - file(WRITE ${OUTPUT_FILE} ${TEXT}) -endfunction() - -transform_sources_list("scripts/sources.lst" "${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake") -include("${CMAKE_CURRENT_BINARY_DIR}/sources.lst.cmake") - if(BROTLI_EMSCRIPTEN) set(BUILD_SHARED_LIBS OFF) endif() -add_library(brotlicommon ${BROTLI_COMMON_C}) -add_library(brotlidec ${BROTLI_DEC_C}) -add_library(brotlienc ${BROTLI_ENC_C}) +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}) # Older CMake versions does not understand INCLUDE_DIRECTORIES property. include_directories(${BROTLI_INCLUDE_DIRS}) @@ -206,7 +168,7 @@ if(BROTLI_PARENT_DIRECTORY) endif() # Build the brotli executable -add_executable(brotli ${BROTLI_CLI_C}) +add_executable(brotli c/tools/brotli.c) target_link_libraries(brotli ${BROTLI_LIBRARIES}) # Installation diff --git a/c/common/version.h b/c/common/version.h index 01b2998e2..0939eb8b6 100644 --- a/c/common/version.h +++ b/c/common/version.h @@ -9,18 +9,31 @@ #ifndef BROTLI_COMMON_VERSION_H_ #define BROTLI_COMMON_VERSION_H_ -/* This macro should only be used when library is compiled together with client. - If library is dynamically linked, use BrotliDecoderVersion and +/* Compose 3 components into a single number. In a hexadecimal representation + B and C components occupy exactly 3 digits. */ +#define BROTLI_MAKE_HEX_VERSION(A, B, C) ((A << 24) | (B << 12) | C) + +/* Those macros should only be used when library is compiled together with + the client. If library is dynamically linked, use BrotliDecoderVersion and BrotliEncoderVersion methods. */ -/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */ -#define BROTLI_VERSION 0x1000009 +#define BROTLI_VERSION_MAJOR 1 +#define BROTLI_VERSION_MINOR 0 +#define BROTLI_VERSION_PATCH 9 + +#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \ + BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH) /* This macro is used by build system to produce Libtool-friendly soname. See https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html + Version evolution rules: + - interfaces added (or change is compatible) -> current+1:0:age+1 + - interfaces removed (or changed is incompatible) -> current+1:0:0 + - interfaces not changed -> current:revision+1:age */ -/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */ -#define BROTLI_ABI_VERSION 0x1009000 +#define BROTLI_ABI_CURRENT 1 +#define BROTLI_ABI_REVISION 9 +#define BROTLI_ABI_AGE 0 #endif /* BROTLI_COMMON_VERSION_H_ */ diff --git a/c/include/brotli/decode.h b/c/include/brotli/decode.h index 3c473d611..af1aa23f6 100644 --- a/c/include/brotli/decode.h +++ b/c/include/brotli/decode.h @@ -357,7 +357,7 @@ BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c); /** * Gets a decoder library version. * - * Look at BROTLI_VERSION for more information. + * Look at BROTLI_MAKE_HEX_VERSION for more information. */ BROTLI_DEC_API uint32_t BrotliDecoderVersion(void); diff --git a/c/include/brotli/encode.h b/c/include/brotli/encode.h index 7247d3d69..dea9931eb 100644 --- a/c/include/brotli/encode.h +++ b/c/include/brotli/encode.h @@ -490,7 +490,7 @@ BROTLI_ENC_EXTRA_API size_t BrotliEncoderGetPreparedDictionarySize( /** * Gets an encoder library version. * - * Look at BROTLI_VERSION for more information. + * Look at BROTLI_MAKE_HEX_VERSION for more information. */ BROTLI_ENC_API uint32_t BrotliEncoderVersion(void); diff --git a/c/tools/brotli.c b/c/tools/brotli.c index b7afae337..f7e531eb7 100644 --- a/c/tools/brotli.c +++ b/c/tools/brotli.c @@ -561,9 +561,9 @@ static Command ParseParams(Context* params) { } static void PrintVersion(void) { - int major = BROTLI_VERSION >> 24; - int minor = (BROTLI_VERSION >> 12) & 0xFFF; - int patch = BROTLI_VERSION & 0xFFF; + int major = BROTLI_VERSION_MAJOR; + int minor = BROTLI_VERSION_MINOR; + int patch = BROTLI_VERSION_PATCH; fprintf(stdout, "brotli %d.%d.%d\n", major, minor, patch); } diff --git a/docs/decode.h.3 b/docs/decode.h.3 index 320663c5f..30929e972 100644 --- a/docs/decode.h.3 +++ b/docs/decode.h.3 @@ -499,7 +499,7 @@ pointer to output data .SS "uint32_t BrotliDecoderVersion (void)" .PP -Gets a decoder library version\&. Look at BROTLI_VERSION for more information\&. +Gets a decoder library version\&. Look at BROTLI_MAKE_HEX_VERSION for more information\&. .SH "Author" .PP Generated automatically by Doxygen for Brotli from the source code\&. diff --git a/docs/encode.h.3 b/docs/encode.h.3 index f3430fa9e..eea97d99f 100644 --- a/docs/encode.h.3 +++ b/docs/encode.h.3 @@ -624,7 +624,7 @@ pointer to output data .SS "uint32_t BrotliEncoderVersion (void)" .PP -Gets an encoder library version\&. Look at BROTLI_VERSION for more information\&. +Gets an encoder library version\&. Look at BROTLI_MAKE_HEX_VERSION for more information\&. .SH "Author" .PP Generated automatically by Doxygen for Brotli from the source code\&. diff --git a/scripts/sources.lst b/scripts/sources.lst deleted file mode 100644 index 2848cc54d..000000000 --- a/scripts/sources.lst +++ /dev/null @@ -1,111 +0,0 @@ -# IT WOULD BE FOOLISH TO USE COMPUTERS TO AUTOMATE REPETITIVE TASKS: -# neither CMake nor Automake support "glob" expressions, -# so every header and source file have to be listed manually. - -BROTLI_CLI_C = \ - c/tools/brotli.c - -BROTLI_COMMON_C = \ - c/common/constants.c \ - c/common/context.c \ - c/common/dictionary.c \ - c/common/platform.c \ - c/common/shared_dictionary.c \ - c/common/transform.c - -BROTLI_COMMON_H = \ - c/common/constants.h \ - c/common/context.h \ - c/common/dictionary.h \ - c/common/platform.h \ - c/common/shared_dictionary_internal.h \ - c/common/transform.h \ - c/common/version.h - -BROTLI_DEC_C = \ - c/dec/bit_reader.c \ - c/dec/decode.c \ - c/dec/huffman.c \ - c/dec/state.c - -BROTLI_DEC_H = \ - c/dec/bit_reader.h \ - c/dec/huffman.h \ - c/dec/prefix.h \ - c/dec/state.h - -BROTLI_ENC_C = \ - c/enc/backward_references.c \ - c/enc/backward_references_hq.c \ - c/enc/bit_cost.c \ - c/enc/block_splitter.c \ - c/enc/brotli_bit_stream.c \ - c/enc/cluster.c \ - c/enc/command.c \ - c/enc/compound_dictionary.c \ - c/enc/compress_fragment.c \ - c/enc/compress_fragment_two_pass.c \ - c/enc/dictionary_hash.c \ - c/enc/encode.c \ - c/enc/encoder_dict.c \ - c/enc/entropy_encode.c \ - c/enc/fast_log.c \ - c/enc/histogram.c \ - c/enc/literal_cost.c \ - c/enc/memory.c \ - c/enc/metablock.c \ - c/enc/static_dict.c \ - c/enc/utf8_util.c - -BROTLI_ENC_H = \ - c/enc/backward_references.h \ - c/enc/backward_references_hq.h \ - c/enc/backward_references_inc.h \ - c/enc/bit_cost.h \ - c/enc/bit_cost_inc.h \ - c/enc/block_encoder_inc.h \ - c/enc/block_splitter.h \ - c/enc/block_splitter_inc.h \ - c/enc/brotli_bit_stream.h \ - c/enc/cluster.h \ - c/enc/cluster_inc.h \ - c/enc/command.h \ - c/enc/compound_dictionary.h \ - c/enc/compress_fragment.h \ - c/enc/compress_fragment_two_pass.h \ - c/enc/dictionary_hash.h \ - c/enc/encoder_dict.h \ - c/enc/entropy_encode.h \ - c/enc/entropy_encode_static.h \ - c/enc/fast_log.h \ - c/enc/find_match_length.h \ - c/enc/hash.h \ - c/enc/hash_composite_inc.h \ - c/enc/hash_forgetful_chain_inc.h \ - c/enc/hash_longest_match64_inc.h \ - c/enc/hash_longest_match_inc.h \ - c/enc/hash_longest_match_quickly_inc.h \ - c/enc/hash_rolling_inc.h \ - c/enc/hash_to_binary_tree_inc.h \ - c/enc/histogram.h \ - c/enc/histogram_inc.h \ - c/enc/literal_cost.h \ - c/enc/memory.h \ - c/enc/metablock.h \ - c/enc/metablock_inc.h \ - c/enc/params.h \ - c/enc/prefix.h \ - c/enc/quality.h \ - c/enc/ringbuffer.h \ - c/enc/state.h \ - c/enc/static_dict.h \ - c/enc/static_dict_lut.h \ - c/enc/utf8_util.h \ - c/enc/write_bits.h - -BROTLI_INCLUDE = \ - c/include/brotli/decode.h \ - c/include/brotli/encode.h \ - c/include/brotli/port.h \ - c/include/brotli/shared_dictionary.h \ - c/include/brotli/types.h diff --git a/setup.py b/setup.py index 5d934831c..2cb89c396 100644 --- a/setup.py +++ b/setup.py @@ -23,106 +23,109 @@ CURR_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) +def read_define(path, macro): + """ Return macro value from the given file. """ + with open(path, 'r') as f: + for line in f: + m = re.match(rf'#define\s{macro}\s+(.+)', line) + if m: + return m.group(1) + return '' + + def get_version(): - """ Return BROTLI_VERSION string as defined in 'common/version.h' file. """ - version_file_path = os.path.join(CURR_DIR, 'c', 'common', 'version.h') - version = 0 - with open(version_file_path, 'r') as f: - for line in f: - m = re.match(r'#define\sBROTLI_VERSION\s+0x([0-9a-fA-F]+)', line) - if m: - version = int(m.group(1), 16) - if version == 0: - return '' - # Semantic version is calculated as (MAJOR << 24) | (MINOR << 12) | PATCH. - major = version >> 24 - minor = (version >> 12) & 0xFFF - patch = version & 0xFFF - return '{0}.{1}.{2}'.format(major, minor, patch) + """ Return library version string from 'common/version.h' file. """ + version_file_path = os.path.join(CURR_DIR, 'c', 'common', 'version.h') + major = read_define(version_file_path, 'BROTLI_VERSION_MAJOR') + minor = read_define(version_file_path, 'BROTLI_VERSION_MINOR') + patch = read_define(version_file_path, 'BROTLI_VERSION_PATCH') + if not major or not minor or not patch: + return '' + return f'{major}.{minor}.{patch}' def get_test_suite(): - test_loader = unittest.TestLoader() - test_suite = test_loader.discover('python', pattern='*_test.py') - return test_suite + test_loader = unittest.TestLoader() + test_suite = test_loader.discover('python', pattern='*_test.py') + return test_suite class BuildExt(build_ext): - def get_source_files(self): - filenames = build_ext.get_source_files(self) - for ext in self.extensions: - filenames.extend(ext.depends) - return filenames - - def build_extension(self, ext): - if ext.sources is None or not isinstance(ext.sources, (list, tuple)): - raise errors.DistutilsSetupError( - "in 'ext_modules' option (extension '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % ext.name) - - ext_path = self.get_ext_fullpath(ext.name) - depends = ext.sources + ext.depends - if not (self.force or dep_util.newer_group(depends, ext_path, 'newer')): - log.debug("skipping '%s' extension (up-to-date)", ext.name) - return - else: - log.info("building '%s' extension", ext.name) - - c_sources = [] - for source in ext.sources: - if source.endswith('.c'): - c_sources.append(source) - extra_args = ext.extra_compile_args or [] - - objects = [] - - macros = ext.define_macros[:] - if platform.system() == 'Darwin': - macros.append(('OS_MACOSX', '1')) - elif self.compiler.compiler_type == 'mingw32': - # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot", - # This clashes with GCC's cmath, and causes compilation errors when - # building under MinGW: http://bugs.python.org/issue11566 - macros.append(('_hypot', 'hypot')) - for undef in ext.undef_macros: - macros.append((undef,)) - - objs = self.compiler.compile( - c_sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=ext.include_dirs, - debug=self.debug, - extra_postargs=extra_args, - depends=ext.depends) - objects.extend(objs) - - self._built_objects = objects[:] - if ext.extra_objects: - objects.extend(ext.extra_objects) - extra_args = ext.extra_link_args or [] - # when using GCC on Windows, we statically link libgcc and libstdc++, - # so that we don't need to package extra DLLs - if self.compiler.compiler_type == 'mingw32': - extra_args.extend(['-static-libgcc', '-static-libstdc++']) - - ext_path = self.get_ext_fullpath(ext.name) - # Detect target language, if not provided - language = ext.language or self.compiler.detect_language(c_sources) - - self.compiler.link_shared_object( - objects, - ext_path, - libraries=self.get_libraries(ext), - library_dirs=ext.library_dirs, - runtime_library_dirs=ext.runtime_library_dirs, - extra_postargs=extra_args, - export_symbols=self.get_export_symbols(ext), - debug=self.debug, - build_temp=self.build_temp, - target_lang=language) + def get_source_files(self): + filenames = build_ext.get_source_files(self) + for ext in self.extensions: + filenames.extend(ext.depends) + return filenames + + def build_extension(self, ext): + if ext.sources is None or not isinstance(ext.sources, (list, tuple)): + raise errors.DistutilsSetupError( + "in 'ext_modules' option (extension '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % ext.name) + + ext_path = self.get_ext_fullpath(ext.name) + depends = ext.sources + ext.depends + if not (self.force or dep_util.newer_group(depends, ext_path, 'newer')): + log.debug("skipping '%s' extension (up-to-date)", ext.name) + return + else: + log.info("building '%s' extension", ext.name) + + c_sources = [] + for source in ext.sources: + if source.endswith('.c'): + c_sources.append(source) + extra_args = ext.extra_compile_args or [] + + objects = [] + + macros = ext.define_macros[:] + if platform.system() == 'Darwin': + macros.append(('OS_MACOSX', '1')) + elif self.compiler.compiler_type == 'mingw32': + # On Windows Python 2.7, pyconfig.h defines "hypot" as "_hypot", + # This clashes with GCC's cmath, and causes compilation errors when + # building under MinGW: http://bugs.python.org/issue11566 + macros.append(('_hypot', 'hypot')) + for undef in ext.undef_macros: + macros.append((undef,)) + + objs = self.compiler.compile( + c_sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=ext.include_dirs, + debug=self.debug, + extra_postargs=extra_args, + depends=ext.depends) + objects.extend(objs) + + self._built_objects = objects[:] + if ext.extra_objects: + objects.extend(ext.extra_objects) + extra_args = ext.extra_link_args or [] + # when using GCC on Windows, we statically link libgcc and libstdc++, + # so that we don't need to package extra DLLs + if self.compiler.compiler_type == 'mingw32': + extra_args.extend(['-static-libgcc', '-static-libstdc++']) + + ext_path = self.get_ext_fullpath(ext.name) + # Detect target language, if not provided + language = ext.language or self.compiler.detect_language(c_sources) + + self.compiler.link_shared_object( + objects, + ext_path, + libraries=self.get_libraries(ext), + library_dirs=ext.library_dirs, + runtime_library_dirs=ext.runtime_library_dirs, + extra_postargs=extra_args, + export_symbols=self.get_export_symbols(ext), + debug=self.debug, + build_temp=self.build_temp, + target_lang=language) NAME = 'Brotli'