diff --git a/CMakeLists.txt b/CMakeLists.txt index 927dcbe..b95ec69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,116 +1,210 @@ -cmake_minimum_required(VERSION 3.0) +cmake_minimum_required(VERSION 3.4) +project(pugixml VERSION 1.10 LANGUAGES CXX) -project(pugixml VERSION 1.10) +include(CMakePackageConfigHelpers) +include(CMakeDependentOption) +include(GNUInstallDirs) +include(CTest) + + +cmake_dependent_option(USE_VERSIONED_LIBDIR + "Use a private subdirectory to install the headers and libraries" OFF + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) + +cmake_dependent_option(USE_POSTFIX + "Use separate postfix for each configuration to make sure you can install multiple build outputs" OFF + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) + +cmake_dependent_option(STATIC_CRT + "Use static MSVC RT libraries" OFF + "MSVC" OFF) + +cmake_dependent_option(BUILD_TESTS + "Build pugixml tests" OFF + "BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) option(BUILD_SHARED_AND_STATIC_LIBS "Build both shared and static libraries" OFF) -option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF) -option(BUILD_TESTS "Build tests" OFF) -option(USE_VERSIONED_LIBDIR "Use a private subdirectory to install the headers and libs" OFF) -option(USE_POSTFIX "Use separate postfix for each configuration to make sure you can install multiple build outputs" OFF) + # Technically not needed for this file. This is builtin. +option(BUILD_SHARED_LIBS "Build shared instead of static library" OFF) -set(BUILD_DEFINES "" CACHE STRING "Build defines") +set(BUILD_DEFINES CACHE STRING "Build defines") -if(MSVC) - option(STATIC_CRT "Use static CRT libraries" OFF) - - # Rewrite command line flags to use /MT if necessary - if(STATIC_CRT) - foreach(flag_var - CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE - CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO) - if(${flag_var} MATCHES "/MD") - string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}") - endif(${flag_var} MATCHES "/MD") - endforeach(flag_var) - endif() +# This is used to backport a CMake 3.15 feature, but is also forwards compatible +if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY + MultiThreaded$<$:Debug>$<$>:DLL>) endif() -# Pre-defines standard install locations on *nix systems. -include(GNUInstallDirs) -mark_as_advanced(CLEAR CMAKE_INSTALL_LIBDIR CMAKE_INSTALL_INCLUDEDIR) - -set(HEADERS src/pugixml.hpp src/pugiconfig.hpp) -set(SOURCES src/pugixml.cpp) - -if(BUILD_SHARED_LIBS AND MSVC) - set(PUGIXML_WINDLL_SRCS scripts/pugixml_dll.rc) +if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED) + set(CMAKE_CXX_STANDARD_REQUIRED ON) endif() -if(DEFINED BUILD_DEFINES) - foreach(DEFINE ${BUILD_DEFINES}) - add_definitions("-D" ${DEFINE}) - endforeach() +if (NOT DEFINED CMAKE_CXX_STANDARD) + set(CMAKE_CXX_STANDARD 11) endif() -if(BUILD_SHARED_AND_STATIC_LIBS) - set(LIBRARY pugixml-static pugixml-shared) +if (USE_POSTFIX) + set(CMAKE_RELWITHDEBINFO_POSTFIX _r) + set(CMAKE_MINSIZEREL_POSTFIX _m) + set(CMAKE_DEBUG_POSTFIX _d) +endif() + +if (CMAKE_VERSION VERSION_LESS 3.15) + set(msvc-rt $) + + set(msvc-rt-mtd-shared $) + set(msvc-rt-mtd-static $) + set(msvc-rt-mt-shared $) + set(msvc-rt-mt-static $) + unset(msvc-rt) + + set(msvc-rt-mtd-shared $<${msvc-rt-mtd-shared}:-MDd>) + set(msvc-rt-mtd-static $<${msvc-rt-mtd-static}:-MTd>) + set(msvc-rt-mt-shared $<${msvc-rt-mt-shared}:-MD>) + set(msvc-rt-mt-static $<${msvc-rt-mt-static}:-MT>) +endif() + +set(build-shared $) +set(build-both $) +set(versioned-dir $<$:/pugixml-${PROJECT_VERSION}>) + +add_library(pugixml) # Auto selects static or shared based on BUILD_SHARED_LIBS +add_library(pugixml-shared SHARED) +add_library(pugixml-static STATIC) + +add_library(pugixml::pugixml ALIAS pugixml) +add_library(pugixml::shared ALIAS pugixml-shared) +add_library(pugixml::static ALIAS pugixml-static) + +# This means you can use pugixml::shared when a `find_package(pugixml CONFIG)` +# is called. This keeps it consistent with the aliases we provide. +set_property(TARGET pugixml-shared PROPERTY EXPORT_NAME shared) +set_property(TARGET pugixml-static PROPERTY EXPORT_NAME static) + +set_target_properties(pugixml-shared pugixml-static pugixml + PROPERTIES + MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY} + EXCLUDE_FROM_ALL ON + SOVERSION ${PROJECT_VERSION_MAJOR} + VERSION ${PROJECT_VERSION}) + +# XXX: EXCLUDE_FROM_ALL cannot be set via a generator expression! :( +if (BUILD_SHARED_AND_STATIC_LIBS) + set_target_properties(pugixml-shared pugixml-static + PROPERTIES + EXCLUDE_FROM_ALL OFF) + set(install-targets pugixml-shared pugixml-static) else() - set(LIBRARY pugixml) + set_target_properties(pugixml + PROPERTIES + EXCLUDE_FROM_ALL OFF) + set(install-targets pugixml) endif() -if(BUILD_SHARED_AND_STATIC_LIBS) - add_library(pugixml-static STATIC ${HEADERS} ${SOURCES}) - add_library(pugixml-shared SHARED ${HEADERS} ${SOURCES} ${PUGIXML_WINDLL_SRCS}) -else() - if(BUILD_SHARED_LIBS) - add_library(pugixml SHARED ${HEADERS} ${SOURCES} ${PUGIXML_WINDLL_SRCS}) - else() - add_library(pugixml STATIC ${HEADERS} ${SOURCES}) +target_sources(pugixml-shared + PRIVATE + $<${build-shared}:${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc> + ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) +target_sources(pugixml-static + PRIVATE + ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) +target_sources(pugixml + PRIVATE + $<${build-shared}:${PROJECT_SOURCE_DIR}/scripts/pugixml_dll.rc> + ${PROJECT_SOURCE_DIR}/src/pugixml.cpp) + +# XXX: INSTALL_INTERFACE is not used here so that INCLUDES DESTINATION can work +# correctly if USE_VERSIONED_LIBDIR is set. $ can't expand +# generator expressions otherwise. +target_include_directories(pugixml-shared + PUBLIC + $) +target_include_directories(pugixml-static + PUBLIC + $) +target_include_directories(pugixml + PUBLIC + $) + +target_compile_definitions(pugixml-shared + PRIVATE + $<$:PUGIXML_API=__declspec\(dllexport\)>) +target_compile_definitions(pugixml + PRIVATE + $<$:PUGIXML_API=__declspec\(dllexport\)>) + +target_compile_options(pugixml-shared + PRIVATE + ${msvc-rt-mtd-shared} + ${msvc-rt-mtd-static} + ${msvc-rt-mt-shared} + ${msvc-rt-mt-static}) +target_compile_options(pugixml + PRIVATE + ${msvc-rt-mtd-shared} + ${msvc-rt-mtd-static} + ${msvc-rt-mt-shared} + ${msvc-rt-mt-static}) + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/scripts/pugixml-config.cmake.in" + "${PROJECT_BINARY_DIR}/pugixml-config.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_DATADIR} + NO_CHECK_REQUIRED_COMPONENTS_MACRO + NO_SET_AND_CHECK_MACRO) + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" + COMPATIBILITY SameMajorVersion) + +configure_file(scripts/pugixml.pc.in pugixml.pc @ONLY) + +install(TARGETS ${install-targets} + EXPORT pugixml-targets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir}) + +install(EXPORT pugixml-targets + NAMESPACE pugixml:: + DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/pugixml) + +install(FILES + "${PROJECT_BINARY_DIR}/pugixml-config-version.cmake" + "${PROJECT_BINARY_DIR}/pugixml-config.cmake" + DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/pugixml) + +install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc + DESTINATION ${CMAKE_INSTALL_DATADIR}/pkgconfig) + +install( + FILES + "${PROJECT_SOURCE_DIR}/src/pugiconfig.hpp" + "${PROJECT_SOURCE_DIR}/src/pugixml.hpp" + DESTINATION + ${CMAKE_INSTALL_INCLUDEDIR}${versioned-dir}) + +if (BUILD_TESTS) + set(fuzz-pattern "tests/fuzz_*.cpp") + set(test-pattern "tests/*.cpp") + if (CMAKE_VERSION VERSION_GREATER 3.11) + list(INSERT fuzz-pattern 0 CONFIGURE_DEPENDS) + list(INSERT test-pattern 0 CONFIGURE_DEPENDS) endif() -endif() - -# Export symbols for shared library builds -if(BUILD_SHARED_AND_STATIC_LIBS AND MSVC) - target_compile_definitions(pugixml-shared PRIVATE "PUGIXML_API=__declspec(dllexport)") -endif() - -if(BUILD_SHARED_LIBS AND MSVC) - target_compile_definitions(pugixml PRIVATE "PUGIXML_API=__declspec(dllexport)") -endif() - -if(USE_VERSIONED_LIBDIR) - # Install library into its own directory under LIBDIR - set(INSTALL_SUFFIX /pugixml-${pugixml_VERSION}) -endif() - -foreach(TARGET ${LIBRARY}) - # Enable C++11 long long for compilers that are capable of it - if(NOT ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} STRLESS 3.1 AND ";${CMAKE_CXX_COMPILE_FEATURES};" MATCHES ";cxx_long_long_type;") - target_compile_features(${TARGET} PUBLIC cxx_long_long_type) - endif() - - set_target_properties(${TARGET} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION ${PROJECT_VERSION_MAJOR}) - - target_include_directories(${TARGET} PUBLIC - $ - $) - - if(USE_POSTFIX) - set_target_properties(${TARGET} PROPERTIES DEBUG_POSTFIX "_d" MINSIZEREL_POSTFIX "_m" RELWITHDEBINFO_POSTFIX "_r") - endif() -endforeach() - -install(TARGETS ${LIBRARY} EXPORT pugixml-config - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}${INSTALL_SUFFIX} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}${INSTALL_SUFFIX} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - -install(FILES ${HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}${INSTALL_SUFFIX}) -install(EXPORT pugixml-config DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/pugixml) - -configure_file(scripts/pugixml.pc.in ${PROJECT_BINARY_DIR}/pugixml.pc @ONLY) -install(FILES ${PROJECT_BINARY_DIR}/pugixml.pc DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/pkgconfig) - -if(BUILD_TESTS) - file(GLOB TEST_SOURCES tests/*.cpp) - file(GLOB FUZZ_SOURCES tests/fuzz_*.cpp) - list(REMOVE_ITEM TEST_SOURCES ${FUZZ_SOURCES}) - - add_executable(check ${TEST_SOURCES}) - if(BUILD_SHARED_AND_STATIC_LIBS) - target_link_libraries(check pugixml-static) - else() - target_link_libraries(check pugixml) - endif() - add_custom_command(TARGET check POST_BUILD COMMAND check WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) + file(GLOB test-sources ${test-pattern}) + file(GLOB fuzz-sources ${fuzz-pattern}) + list(REMOVE_ITEM test-sources ${fuzz-sources}) + + add_custom_target(check + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure) + + add_executable(pugixml-check ${test-sources}) + add_test(NAME pugixml::test + COMMAND pugixml-check + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}) + add_dependencies(check pugixml-check) + target_link_libraries(pugixml-check + PRIVATE + $) endif() diff --git a/scripts/pugixml-config.cmake.in b/scripts/pugixml-config.cmake.in new file mode 100644 index 0000000..91e3493 --- /dev/null +++ b/scripts/pugixml-config.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/pugixml-targets.cmake")