#!/usr/bin/cmake cmake_minimum_required (VERSION 3.8) # ------------------------------------------------------------------------------------------------- project( NuclexStorageNative VERSION 1.0.0 DESCRIPTION "Virtual file system, serialization and compression utlities" ) # Contains compiler options, compiler tag for output directory, etc. include("../BuildSystem/cmake/cplusplus.cmake") set(BUILD_DOCS OFF CACHE BOOL "Whether to generate documentation via Doxygen") set(ENABLE_COVERAGE OFF CACHE BOOL "Whether to instrument binaries for code coverage metrics") set(WANT_BROTLI ON CACHE BOOL "Whether to integrate Brotli compression") set(WANT_BSC OFF CACHE BOOL "Whether to integrate BSC compression") set(WANT_CSC ON CACHE BOOL "Whether to integrate CSC compression") set(WANT_LZIP ON CACHE BOOL "Whether to integrate LZip (LZMA) compression") set(WANT_SEVENZIP OFF CACHE BOOL "Whether to integrate 7-Zip (LZMA, PPMD) compression") set(WANT_TANGELO OFF CACHE BOOL "Whether to integrate Tangelo compression (careful: GPL!)") set(WANT_UNRAR OFF CACHE BOOL "Whether to integrate RAR compression") set(WANT_ZLIB ON CACHE BOOL "Whether to integrate ZLib (deflate) compression") set(WANT_ZPAQ OFF CACHE BOOL "Whether to integrate ZPAQ compression") # ------------------------------------------------------------------------------------------------- # Include threading library (on Linux/Posix pthreads must be linked) find_package(Threads REQUIRED) # Use CMake's own package for locating Doxygen on the system if(BUILD_DOCS) find_package(Doxygen) endif() # Add Nuclex.Support.Native as a sub-project, we link it for utility methods. if(NOT (TARGET NuclexSupportNative)) add_subdirectory( ${PROJECT_SOURCE_DIR}/../Nuclex.Support.Native ${CMAKE_BINARY_DIR}/NuclexSupportNative ) endif() # Already included by Nuclex.Support.Native, CMake doesn't like a second inclusion... if(NOT (TARGET GoogleTest)) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/gtest ${CMAKE_BINARY_DIR}/gtest) endif() add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/expat ${CMAKE_BINARY_DIR}/expat) if(WANT_BROTLI) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/brotli ${CMAKE_BINARY_DIR}/brotli) endif() if(WANT_BSC) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/bsc ${CMAKE_BINARY_DIR}/bsc) endif() if(WANT_CSC) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/csc ${CMAKE_BINARY_DIR}/csc) endif() if(WANT_LZIP) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/lzip ${CMAKE_BINARY_DIR}/lzip) endif() if(WANT_SEVENZIP) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/lzma-sdk ${CMAKE_BINARY_DIR}/lzma-sdk) endif() if(WANT_TANGELO) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/tangelo ${CMAKE_BINARY_DIR}/tangelo) endif() if(WANT_UNRAR) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/unrar ${CMAKE_BINARY_DIR}/unrar) endif() if(WANT_ZLIB) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/zlib ${CMAKE_BINARY_DIR}/zlib) endif() if(WANT_ZPAQ) add_subdirectory(${PROJECT_SOURCE_DIR}/../ThirdParty/zpaq ${CMAKE_BINARY_DIR}/zpaq) endif() # ------------------------------------------------------------------------------------------------- if(ENABLE_COVERAGE) # Function from cplusplus.cmake that adds the required flags to # the CMAKE_C_FLAGS and CMAKE_CXX_FLAGS globally-applied build flags set_coverage_c_cxx_flags() endif() # ------------------------------------------------------------------------------------------------- # All source files are in the Source/ directory. # All (public) headers are in the Include/ directory. # All unit test source file are in the Tests/ directory. # # CMake documentation: # | Note: We do not recommend using GLOB to collect a list of # | source files from your source tree. If no CMakeLists.txt file # | changes when a source is added or removed then the generated # | build system cannot know when to ask CMake to regenerate. # # As so very often, CMake becomes a hurdle rather than helping. # I'm not going to manually maintain a list of source files. Rebuilds # where files are added, removed or renamed need to be from scratch. # file( GLOB_RECURSE sourceFiles CONFIGURE_DEPENDS "Source/*.cpp" "Source/*.c" ) file( GLOB_RECURSE headerFiles CONFIGURE_DEPENDS "Include/Nuclex/Storage/*.h" ) file( GLOB_RECURSE unittestFiles CONFIGURE_DEPENDS "Tests/*.cpp" ) # ------------------------------------------------------------------------------------------------- function(add_third_party_libraries target_name) if(WANT_BROTLI) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_BROTLI) target_link_libraries(${target_name} PRIVATE Brotli::Static) endif() if(WANT_BSC) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_BSC) target_link_libraries(${target_name} PRIVATE Bsc::Static) endif() if(WANT_CSC) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_CSC) target_link_libraries(${target_name} PRIVATE Csc::Static) endif() if(WANT_LZIP) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_LZIP) target_link_libraries(${target_name} PRIVATE LZip::Static) endif() if(WANT_SEVENZIP) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_SEVENZIP) target_link_libraries(${target_name} PRIVATE LZMA-SDK::Static) endif() if(WANT_TANGELO) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_TANGELO) target_link_libraries(${target_name} PRIVATE Tangelo::Static) endif() if(WANT_UNRAR) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_UNRAR) target_link_libraries(${target_name} PRIVATE Unrar) endif() if(WANT_ZLIB) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_ZLIB) target_link_libraries(${target_name} PRIVATE ZLib::SoloStatic) endif() if(WANT_ZPAQ) target_compile_definitions(${target_name} PRIVATE NUCLEX_STORAGE_HAVE_ZPAQ) target_link_libraries(${target_name} PRIVATE ZPaq::Static) endif() # On Unix systems, the library and unit test executable should look for # dependencies in its own directory first. set_target_properties( ${target_name} PROPERTIES BUILD_RPATH_USE_ORIGIN ON BUILD_WITH_INSTALL_RPATH ON INSTALL_RPATH_USE_LINK_PATH OFF INSTALL_RPATH "\${ORIGIN}" ) endfunction() # ------------------------------------------------------------------------------------------------- # Shared library that can be linked to other projects add_library(NuclexStorageNative SHARED) # Enable compiler warnings only if this library is compiles on its own. # If it's used as a sub-project, the including project's developers aren't # interested in seeing warnings from a project they're not maintaining. if(${CMAKE_PROJECT_NAME} STREQUAL "NuclexStorageNative") enable_target_compiler_warnings(NuclexStorageNative) else() disable_target_compiler_warnings(NuclexStorageNative) endif() # Add directory with public headers to include path target_include_directories( NuclexStorageNative PUBLIC "Include" ) # Add public headers and sources to compilation list # (headers, too, in case CMake is used to generate an IDE project) target_sources( NuclexStorageNative PUBLIC ${headerFiles} PRIVATE ${sourceFiles} ) # Link against PThreads and Nuclex.Support.Native target_link_libraries( NuclexStorageNative PRIVATE Threads::Threads PRIVATE Expat::Static PUBLIC NuclexSupportNative ) # Add include directories and static libraries of all enabled image formats add_third_party_libraries(NuclexStorageNative) # On Windows, we want the shared library to be named Nuclex.Storage.Native.dll if(WIN32) set_target_properties( NuclexStorageNative PROPERTIES OUTPUT_NAME "Nuclex.Storage.Native" ) endif() # ------------------------------------------------------------------------------------------------- # Executable that runs the unit tests (main() supplied by Googletest) add_executable(NuclexStorageNativeTests) # Enable compiler warnings only if this library is compiles on its own. # If it's used as a sub-project, the including project's developers aren't # interested in seeing warnings from a project they're not maintaining. if(${CMAKE_PROJECT_NAME} STREQUAL "NuclexStorageNative") enable_target_compiler_warnings(NuclexStorageNativeTests) else() disable_target_compiler_warnings(NuclexStorageNativeTests) endif() # Let the code know it's not being compiled into a shared library # (this disables visibility/exports, thus allowing the compiler detect # additional unused code and warn about it) target_compile_definitions( NuclexStorageNativeTests PRIVATE NUCLEX_STORAGE_EXECUTABLE ) # Add directory with public headers to include path target_include_directories( NuclexStorageNativeTests PUBLIC "Include" ) # Add public headers and sources (normal + unit tests) to compilation list # (headers, too, in case CMake is used to generate an IDE project) target_sources( NuclexStorageNativeTests PRIVATE ${headerFiles} PRIVATE ${sourceFiles} PRIVATE ${unittestFiles} ) target_link_libraries( NuclexStorageNativeTests PRIVATE GoogleTest::Static PRIVATE GoogleTest::Main PRIVATE Threads::Threads PRIVATE Expat::Static PUBLIC NuclexSupportNative ) add_third_party_libraries(NuclexStorageNativeTests) # On Windows, we want the executable to be named Nuclex.Storage.Native.Tests.exe if(WIN32) set_target_properties( NuclexStorageNativeTests PROPERTIES OUTPUT_NAME "Nuclex.Storage.Native.Tests" ) endif() # ------------------------------------------------------------------------------------------------- # Install the shared library into a subdirectory of this CMakeLists.txt file # under ./bin/linux-gcc9.3-amd64-debug/ (the second-level directory is called # "compiler tag" and dynamically formed -- it ensures that when linking # a pre-compiled shared library, the correct library is used). install( TARGETS NuclexStorageNative ARCHIVE DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} ) # Do the same for Nuclex.Support.Native. Since we depend on this library # and have set the rpath accordingly, it needs to be in the same directory install( TARGETS NuclexSupportNative ARCHIVE DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} LIBRARY DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} ) # Install unit tests in same location as shared library. install( TARGETS NuclexStorageNativeTests RUNTIME DESTINATION ${PROJECT_SOURCE_DIR}/bin/${NUCLEX_COMPILER_TAG} ) # Install .pdb files on Windows platforms for the unit tests, too. install_debug_symbols(NuclexStorageNativeTests) # ------------------------------------------------------------------------------------------------- if(BUILD_DOCS) if(NOT DOXYGEN_FOUND) message(FATAL_ERROR "Can't build documentation because Doxygen was not found") endif() add_custom_target( NuclexStorageNativeDocs ALL COMMAND ${DOXYGEN_EXECUTABLE} "Nuclex.Storage.Native.doxygen.cfg" WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} ) endif() # ------------------------------------------------------------------------------------------------- file( WRITE "${PROJECT_SOURCE_DIR}/NuclexStorageNativeConfig.cmake" "#!/usr/bin/cmake # Configuration to include Nuclex.Storage.Native in a CMake-based project. If you want to # reference Nuclex.Storage.Native as an externally compiled static library, do this: # # set(NuclexStorageNative_DIR \"../Nuclex.Storage.Native\") # find_package(NuclexStorageNative REQUIRED CONFIG) # # target_link_libraries( # MyAwesomeProject # PRIVATE NuclexStorageNative::Dynamic # ) # # Alternatively, if you want to build Nuclex.Storage.Native together with your project, # use the normal CMakeLists.txt with CMake's add_subdirectory() command: # # add_subdirectory( # \"\${PROJECT_SOURCE_DIR}/../Nuclex.Storage.Native\" # \"\${CMAKE_BINARY_DIR}/nuclex.storage.native\" # ) # # target_link_libraries( # MyAwesomeProject # PRIVATE NuclexStorageNative # ) # # ------------------------------------------------------------------------------------------------- if(NOT DEFINED NUCLEX_COMPILER_TAG) message( FATAL_ERROR \"NUCLEX_COMPILER_TAG not defined! Include cplusplus.cmake before importing this package \\ in order to generate a tag identifying the platform/compiler/architecture/variant!\" ) endif() # ------------------------------------------------------------------------------------------------- if(NOT EXISTS \"\${CMAKE_CURRENT_LIST_DIR}/bin/\${NUCLEX_COMPILER_TAG}\") # TODO: Warn and link release build when compiling in debug mode # TODO: Warn and link build for older compiler version if found message( FATAL_ERROR \"Directory '\${CMAKE_CURRENT_LIST_DIR}/bin/\${NUCLEX_COMPILER_TAG}' not found. \\ Please either build and install this project before importing it via \\ find_package() or use this project's main CMakeFiles.txt via add_subdirectory()!\" ) endif() # ------------------------------------------------------------------------------------------------- add_library(NuclexStorageNative::Dynamic SHARED IMPORTED) # This may cause warnings on recent GCC versions (10.0.0+?) with LTO because GCC detects # that the headers used during build (residing in build/) are not the same used when # linking the library (copies resising in Include/). # # CMake doesn't run the install step during build, so the only way to get the headers # in place before building would be by copying them rather than installing them. set_target_properties( NuclexStorageNative::Dynamic PROPERTIES INTERFACE_INCLUDE_DIRECTORIES \"\${CMAKE_CURRENT_LIST_DIR}/Include\" IMPORTED_LINK_INTERFACE_LANGUAGES \"C\" ) if(WIN32) set_target_properties( NuclexStorageNative::Dynamic PROPERTIES IMPORTED_LOCATION \"\${CMAKE_CURRENT_LIST_DIR}/bin/\${NUCLEX_COMPILER_TAG}/Nuclex.Storage.Native.lib\" ) else() set_target_properties( NuclexStorageNative::Dynamic PROPERTIES IMPORTED_LOCATION \"\${CMAKE_CURRENT_LIST_DIR}/bin/\${NUCLEX_COMPILER_TAG}/libNuclexStorageNative.so\" ) endif() message(STATUS \"Imported Nuclex.Storage.Native targets with binaries in '\${CMAKE_CURRENT_LIST_DIR}'\")" ) # -------------------------------------------------------------------------------------------------