On 2020-02-17 Mario Emmenlauer wrote:
> I think the conan community also enjoyes cmake because it integrates
> very well. So, since this CMakeLists.txt is quite well developed its
> not unlikely that more people looking mostly for liblzma will try to
> switch to cmake.

OK. I hadn't thought much about other use cases than package managers
included in the operating systems. With them one wants to build the
whole package anyway. Windows was a special case on top of this and
largely done as a portability exercise as LZMA SDK has always had great
Windows support. So these "only liblzma" cases are still a bit new
thought to me.

> Are you still considering this mostly for MSVC? If so, it may be
> helpful to add an explicit check, to avoid people trying to track
> down problems of missing 'config.h'.

Yes.

> But if more platforms could qualify it would certainly be
> appreciated! Maybe some of the major platforms like Linux and macOS?

Perhaps some day but let's get MSVC support done first (and a little
GNU/Linux too to let me test the basics).

I made a few changes to CMakeLists.txt:

  - Added the header files to the add_library call.

  - In target_compile_definitions, NDEBUG was replaced with
    $<$<CONFIG:>:NDEBUG> to define NDEBUG only when no build type
    has been specified. When e.g. "Release" is used, it already takes
    care of defining NDEBUG.

  - Use CMAKE_CURRENT_SOURCE_DIR instead of CMAKE_CURRENT_LIST_DIR when
    appropriate. Only liblzmaConfig.cmake needs CMAKE_CURRENT_LIST_DIR.

  - Added a commented-out alternative for -Wl,--version-script usage
    that is compatible with CMake 3.1.

I didn't add a check for "NOT WIN32" yet.

> Anything I can do to help?

Yes, I have a few questions about the attached current CMakeLists.txt
when used with xz.git.

Does it work with MSVC targeting x86, x86-64, and ARM64?

Does the liblzma_w32res.rc get included in the build and does it build
correctly when creating liblzma.dll? You should see the information in
the file properties/details in Windows Explorer.

Optimizations in src/liblzma/common/memcmplen.h:

  - If SSE2 support is enabled in MSVC settings and targeting 32-bit
    x86, is the SSE2 version used in memcmplen.h? That is, are the
    hairy #ifdefs correct for MSVC and does the HAVE__MM_MOVEMASK_EPI8
    detection in CMakeLists.txt work with MSVC?

  - On x86-64 the 64-bit non-SSE2 version should be used instead.

  - The 64-bit version could be the best version for ARM64 too
    but no one has tested it (it affects compression speed, not
    decompression). Or perhaps some ARM64-specific code would be
    even better. If no one can test this now, it's OK, but liblzma
    should at least be buildable for ARM64. That is, CMake must *not*
    define HAVE__MM_MOVEMASK_EPI8 for ARM64 builds.

Is the enable-uwp-builds.patch needed because using GetModuleHandle()
doesn't work for UWP applications? Like I said, I'll fix it but first I
want to know what is being fixed. :-)

CMakeLists.txt generates a few .cmake files and installs them to
${CMAKE_INSTALL_LIBDIR}/cmake/liblzma (I omitted the optional version
number). The path matches the CMake docs. I see quite a bit of stuff in
/usr/lib/cmake on my system. However, the path doesn't match what was
in the vcpkg files you linked. The CMakeLists.txt there uses
share/liblzma instead.

  - Should I care about this? Shouldn't vcpkg fix it if they use
    a non-standard path?

  - Should CMakeLists.txt have a separate variable for the install
    directory of the .cmake files so it can be overriden by the
    callers? If yes, what variable name?

Is it correct to use this?

    set(THREADS_PREFER_PTHREAD_FLAG TRUE)
    find_package(Threads REQUIRED)

The first version used include(FindThreads) instead of find_package but
I changed it for the second version.

Are the generated .cmake files correctly done?

  - I suppose liblzmaConfigVersion.cmake is OK. I know that
    "COMPATIBILITY SameMajorVersion" is correct for liblzma.

  - liblzmaConfig.cmake checks for the dependency on Threads::Threads.
    Is it needed? Is it correctly done?

  - What is a good namespace for liblzma? Doesn't liblzma::liblzma
    conflict with FindLibLZMA since CMake is case insensitive?
    Actually, doesn't the whole liblzma name conflict with FindLibLZMA
    if FindLibLZMA is meant to be used via find_package(LibLZMA)?

  - Can you test if the generated .cmake files work in practice?
    I haven't tested them in any way.

CMakeLists.txt in vcpkg sets CMAKE_DEBUG_POSTFIX to "d". I hope I don't
need to do that. Isn't it caller's job to set such variables?

