On 2020-02-15 Mario Emmenlauer wrote: > This has been my foremost reason for cmake. While not everything is > perfect, it has proven to work very well for generating native build > instructions with well defined settings on quite a number of > platforms.
CMake can be used like GNU Autotools to make portable builds but in this case it's not practical to move the whole project to CMake. It should be enough to have something that does as little as possible to produce usable output for MSVC and ignore the portability features of CMake... > I would start with the instructions from vcpkg (see > https://github.com/microsoft/vcpkg/tree/master/ports/liblzma) but > unify their multiple patches into a single, concise CMakeLists.txt. ...and these files seem to do that, and they only build liblzma. Thanks! There are several details that I don't understand (yet). I see some small minor problems though. liblzma_w32res.rc is missing from from Windows DLL output. The "NOT WIN32" part looks a bit broken even though it might compile. For example: - The definition of SIZEOF_SIZE_T is wrong as it's not understandable by the preprocessor but it's often not needed either so a compiler may not care. - Some #defines are missing that are needed for a good build on GNU/Linux. I wonder why enable-uwp-builds.patch is needed. Is GetModuleHandle a problem on UWP? If so, it can be changed to make things simpler. Compatibility with Windows 98 isn't that important... ;-) Since I would be maintaining the CMakeLists.txt file, I thought I should understand it too. After reading some CMake docs and the linked vcpkg files I ended up with the attached file. It does a little more than just MSVC support so I can test it on GNU/Linux too. It only works against xz.git, but if this can be finished quickly, a version can be included in the upcoming XZ Utils 5.2.5. Some known issues with my CMakeLists.txt: - The Windows parts aren't tested at all. The file header says 32/64-bit x86/ARM but I tried only x86-64 GNU/Linux. - It obviously doesn't attempt to be properly portable since it assumes little endian etc. but that isn't the goal for now either. - I don't have much clue about the generated .cmake files. E.g. is the single-line liblzmaConfig.cmake fine or does it need something extra to handle the dependency on Threads::Theads? - The default installation paths come from GNUInstallDirs. The .cmake files are installed into a different directory than in the vcpkg files. - All #defines are passed as command line arguments. That is, it doesn't create or use config.h. The number of #defines isn't huge so it the command line lengths don't get too long, but is it bad/ugly on Windows? - NDEBUG shouldn't be #defined for debug builds. Thoughts, fixes, suggestions etc. are welcome. -- 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 ${CMAKE_CURRENT_LIST_DIR}/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, xz_VERSION_MAJOR, and xz_HOMEPAGE_URL. project(xz VERSION ${XZ_VERSION} DESCRIPTION "XZ Utils (liblzma only)" HOMEPAGE_URL "https://tukaani.org/xz/" LANGUAGES C ) add_library(liblzma ${CMAKE_CURRENT_LIST_DIR}/src/common/tuklib_cpucores.c ${CMAKE_CURRENT_LIST_DIR}/src/common/tuklib_physmem.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/check.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/crc32_fast.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/crc32_table.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/crc64_fast.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/crc64_table.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check/sha256.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/alone_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/alone_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/auto_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_buffer_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_buffer_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_header_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_header_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/block_util.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/common.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/easy_buffer_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/easy_decoder_memusage.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/easy_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/easy_encoder_memusage.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/easy_preset.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/file_info.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_buffer_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_buffer_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_common.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_flags_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/filter_flags_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/hardware_cputhreads.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/hardware_physmem.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/index.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/index_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/index_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/index_hash.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/outqueue.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_buffer_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_buffer_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_encoder_mt.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_flags_common.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_flags_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/stream_flags_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/vli_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/vli_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common/vli_size.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/delta/delta_common.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/delta/delta_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/delta/delta_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lz/lz_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lz/lz_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lz/lz_encoder_mf.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/fastpos_table.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma2_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma2_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma_encoder_optimum_fast.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma_encoder_optimum_normal.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma/lzma_encoder_presets.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/rangecoder/price_table.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/arm.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/armthumb.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/ia64.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/powerpc.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/simple_coder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/simple_decoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/simple_encoder.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/sparc.c ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple/x86.c ) target_include_directories(liblzma PRIVATE ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/api ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/common ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/check ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lz ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/rangecoder ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/lzma ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/delta ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/simple ${CMAKE_CURRENT_LIST_DIR}/src/common ) target_compile_definitions(liblzma PRIVATE # liblzma configuration: PACKAGE_NAME=XZ\ Utils PACKAGE_URL=${xz_HOMEPAGE_URL} 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 # Disable assert() checks. NDEBUG # Unaligned access is fast on x86(-64) and usually on 32/64-bit ARM too. TUKLIB_FAST_UNALIGNED_ACCESS ) # Threading support: set(THREADS_PREFER_PTHREAD_FLAG TRUE) include(FindThreads) 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. These lines do nothing on Windows (even under # Cygwin) so it's safe to enable this unconditionally. set_target_properties(liblzma PROPERTIES C_VISIBILITY_PRESET hidden) target_compile_definitions(liblzma PRIVATE HAVE_VISIBILITY=1) if(WIN32) if(BUILD_SHARED_LIBS) # Add the Windows resource file for liblzma.dll. target_sources(liblzma PRIVATE ${CMAKE_CURRENT_LIST_DIR}/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. target_link_options(liblzma PRIVATE -Wl,--version-script=${CMAKE_CURRENT_LIST_DIR}/src/liblzma/liblzma.map ) set_target_properties(liblzma PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_LIST_DIR}/src/liblzma/liblzma.map ) 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.dll, liblzma.lib, liblzma.a, ... but not libliblzma.a: 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(\"\${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 ${CMAKE_CURRENT_LIST_DIR}/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)