From 1acc48794364606c9091cae6fa56db75a1325114 Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Wed, 11 Mar 2020 13:05:29 +0200 Subject: Build: Add very limited experimental CMake support. This version matches CMake files in the master branch (commit 265daa873c0d871f5f23f9b56e133a6f20045a0a) except that this omits two source files that aren't in v5.2 and in the beginning of CMakeLists.txt the first paragraph in the comment is slightly different to point out possible issues in building shared liblzma. --- CMakeLists.txt | 659 ++++++++++++++++++++++++++++++++++++++++++++ cmake/tuklib_common.cmake | 49 ++++ cmake/tuklib_cpucores.cmake | 175 ++++++++++++ cmake/tuklib_integer.cmake | 102 +++++++ cmake/tuklib_mbstr.cmake | 20 ++ cmake/tuklib_physmem.cmake | 150 ++++++++++ cmake/tuklib_progname.cmake | 19 ++ 7 files changed, 1174 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 cmake/tuklib_common.cmake create mode 100644 cmake/tuklib_cpucores.cmake create mode 100644 cmake/tuklib_integer.cmake create mode 100644 cmake/tuklib_mbstr.cmake create mode 100644 cmake/tuklib_physmem.cmake create mode 100644 cmake/tuklib_progname.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 00000000..34c6aca0 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,659 @@ +############################################################################# +# +# Very limited CMake support for building some parts of XZ Utils +# +# Building static liblzma with MSVC should work. Building shared liblzma.dll +# with MSVC may or may not work (building liblzma_w32res.rc might be broken). +# Building liblzma on a few other platforms should work too but it +# is somewhat experimental and not as portable as using ./configure. +# +# On some platforms this builds also xz and xzdec, but these are +# highly experimental and meant for testing only: +# - No large file support on those 32-bit platforms that need it +# - No replacement getopt_long(), libc must have it +# - No sandboxing support +# - No translations +# - No xz symlinks are installed +# +# Other missing things: +# - No xzgrep or other scripts or their symlinks +# - No tests (no test failures either!) +# +# NOTE: Even if the code compiles without warnings, the end result may be +# different than via ./configure. Specifically, the list of #defines +# may be different (if so, probably this CMakeLists.txt got them wrong). +# +# This file provides the following installation components (if you only +# need liblzma, install only its components!): +# - liblzma_Runtime +# - liblzma_Development +# - xz (on some platforms only) +# - xzdec (on some platforms only) +# +# To find the target liblzma::liblzma from other packages, use the CONFIG +# option with find_package() to avoid a conflict with the FindLibLZMA module +# with case-insensitive file systems. For example, to require liblzma 5.2.5 +# or a newer compatible version: +# +# find_package(liblzma 5.2.5 REQUIRED CONFIG) +# target_link_libraries(my_application liblzma::liblzma) +# +############################################################################# +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# +############################################################################# + +cmake_minimum_required(VERSION 3.13...3.16 FATAL_ERROR) + +include(CheckSymbolExists) +include(CheckStructHasMember) +include(cmake/tuklib_integer.cmake) +include(cmake/tuklib_cpucores.cmake) +include(cmake/tuklib_physmem.cmake) +include(cmake/tuklib_progname.cmake) +include(cmake/tuklib_mbstr.cmake) + +# Get the package version from version.h into XZ_VERSION variable. +file(READ src/liblzma/api/lzma/version.h XZ_VERSION) +string(REGEX REPLACE +"^.*\n\ +#define LZMA_VERSION_MAJOR ([0-9]+)\n\ +#define LZMA_VERSION_MINOR ([0-9]+)\n\ +#define LZMA_VERSION_PATCH ([0-9]+)\n\ +.*$" + "\\1.\\2.\\3" XZ_VERSION "${XZ_VERSION}") + +# Among other things, this gives us variables xz_VERSION and xz_VERSION_MAJOR. +project(xz VERSION "${XZ_VERSION}" LANGUAGES C) + +# Definitions common to all targets: +add_compile_definitions( + # Package info: + PACKAGE_NAME="XZ Utils" + PACKAGE_BUGREPORT="lasse.collin@tukaani.org" + PACKAGE_URL="https://tukaani.org/xz/" + + # Features: + HAVE_CHECK_CRC32 + HAVE_CHECK_CRC64 + HAVE_CHECK_SHA256 + HAVE_DECODERS + HAVE_DECODER_ARM + HAVE_DECODER_ARMTHUMB + HAVE_DECODER_DELTA + HAVE_DECODER_IA64 + HAVE_DECODER_LZMA1 + HAVE_DECODER_LZMA2 + HAVE_DECODER_POWERPC + HAVE_DECODER_SPARC + HAVE_DECODER_X86 + HAVE_ENCODERS + HAVE_ENCODER_ARM + HAVE_ENCODER_ARMTHUMB + HAVE_ENCODER_DELTA + HAVE_ENCODER_IA64 + HAVE_ENCODER_LZMA1 + HAVE_ENCODER_LZMA2 + HAVE_ENCODER_POWERPC + HAVE_ENCODER_SPARC + HAVE_ENCODER_X86 + HAVE_MF_BT2 + HAVE_MF_BT3 + HAVE_MF_BT4 + HAVE_MF_HC3 + HAVE_MF_HC4 + + # Standard headers and types are available: + HAVE_STDBOOL_H + HAVE__BOOL + HAVE_STDINT_H + HAVE_INTTYPES_H + + # Disable assert() checks when no build type has been specified. Non-empty + # build types like "Release" and "Debug" handle this by default. + $<$:NDEBUG> +) + +# _GNU_SOURCE and such definitions. This specific macro is special since +# it also adds the definitions to CMAKE_REQUIRED_DEFINITIONS. +tuklib_use_system_extensions(ALL) + +# This is needed by liblzma and xz. +tuklib_integer(ALL) + +# Check for clock_gettime(). Do this before checking for threading so +# that we know there if CLOCK_MONOTONIC is available. +if(NOT WIN32 AND NOT DEFINED CACHE{HAVE_CLOCK_GETTIME}) + check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) + if(NOT HAVE_CLOCK_GETTIME) + # With glibc <= 2.17 or Solaris 10 this needs librt. + unset(HAVE_CLOCK_GETTIME CACHE) + + list(INSERT CMAKE_REQUIRED_LIBRARIES 0 rt) + check_symbol_exists(clock_gettime time.h HAVE_CLOCK_GETTIME) + + # If it was found now, add it to all targets and keep it + # in CMAKE_REQUIRED_LIBRARIES for further tests too. + if(HAVE_CLOCK_GETTIME) + link_libraries(rt) + else() + list(REMOVE_AT CMAKE_REQUIRED_LIBRARIES 0) + endif() + endif() + if(HAVE_CLOCK_GETTIME) + # Check if CLOCK_MONOTONIC is available for clock_gettime(). + check_symbol_exists(CLOCK_MONOTONIC time.h HAVE_DECL_CLOCK_MONOTONIC) + + # HAVE_DECL_CLOCK_MONOTONIC should always be defined to 0 or 1 + # when clock_gettime is available. + add_compile_definitions( + HAVE_CLOCK_GETTIME + HAVE_DECL_CLOCK_MONOTONIC=$ + ) + endif() +endif() + +# Threading support: +set(THREADS_PREFER_PTHREAD_FLAG TRUE) +find_package(Threads REQUIRED) +if(CMAKE_USE_WIN32_THREADS_INIT) + add_compile_definitions(MYTHREAD_VISTA) +else() + add_compile_definitions(MYTHREAD_POSIX) + + # Check if pthread_condattr_setclock() exists to use CLOCK_MONOTONIC. + if(HAVE_DECL_CLOCK_MONOTONIC) + list(INSERT CMAKE_REQUIRED_LIBRARIES 0 "${CMAKE_THREAD_LIBS_INIT}") + check_symbol_exists(pthread_condattr_setclock pthread.h + HAVE_PTHREAD_CONDATTR_SETCLOCK) + tuklib_add_definition_if(ALL HAVE_PTHREAD_CONDATTR_SETCLOCK) + endif() +endif() + +# Options for new enough GCC or Clang on any arch or operating system: +if(CMAKE_C_COMPILER_ID MATCHES GNU|Clang) + # configure.ac has a long list but it won't be copied here: + add_compile_options(-Wall -Wextra) +endif() + + +############################################################################# +# liblzma +############################################################################# + +option(BUILD_SHARED_LIBS "Build liblzma as a shared library instead of static") + +add_library(liblzma + src/common/mythread.h + src/common/sysdefs.h + src/common/tuklib_common.h + src/common/tuklib_config.h + src/common/tuklib_cpucores.c + src/common/tuklib_cpucores.h + src/common/tuklib_integer.h + src/common/tuklib_physmem.c + src/common/tuklib_physmem.h + src/liblzma/api/lzma.h + src/liblzma/api/lzma/base.h + src/liblzma/api/lzma/bcj.h + src/liblzma/api/lzma/block.h + src/liblzma/api/lzma/check.h + src/liblzma/api/lzma/container.h + src/liblzma/api/lzma/delta.h + src/liblzma/api/lzma/filter.h + src/liblzma/api/lzma/hardware.h + src/liblzma/api/lzma/index.h + src/liblzma/api/lzma/index_hash.h + src/liblzma/api/lzma/lzma12.h + src/liblzma/api/lzma/stream_flags.h + src/liblzma/api/lzma/version.h + src/liblzma/api/lzma/vli.h + src/liblzma/check/check.c + src/liblzma/check/check.h + src/liblzma/check/crc32_fast.c + src/liblzma/check/crc32_table.c + src/liblzma/check/crc32_table_be.h + src/liblzma/check/crc32_table_le.h + src/liblzma/check/crc64_fast.c + src/liblzma/check/crc64_table.c + src/liblzma/check/crc64_table_be.h + src/liblzma/check/crc64_table_le.h + src/liblzma/check/crc_macros.h + src/liblzma/check/sha256.c + src/liblzma/common/alone_decoder.c + src/liblzma/common/alone_decoder.h + src/liblzma/common/alone_encoder.c + src/liblzma/common/auto_decoder.c + src/liblzma/common/block_buffer_decoder.c + src/liblzma/common/block_buffer_encoder.c + src/liblzma/common/block_buffer_encoder.h + src/liblzma/common/block_decoder.c + src/liblzma/common/block_decoder.h + src/liblzma/common/block_encoder.c + src/liblzma/common/block_encoder.h + src/liblzma/common/block_header_decoder.c + src/liblzma/common/block_header_encoder.c + src/liblzma/common/block_util.c + src/liblzma/common/common.c + src/liblzma/common/common.h + src/liblzma/common/easy_buffer_encoder.c + src/liblzma/common/easy_decoder_memusage.c + src/liblzma/common/easy_encoder.c + src/liblzma/common/easy_encoder_memusage.c + src/liblzma/common/easy_preset.c + src/liblzma/common/easy_preset.h + src/liblzma/common/filter_buffer_decoder.c + src/liblzma/common/filter_buffer_encoder.c + src/liblzma/common/filter_common.c + src/liblzma/common/filter_common.h + src/liblzma/common/filter_decoder.c + src/liblzma/common/filter_decoder.h + src/liblzma/common/filter_encoder.c + src/liblzma/common/filter_encoder.h + src/liblzma/common/filter_flags_decoder.c + src/liblzma/common/filter_flags_encoder.c + src/liblzma/common/hardware_cputhreads.c + src/liblzma/common/hardware_physmem.c + src/liblzma/common/index.c + src/liblzma/common/index.h + src/liblzma/common/index_decoder.c + src/liblzma/common/index_encoder.c + src/liblzma/common/index_encoder.h + src/liblzma/common/index_hash.c + src/liblzma/common/memcmplen.h + src/liblzma/common/outqueue.c + src/liblzma/common/outqueue.h + src/liblzma/common/stream_buffer_decoder.c + src/liblzma/common/stream_buffer_encoder.c + src/liblzma/common/stream_decoder.c + src/liblzma/common/stream_decoder.h + src/liblzma/common/stream_encoder.c + src/liblzma/common/stream_encoder_mt.c + src/liblzma/common/stream_flags_common.c + src/liblzma/common/stream_flags_common.h + src/liblzma/common/stream_flags_decoder.c + src/liblzma/common/stream_flags_encoder.c + src/liblzma/common/vli_decoder.c + src/liblzma/common/vli_encoder.c + src/liblzma/common/vli_size.c + src/liblzma/delta/delta_common.c + src/liblzma/delta/delta_common.h + src/liblzma/delta/delta_decoder.c + src/liblzma/delta/delta_decoder.h + src/liblzma/delta/delta_encoder.c + src/liblzma/delta/delta_encoder.h + src/liblzma/delta/delta_private.h + src/liblzma/lz/lz_decoder.c + src/liblzma/lz/lz_decoder.h + src/liblzma/lz/lz_encoder.c + src/liblzma/lz/lz_encoder.h + src/liblzma/lz/lz_encoder_hash.h + src/liblzma/lz/lz_encoder_hash_table.h + src/liblzma/lz/lz_encoder_mf.c + src/liblzma/lzma/fastpos.h + src/liblzma/lzma/fastpos_table.c + src/liblzma/lzma/lzma2_decoder.c + src/liblzma/lzma/lzma2_decoder.h + src/liblzma/lzma/lzma2_encoder.c + src/liblzma/lzma/lzma2_encoder.h + src/liblzma/lzma/lzma_common.h + src/liblzma/lzma/lzma_decoder.c + src/liblzma/lzma/lzma_decoder.h + src/liblzma/lzma/lzma_encoder.c + src/liblzma/lzma/lzma_encoder.h + src/liblzma/lzma/lzma_encoder_optimum_fast.c + src/liblzma/lzma/lzma_encoder_optimum_normal.c + src/liblzma/lzma/lzma_encoder_presets.c + src/liblzma/lzma/lzma_encoder_private.h + src/liblzma/rangecoder/price.h + src/liblzma/rangecoder/price_table.c + src/liblzma/rangecoder/range_common.h + src/liblzma/rangecoder/range_decoder.h + src/liblzma/rangecoder/range_encoder.h + src/liblzma/simple/arm.c + src/liblzma/simple/armthumb.c + src/liblzma/simple/ia64.c + src/liblzma/simple/powerpc.c + src/liblzma/simple/simple_coder.c + src/liblzma/simple/simple_coder.h + src/liblzma/simple/simple_decoder.c + src/liblzma/simple/simple_decoder.h + src/liblzma/simple/simple_encoder.c + src/liblzma/simple/simple_encoder.h + src/liblzma/simple/simple_private.h + src/liblzma/simple/sparc.c + src/liblzma/simple/x86.c +) + +target_include_directories(liblzma PRIVATE + src/liblzma/api + src/liblzma/common + src/liblzma/check + src/liblzma/lz + src/liblzma/rangecoder + src/liblzma/lzma + src/liblzma/delta + src/liblzma/simple + src/common +) + +target_link_libraries(liblzma Threads::Threads) + +# Put the tuklib functions under the lzma_ namespace. +target_compile_definitions(liblzma PRIVATE TUKLIB_SYMBOL_PREFIX=lzma_) +tuklib_cpucores(liblzma) +tuklib_physmem(liblzma) + +# While liblzma can be built without tuklib_cpucores or tuklib_physmem +# modules, the liblzma API functions lzma_cputhreads() and lzma_physmem() +# will then be useless (which isn't too bad but still unfortunate). Since +# I expect the CMake-based builds to be only used on systems that are +# supported by these tuklib modules, problems with these tuklib modules +# are considered a hard error for now. This hopefully helps to catch bugs +# in the CMake versions of the tuklib checks. +if(NOT TUKLIB_CPUCORES_FOUND OR NOT TUKLIB_PHYSMEM_FOUND) + # Use SEND_ERROR instead of FATAL_ERROR. If someone reports a bug, + # seeing the results of the remaining checks can be useful too. + message(SEND_ERROR + "tuklib_cpucores() or tuklib_physmem() failed. " + "Unless you really are building for a system where these " + "modules are not supported (unlikely), this is a bug in the " + "included cmake/tuklib_*.cmake files that should be fixed. " + "To build anyway, edit this CMakeLists.txt to ignore this error.") +endif() + +# immintrin.h: +include(CheckIncludeFile) +check_include_file(immintrin.h HAVE_IMMINTRIN_H) +if(HAVE_IMMINTRIN_H) + target_compile_definitions(liblzma PRIVATE HAVE_IMMINTRIN_H) + + # SSE2 intrinsics: + include(CheckCSourceCompiles) + check_c_source_compiles(" + #include + int main(void) + { + __m128i x = { 0 }; + _mm_movemask_epi8(x); + return 0; + } + " + HAVE__MM_MOVEMASK_EPI8) + tuklib_add_definition_if(liblzma HAVE__MM_MOVEMASK_EPI8) +endif() + +# Support -fvisiblity=hidden when building shared liblzma. +# These lines do nothing on Windows (even under Cygwin). +# HAVE_VISIBILITY should always be defined to 0 or 1. +if(BUILD_SHARED_LIBS) + set_target_properties(liblzma PROPERTIES C_VISIBILITY_PRESET hidden) + target_compile_definitions(liblzma PRIVATE HAVE_VISIBILITY=1) +else() + target_compile_definitions(liblzma PRIVATE HAVE_VISIBILITY=0) +endif() + +if(WIN32) + if(BUILD_SHARED_LIBS) + # Add the Windows resource file for liblzma.dll. + target_sources(liblzma PRIVATE src/liblzma/liblzma_w32res.rc) + + # Export the public API symbols with __declspec(dllexport). + target_compile_definitions(liblzma PRIVATE DLL_EXPORT) + else() + # Disable __declspec(dllimport) when linking against static liblzma. + target_compile_definitions(liblzma INTERFACE LZMA_API_STATIC) + endif() +elseif(CMAKE_SYSTEM_NAME MATCHES "^Linux$|^FreeBSD$") + # Symbol versioning for shared liblzma. This doesn't affect static builds. + target_link_options(liblzma PRIVATE + "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/liblzma/liblzma.map" + ) + set_target_properties(liblzma PROPERTIES + LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/liblzma/liblzma.map" + LINK_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/common/common_w32res.rc" + ) +endif() + +set_target_properties(liblzma PROPERTIES + # At least for now the package versioning matches the rules used for + # shared library versioning (excluding development releases) so it is + # fine to use the package version here. + SOVERSION "${xz_VERSION_MAJOR}" + VERSION "${xz_VERSION}" + + # It's liblzma.so or liblzma.dll, not libliblzma.so or lzma.dll. + # Avoid the name lzma.dll because it would conflict with LZMA SDK. + PREFIX "" +) + +# Create liblzmaConfigVersion.cmake. +# +# FIXME: SameMajorVersion is correct for stable releases but it is wrong +# for development releases where each release may have incompatible changes. +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfigVersion.cmake" + VERSION "${liblzma_VERSION}" + COMPATIBILITY SameMajorVersion) + +# Create liblzmaConfig.cmake. +file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfig.cmake" +"include(CMakeFindDependencyMacro) +set(THREADS_PREFER_PTHREAD_FLAG TRUE) +find_dependency(Threads) +include(\"\${CMAKE_CURRENT_LIST_DIR}/liblzmaTargets.cmake\") +") + +# Set CMAKE_INSTALL_LIBDIR and friends. +include(GNUInstallDirs) + +# Install the library binary. The INCLUDES specifies the include path that +# is exported for other projects to use but it doesn't install any files. +install(TARGETS liblzma EXPORT liblzmaTargets + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT liblzma_Runtime + LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT liblzma_Runtime + NAMELINK_COMPONENT liblzma_Development + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" + COMPONENT liblzma_Development + INCLUDES DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") + +# Install the liblzma API headers. These use a subdirectory so +# this has to be done as a separate step. +install(DIRECTORY src/liblzma/api/ + COMPONENT liblzma_Development + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.h") + +# Install the CMake files that other packages can use to find liblzma. +set(liblzma_INSTALL_CMAKEDIR + "${CMAKE_INSTALL_LIBDIR}/cmake/liblzma" + CACHE STRING "Path to liblzma's .cmake files") + +install(EXPORT liblzmaTargets + NAMESPACE liblzma:: + FILE liblzmaTargets.cmake + DESTINATION "${liblzma_INSTALL_CMAKEDIR}" + COMPONENT liblzma_Development) + +install(FILES "${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfigVersion.cmake" + DESTINATION "${liblzma_INSTALL_CMAKEDIR}" + COMPONENT liblzma_Development) + + +############################################################################# +# getopt_long +############################################################################# + +# The command line tools needs this. +check_symbol_exists(getopt_long getopt.h HAVE_GETOPT_LONG) + + +############################################################################# +# xzdec +############################################################################# + +if(HAVE_GETOPT_LONG) + add_executable(xzdec + src/common/sysdefs.h + src/common/tuklib_common.h + src/common/tuklib_config.h + src/common/tuklib_exit.c + src/common/tuklib_exit.h + src/common/tuklib_gettext.h + src/common/tuklib_progname.c + src/common/tuklib_progname.h + src/xzdec/xzdec.c + ) + + target_include_directories(xzdec PRIVATE + src/common + src/liblzma/api + ) + + target_link_libraries(xzdec PRIVATE liblzma) + + tuklib_progname(xzdec) + + install(TARGETS xzdec + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT xzdec) + + if(UNIX) + install(FILES src/xzdec/xzdec.1 + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" + COMPONENT xzdec) + endif() +endif() + + +############################################################################# +# xz +############################################################################# + +if(NOT MSVC AND HAVE_GETOPT_LONG) + add_executable(xz + src/common/mythread.h + src/common/sysdefs.h + src/common/tuklib_common.h + src/common/tuklib_config.h + src/common/tuklib_exit.c + src/common/tuklib_exit.h + src/common/tuklib_gettext.h + src/common/tuklib_integer.h + src/common/tuklib_mbstr.h + src/common/tuklib_mbstr_fw.c + src/common/tuklib_mbstr_width.c + src/common/tuklib_open_stdxxx.c + src/common/tuklib_open_stdxxx.h + src/common/tuklib_progname.c + src/common/tuklib_progname.h + src/xz/args.c + src/xz/args.h + src/xz/coder.c + src/xz/coder.h + src/xz/file_io.c + src/xz/file_io.h + src/xz/hardware.c + src/xz/hardware.h + src/xz/list.c + src/xz/list.h + src/xz/main.c + src/xz/main.h + src/xz/message.c + src/xz/message.h + src/xz/mytime.c + src/xz/mytime.h + src/xz/options.c + src/xz/options.h + src/xz/private.h + src/xz/signals.c + src/xz/signals.h + src/xz/suffix.c + src/xz/suffix.h + src/xz/util.c + src/xz/util.h + ) + + target_include_directories(xz PRIVATE + src/common + src/liblzma/api + ) + + target_link_libraries(xz PRIVATE liblzma) + + target_compile_definitions(xz PRIVATE ASSUME_RAM=128) + + tuklib_progname(xz) + tuklib_mbstr(xz) + + check_symbol_exists(optreset getopt.h HAVE_OPTRESET) + tuklib_add_definition_if(xz HAVE_OPTRESET) + + check_symbol_exists(posix_fadvise fcntl.h HAVE_POSIX_FADVISE) + tuklib_add_definition_if(xz HAVE_POSIX_FADVISE) + + # How to get file time: + check_struct_has_member("struct stat" st_atim.tv_nsec + "sys/types.h;sys/stat.h" + HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) + if(HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) + tuklib_add_definitions(xz HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) + else() + check_struct_has_member("struct stat" st_atimespec.tv_nsec + "sys/types.h;sys/stat.h" + HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) + if(HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) + tuklib_add_definitions(xz HAVE_STRUCT_STAT_ST_ATIMESPEC_TV_NSEC) + else() + check_struct_has_member("struct stat" st_atimensec + "sys/types.h;sys/stat.h" + HAVE_STRUCT_STAT_ST_ATIMENSEC) + tuklib_add_definition_if(xz HAVE_STRUCT_STAT_ST_ATIMENSEC) + endif() + endif() + + # How to set file time: + check_symbol_exists(futimens "sys/types.h;sys/stat.h" HAVE_FUTIMENS) + if(HAVE_FUTIMENS) + tuklib_add_definitions(xz HAVE_FUTIMENS) + else() + check_symbol_exists(futimes "sys/time.h" HAVE_FUTIMES) + if(HAVE_FUTIMES) + tuklib_add_definitions(xz HAVE_FUTIMES) + else() + check_symbol_exists(futimesat "sys/time.h" HAVE_FUTIMESAT) + if(HAVE_FUTIMESAT) + tuklib_add_definitions(xz HAVE_FUTIMESAT) + else() + check_symbol_exists(utimes "sys/time.h" HAVE_UTIMES) + if(HAVE_UTIMES) + tuklib_add_definitions(xz HAVE_UTIMES) + else() + check_symbol_exists(_futime "sys/utime.h" HAVE__FUTIME) + if(HAVE__FUTIME) + tuklib_add_definitions(xz HAVE__FUTIME) + else() + check_symbol_exists(utime "utime.h" HAVE_UTIME) + tuklib_add_definition_if(xz HAVE_UTIME) + endif() + endif() + endif() + endif() + endif() + + install(TARGETS xz + RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" + COMPONENT xz) + + install(FILES src/xz/xz.1 + DESTINATION "${CMAKE_INSTALL_MANDIR}/man1" + COMPONENT xz) +endif() diff --git a/cmake/tuklib_common.cmake b/cmake/tuklib_common.cmake new file mode 100644 index 00000000..088a3cb1 --- /dev/null +++ b/cmake/tuklib_common.cmake @@ -0,0 +1,49 @@ +# +# tuklib_common.cmake - common functions and macros for tuklib_*.cmake files +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +function(tuklib_add_definitions TARGET_OR_ALL DEFINITIONS) + # DEFINITIONS may be an empty string/list but it's fine here. There is + # no need to quote ${DEFINITIONS} as empty arguments are fine here. + if(TARGET_OR_ALL STREQUAL "ALL") + add_compile_definitions(${DEFINITIONS}) + else() + target_compile_definitions("${TARGET_OR_ALL}" PRIVATE ${DEFINITIONS}) + endif() +endfunction() + +function(tuklib_add_definition_if TARGET_OR_ALL VAR) + if(${VAR}) + tuklib_add_definitions("${TARGET_OR_ALL}" "${VAR}") + endif() +endfunction() + +# This is an over-simplified version of AC_USE_SYSTEM_EXTENSIONS in Autoconf +# or gl_USE_SYSTEM_EXTENSIONS in gnulib. +macro(tuklib_use_system_extensions TARGET_OR_ALL) + if(NOT WIN32) + # FIXME? The Solaris-specific __EXTENSIONS__ should be conditional + # even on Solaris. See gnulib: git log m4/extensions.m4. + # FIXME? gnulib and autoconf.git has lots of new stuff. + tuklib_add_definitions("${TARGET_OR_ALL}" + _GNU_SOURCE + __EXTENSIONS__ + _POSIX_PTHREAD_SEMANTICS + _TANDEM_SOURCE + _ALL_SOURCE + ) + + list(APPEND CMAKE_REQUIRED_DEFINITIONS + -D_GNU_SOURCE + -D__EXTENSIONS__ + -D_POSIX_PTHREAD_SEMANTICS + -D_TANDEM_SOURCE + -D_ALL_SOURCE + ) + endif() +endmacro() diff --git a/cmake/tuklib_cpucores.cmake b/cmake/tuklib_cpucores.cmake new file mode 100644 index 00000000..5844e4b2 --- /dev/null +++ b/cmake/tuklib_cpucores.cmake @@ -0,0 +1,175 @@ +# +# tuklib_cpucores.cmake - see tuklib_cpucores.m4 for description and comments +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(CheckCSourceCompiles) +include(CheckIncludeFile) + +function(tuklib_cpucores_internal_check) + if(WIN32 OR CYGWIN) + # Nothing to do, the tuklib_cpucores.c handles it. + set(TUKLIB_CPUCORES_DEFINITIONS "" CACHE INTERNAL "") + return() + endif() + + # glibc-based systems (GNU/Linux and GNU/kFreeBSD) have + # sched_getaffinity(). The CPU_COUNT() macro was added in glibc 2.9. + # glibc 2.9 is old enough that if someone uses the code on older glibc, + # the fallback to sysconf() should be good enough. + # + # NOTE: This required that _GNU_SOURCE is defined. We assume that whatever + # feature test macros the caller wants to use are already set in + # CMAKE_REQUIRED_DEFINES and in the target defines. + check_c_source_compiles(" + #include + int main(void) + { + cpu_set_t cpu_mask; + sched_getaffinity(0, sizeof(cpu_mask), &cpu_mask); + return CPU_COUNT(&cpu_mask); + } + " + TUKLIB_CPUCORES_SCHED_GETAFFINITY) + if(TUKLIB_CPUCORES_SCHED_GETAFFINITY) + set(TUKLIB_CPUCORES_DEFINITIONS + "TUKLIB_CPUCORES_SCHED_GETAFFINITY" + CACHE INTERNAL "") + return() + endif() + + # FreeBSD has both cpuset and sysctl. Look for cpuset first because + # it's a better approach. + # + # This test would match on GNU/kFreeBSD too but it would require + # -lfreebsd-glue when linking and thus in the current form this would + # fail on GNU/kFreeBSD. The above test for sched_getaffinity() matches + # on GNU/kFreeBSD so the test below should never run on that OS. + check_c_source_compiles(" + #include + #include + int main(void) + { + cpuset_t set; + cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, + sizeof(set), &set); + return 0; + } + " + TUKLIB_CPUCORES_CPUSET) + if(TUKLIB_CPUCORES_CPUSET) + set(TUKLIB_CPUCORES_DEFINITIONS "HAVE_PARAM_H;TUKLIB_CPUCORES_CPUSET" + CACHE INTERNAL "") + return() + endif() + + # On OS/2, both sysconf() and sysctl() pass the tests in this file, + # but only sysctl() works. On QNX it's the opposite: only sysconf() works + # (although it assumes that _POSIX_SOURCE, _XOPEN_SOURCE, and + # _POSIX_C_SOURCE are undefined or alternatively _QNX_SOURCE is defined). + # + # We test sysctl() first and intentionally break the sysctl() test on QNX + # so that sysctl() is never used on QNX. + check_include_file(sys/param.h HAVE_SYS_PARAM_H) + if(HAVE_SYS_PARAM_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_PARAM_H) + endif() + check_c_source_compiles(" + #ifdef __QNX__ + compile error + #endif + #ifdef HAVE_SYS_PARAM_H + # include + #endif + #include + int main(void) + { + int name[2] = { CTL_HW, HW_NCPU }; + int cpus; + size_t cpus_size = sizeof(cpus); + sysctl(name, 2, &cpus, &cpus_size, NULL, 0); + return 0; + } + " + TUKLIB_CPUCORES_SYSCTL) + if(TUKLIB_CPUCORES_SYSCTL) + if(HAVE_SYS_PARAM_H) + set(TUKLIB_CPUCORES_DEFINITIONS + "HAVE_PARAM_H;TUKLIB_CPUCORES_SYSCTL" + CACHE INTERNAL "") + else() + set(TUKLIB_CPUCORES_DEFINITIONS + "TUKLIB_CPUCORES_SYSCTL" + CACHE INTERNAL "") + endif() + return() + endif() + + # Many platforms support sysconf(). + check_c_source_compiles(" + #include + int main(void) + { + long i; + #ifdef _SC_NPROCESSORS_ONLN + /* Many systems using sysconf() */ + i = sysconf(_SC_NPROCESSORS_ONLN); + #else + /* IRIX */ + i = sysconf(_SC_NPROC_ONLN); + #endif + return 0; + } + " + TUKLIB_CPUCORES_SYSCONF) + if(TUKLIB_CPUCORES_SYSCONF) + set(TUKLIB_CPUCORES_DEFINITIONS "TUKLIB_CPUCORES_SYSCONF" + CACHE INTERNAL "") + return() + endif() + + # HP-UX + check_c_source_compiles(" + #include + #include + int main(void) + { + struct pst_dynamic pst; + pstat_getdynamic(&pst, sizeof(pst), 1, 0); + (void)pst.psd_proc_cnt; + return 0; + } + " + TUKLIB_CPUCORES_PSTAT_GETDYNAMIC) + if(TUKLIB_CPUCORES_PSTAT_GETDYNAMIC) + set(TUKLIB_CPUCORES_DEFINITIONS "TUKLIB_CPUCORES_PSTAT_GETDYNAMIC" + CACHE INTERNAL "") + return() + endif() +endfunction() + +function(tuklib_cpucores TARGET_OR_ALL) + if(NOT DEFINED CACHE{TUKLIB_CPUCORES_FOUND}) + message(STATUS + "Checking how to detect the number of available CPU cores") + tuklib_cpucores_internal_check() + + if(DEFINED CACHE{TUKLIB_CPUCORES_DEFINITIONS}) + set(TUKLIB_CPUCORES_FOUND 1 CACHE INTERNAL "") + else() + set(TUKLIB_CPUCORES_FOUND 0 CACHE INTERNAL "") + message(WARNING + "No method to detect the number of CPU cores was found") + endif() + endif() + + if(TUKLIB_CPUCORES_FOUND) + tuklib_add_definitions("${TARGET_OR_ALL}" + "${TUKLIB_CPUCORES_DEFINITIONS}") + endif() +endfunction() diff --git a/cmake/tuklib_integer.cmake b/cmake/tuklib_integer.cmake new file mode 100644 index 00000000..d7e2e28c --- /dev/null +++ b/cmake/tuklib_integer.cmake @@ -0,0 +1,102 @@ +# +# tuklib_integer.cmake - see tuklib_integer.m4 for description and comments +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(TestBigEndian) +include(CheckCSourceCompiles) +include(CheckIncludeFile) +include(CheckSymbolExists) + +function(tuklib_integer TARGET_OR_ALL) + # Check for endianness. Unlike the Autoconf's AC_C_BIGENDIAN, this doesn't + # support Apple universal binaries. The CMake module will leave the + # variable unset so we can catch that situation here instead of continuing + # as if we were little endian. + test_big_endian(WORDS_BIGENDIAN) + if(NOT DEFINED WORDS_BIGENDIAN) + message(FATAL_ERROR "Cannot determine endianness") + endif() + tuklib_add_definition_if("${TARGET_OR_ALL}" WORDS_BIGENDIAN) + + # Look for a byteswapping method. + check_c_source_compiles(" + int main(void) + { + __builtin_bswap16(1); + __builtin_bswap32(1); + __builtin_bswap64(1); + return 0; + } + " + HAVE___BUILTIN_BSWAPXX) + if(HAVE___BUILTIN_BSWAPXX) + tuklib_add_definitions("${TARGET_OR_ALL}" HAVE___BUILTIN_BSWAPXX) + else() + check_include_file(byteswap.h HAVE_BYTESWAP_H) + if(HAVE_BYTESWAP_H) + tuklib_add_definitions("${TARGET_OR_ALL}" HAVE_BYTESWAP_H) + check_symbol_exists(bswap_16 byteswap.h HAVE_BSWAP_16) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE_BSWAP_16) + check_symbol_exists(bswap_32 byteswap.h HAVE_BSWAP_32) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE_BSWAP_32) + check_symbol_exists(bswap_64 byteswap.h HAVE_BSWAP_64) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE_BSWAP_64) + else() + check_include_file(sys/endian.h HAVE_SYS_ENDIAN_H) + if(HAVE_SYS_ENDIAN_H) + tuklib_add_definitions("${TARGET_OR_ALL}" HAVE_SYS_ENDIAN_H) + else() + check_include_file(sys/byteorder.h HAVE_SYS_BYTEORDER_H) + tuklib_add_definition_if("${TARGET_OR_ALL}" + HAVE_SYS_BYTEORDER_H) + endif() + endif() + endif() + + # 16-bit and 32-bit unaligned access is fast on x86(-64), + # big endian PowerPC, and usually on 32/64-bit ARM too. + # There are others too and ARM could be a false match. + # + # Guess the default value for the option. + # CMake's ability to give info about the target arch seems bad. + # The the same arch can have different name depending on the OS. + # + # FIXME: The regex is based on guessing, not on factual information! + # + # NOTE: Compared to the Autoconf test, this lacks the GCC/Clang test + # on ARM and always assumes that unaligned is fast on ARM. + set(FAST_UNALIGNED_GUESS OFF) + if(CMAKE_SYSTEM_PROCESSOR MATCHES + "[Xx3456]86|^[Xx]64|^[Aa][Mm][Dd]64|^[Aa][Rr][Mm]|^aarch|^powerpc|^ppc") + if(NOT WORDS_BIGENDIAN OR + NOT CMAKE_SYSTEM_PROCESSOR MATCHES "^powerpc|^ppc") + set(FAST_UNALIGNED_GUESS ON) + endif() + endif() + option(TUKLIB_FAST_UNALIGNED_ACCESS + "Enable if the system supports *fast* unaligned memory access \ +with 16-bit and 32-bit integers." + "${FAST_UNALIGNED_GUESS}") + tuklib_add_definition_if("${TARGET_OR_ALL}" TUKLIB_FAST_UNALIGNED_ACCESS) + + # Unsafe type punning: + option(TUKLIB_USE_UNSAFE_TYPE_PUNNING + "This introduces strict aliasing violations and \ +may result in broken code. However, this might improve performance \ +in some cases, especially with old compilers \ +(e.g. GCC 3 and early 4.x on x86, GCC < 6 on ARMv6 and ARMv7)." + OFF) + tuklib_add_definition_if("${TARGET_OR_ALL}" TUKLIB_USE_UNSAFE_TYPE_PUNNING) + + # Check for GCC/Clang __builtin_assume_aligned(). + check_c_source_compiles( + "int main(void) { __builtin_assume_aligned(\"\", 1); return 0; }" + HAVE___BUILTIN_ASSUME_ALIGNED) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE___BUILTIN_ASSUME_ALIGNED) +endfunction() diff --git a/cmake/tuklib_mbstr.cmake b/cmake/tuklib_mbstr.cmake new file mode 100644 index 00000000..e073be6a --- /dev/null +++ b/cmake/tuklib_mbstr.cmake @@ -0,0 +1,20 @@ +# +# tuklib_mbstr.cmake - see tuklib_mbstr.m4 for description and comments +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(CheckSymbolExists) + +function(tuklib_mbstr TARGET_OR_ALL) + check_symbol_exists(mbrtowc wchar.h HAVE_MBRTOWC) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE_MBRTOWC) + + # NOTE: wcwidth() requires _GNU_SOURCE or _XOPEN_SOURCE on GNU/Linux. + check_symbol_exists(wcwidth wchar.h HAVE_WCWIDTH) + tuklib_add_definition_if("${TARGET_OR_ALL}" HAVE_WCWIDTH) +endfunction() diff --git a/cmake/tuklib_physmem.cmake b/cmake/tuklib_physmem.cmake new file mode 100644 index 00000000..ea5bcc46 --- /dev/null +++ b/cmake/tuklib_physmem.cmake @@ -0,0 +1,150 @@ +# +# tuklib_physmem.cmake - see tuklib_physmem.m4 for description and comments +# +# NOTE: Compared tuklib_physmem.m4, this lacks support for Tru64, IRIX, and +# Linux sysinfo() (usually sysconf() is used on GNU/Linux). +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(CheckCSourceCompiles) +include(CheckIncludeFile) + +function(tuklib_physmem_internal_check) + # Shortcut on Windows: + if(WIN32 OR CYGWIN) + # Nothing to do, the tuklib_physmem.c handles it. + set(TUKLIB_PHYSMEM_DEFINITIONS "" CACHE INTERNAL "") + return() + endif() + + # Full check for special cases: + check_c_source_compiles(" + #if defined(_WIN32) || defined(__CYGWIN__) || defined(__OS2__) \ + || defined(__DJGPP__) || defined(__VMS) \ + || defined(AMIGA) || defined(__AROS__) || defined(__QNX__) + int main(void) { return 0; } + #else + compile error + #endif + " + TUKLIB_PHYSMEM_SPECIAL) + if(TUKLIB_PHYSMEM_SPECIAL) + # Nothing to do, the tuklib_physmem.c handles it. + set(TUKLIB_PHYSMEM_DEFINITIONS "" CACHE INTERNAL "") + return() + endif() + + # Look for AIX-specific solution before sysconf(), because the test + # for sysconf() will pass on AIX but won't actually work + # (sysconf(_SC_PHYS_PAGES) compiles but always returns -1 on AIX). + check_c_source_compiles(" + #include + int main(void) + { + (void)_system_configuration.physmem; + return 0; + } + " + TUKLIB_PHYSMEM_AIX) + if(TUKLIB_PHYSMEM_AIX) + set(TUKLIB_PHYSMEM_DEFINITIONS "TUKLIB_PHYSMEM_AIX" CACHE INTERNAL "") + return() + endif() + + # sysconf() + check_c_source_compiles(" + #include + int main(void) + { + long i; + i = sysconf(_SC_PAGESIZE); + i = sysconf(_SC_PHYS_PAGES); + return 0; + } + " + TUKLIB_PHYSMEM_SYSCONF) + if(TUKLIB_PHYSMEM_SYSCONF) + set(TUKLIB_PHYSMEM_DEFINITIONS "TUKLIB_PHYSMEM_SYSCONF" + CACHE INTERNAL "") + return() + endif() + + # sysctl() + check_include_file(sys/param.h HAVE_SYS_PARAM_H) + if(HAVE_SYS_PARAM_H) + list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_PARAM_H) + endif() + + check_c_source_compiles(" + #ifdef HAVE_SYS_PARAM_H + # include + #endif + #include + int main(void) + { + int name[2] = { CTL_HW, HW_PHYSMEM }; + unsigned long mem; + size_t mem_ptr_size = sizeof(mem); + sysctl(name, 2, &mem, &mem_ptr_size, NULL, 0); + return 0; + } + " + TUKLIB_PHYSMEM_SYSCTL) + if(TUKLIB_PHYSMEM_SYSCTL) + if(HAVE_SYS_PARAM_H) + set(TUKLIB_PHYSMEM_DEFINITIONS + "HAVE_PARAM_H;TUKLIB_PHYSMEM_SYSCTL" + CACHE INTERNAL "") + else() + set(TUKLIB_PHYSMEM_DEFINITIONS + "TUKLIB_PHYSMEM_SYSCTL" + CACHE INTERNAL "") + endif() + return() + endif() + + # HP-UX + check_c_source_compiles(" + #include + #include + int main(void) + { + struct pst_static pst; + pstat_getstatic(&pst, sizeof(pst), 1, 0); + (void)pst.physical_memory; + (void)pst.page_size; + return 0; + } + " + TUKLIB_PHYSMEM_PSTAT_GETSTATIC) + if(TUKLIB_PHYSMEM_PSTAT_GETSTATIC) + set(TUKLIB_PHYSMEM_DEFINITIONS "TUKLIB_PHYSMEM_PSTAT_GETSTATIC" + CACHE INTERNAL "") + return() + endif() +endfunction() + +function(tuklib_physmem TARGET_OR_ALL) + if(NOT DEFINED CACHE{TUKLIB_PHYSMEM_FOUND}) + message(STATUS "Checking how to detect the amount of physical memory") + tuklib_physmem_internal_check() + + if(DEFINED CACHE{TUKLIB_PHYSMEM_DEFINITIONS}) + set(TUKLIB_PHYSMEM_FOUND 1 CACHE INTERNAL "") + else() + set(TUKLIB_PHYSMEM_FOUND 0 CACHE INTERNAL "") + message(WARNING + "No method to detect the amount of physical memory was found") + endif() + endif() + + if(TUKLIB_PHYSMEM_FOUND) + tuklib_add_definitions("${TARGET_OR_ALL}" + "${TUKLIB_PHYSMEM_DEFINITIONS}") + endif() +endfunction() diff --git a/cmake/tuklib_progname.cmake b/cmake/tuklib_progname.cmake new file mode 100644 index 00000000..0fa1d3d7 --- /dev/null +++ b/cmake/tuklib_progname.cmake @@ -0,0 +1,19 @@ +# +# tuklib_progname.cmake - see tuklib_progname.m4 for description and comments +# +# Author: Lasse Collin +# +# This file has been put into the public domain. +# You can do whatever you want with this file. +# + +include("${CMAKE_CURRENT_LIST_DIR}/tuklib_common.cmake") +include(CheckSymbolExists) + +function(tuklib_progname TARGET_OR_ALL) + # NOTE: This glibc extension requires _GNU_SOURCE. + check_symbol_exists(program_invocation_name errno.h + HAVE_DECL_PROGRAM_INVOCATION_NAME) + tuklib_add_definition_if("${TARGET_OR_ALL}" + HAVE_DECL_PROGRAM_INVOCATION_NAME) +endfunction() -- cgit v1.2.3