Would it be useful to specify "COMPONENT Release" and "COMPONENT
Development" in the install commands? To do it properly for GNU/Linux
requires NAMELINK_COMPONENT too which requires CMake 3.12.

Do you have any opinion how old CMake versions need to be supported?

If you wish to help with non-Windows support too, having proper checks
for the defines under "These are specific to GNU/Linux" would be
important (and a check if librt is needed for clock_gettime). The M4
macros are in m4/tuklib_cpucores.m4 and m4/tuklib_physmem.m4. These
aren't a priority for now as the main reason for CMake support still is
MSVC and getting rid of the need to maintain the VS project files.

Thanks!

-- 
Lasse Collin  |  IRC: Larhzu @ IRCnet & Freenode
#############################################################################
#
# This provides very limited CMake support:
#   - Static or shared liblzma only (no command line tools or tests)
#   - GNU/Linux with GCC or Clang, or Windows with MSVC
#   - 32/64-bit x86 and 32/64-bit little endian ARM
#
# For now, this is indented to be useful on Windows. The GNU/Linux support
# is just for testing and shouldn't normally be used.
#
#############################################################################
#
# 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.1)

# 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})

# While this file only builds liblzma, name the project xz still in case
# some day this file builds more than liblzma. Among other things, this
# gives us variables xz_VERSION and xz_VERSION_MAJOR.
project(xz VERSION ${XZ_VERSION} LANGUAGES C)

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/file_info.c
    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_decoder.h
    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_compile_definitions(liblzma PRIVATE
    # liblzma configuration:
    PACKAGE_NAME=XZ\ Utils
    PACKAGE_URL=https://tukaani.org/xz/
    TUKLIB_SYMBOL_PREFIX=lzma_
    ASSUME_RAM=128
    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

    # Unaligned access is fast on x86(-64) and usually on 32/64-bit ARM too.
    TUKLIB_FAST_UNALIGNED_ACCESS

    # Disable assert() checks when no build type has been specified. Non-empty
    # build types like "Release" and "Debug" handle this by default.
    $<$<CONFIG:>:NDEBUG>
)

# Threading support:
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
target_link_libraries(liblzma Threads::Threads)
if(CMAKE_USE_WIN32_THREADS_INIT)
    target_compile_definitions(liblzma PRIVATE MYTHREAD_VISTA)
else()
    target_compile_definitions(liblzma PRIVATE MYTHREAD_POSIX)
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 <immintrin.h>
            int main(void)
            {
                __m128i x = { 0 };
                _mm_movemask_epi8(x);
                return 0;
            }
        "
        HAVE__MM_MOVEMASK_EPI8)
    if(HAVE__MM_MOVEMASK_EPI8)
        target_compile_definitions(liblzma PRIVATE HAVE__MM_MOVEMASK_EPI8)
    endif()
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()
else()
    # These are specific to GNU/Linux:
    target_compile_definitions(liblzma PRIVATE
        _GNU_SOURCE
        TUKLIB_CPUCORES_SCHED_GETAFFINITY
        TUKLIB_PHYSMEM_SYSCONF
        HAVE_CLOCK_GETTIME
        HAVE_DECL_CLOCK_MONOTONIC
        HAVE_PTHREAD_CONDATTR_SETCLOCK
    )

    # Symbol versioning for shared liblzma. This doesn't affect static builds.
    # FIXME? target_link_options needs CMake >= 3.13. LINK_FLAGS would be
    # compatible with CMake 3.1.
    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
    )
#     set_target_properties(liblzma PROPERTIES
#         LINK_FLAGS
#         
-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/src/liblzma/liblzma.map
#         LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/liblzma/liblzma.map
#         LINK_DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/common/common_w32res.rc
#     )
endif()

# Options for new enough GCC or Clang on any arch or operating system:
if(NOT MSVC)
    target_compile_definitions(liblzma PRIVATE
        HAVE___BUILTIN_ASSUME_ALIGNED
        HAVE___BUILTIN_BSWAPXX
    )

    # configure.ac has a long list but it won't be copied here:
    target_compile_options(liblzma PRIVATE -Wall -Wextra)
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.
    # lzma.dll would conflict with LZMA SDK.
    PREFIX ""
)

# Create liblzmaConfigVersion.cmake.
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}
        LIBRARY  DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE  DESTINATION ${CMAKE_INSTALL_LIBDIR}
        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/
        DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
        FILES_MATCHING PATTERN "*.h")

# Install the CMake files that other packages can use to find liblzma.
install(EXPORT liblzmaTargets
        NAMESPACE liblzma::
        FILE liblzmaTargets.cmake
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblzma)

install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfig.cmake
              ${CMAKE_CURRENT_BINARY_DIR}/liblzmaConfigVersion.cmake
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblzma)

Reply via email to