diff --git a/CMakeLists.txt b/CMakeLists.txt index afd620f..ae4e996 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,96 +19,194 @@ 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) + # 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") + # This is used to backport a CMake 3.15 feature if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreaded$<$:Debug>$<$>:DLL>) endif() +if (NOT DEFINED CMAKE_CXX_STANDARD_REQUIRED) + set(CMAKE_CXX_STANDARD_REQUIRED ON) +endif() + if (NOT DEFINED CMAKE_CXX_STANDARD) set(CMAKE_CXX_STANDARD 11) endif() -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) - -set(BUILD_DEFINES "" CACHE STRING "Build defines") - -# Pre-defines standard install locations on *nix systems. -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 (USE_POSTFIX) + set(CMAKE_RELWITHDEBINFO_POSTFIX _r) + set(CMAKE_MINSIZEREL_POSTFIX _m) + set(CMAKE_DEBUG_POSTFIX _d) endif() -if(DEFINED BUILD_DEFINES) - foreach(DEFINE ${BUILD_DEFINES}) - add_definitions("-D" ${DEFINE}) - endforeach() -endif() +# Generator expressions to make backporting more readable +set(should-backport-msvc-rt $) +set(msvc-rt $) +set(msvc-rt-mtd-shared $) +set(msvc-rt-mtd-static $) +set(msvc-rt-mt-shared $) +set(msvc-rt-mt-static $) -if(BUILD_SHARED_AND_STATIC_LIBS) - set(LIBRARY pugixml-static pugixml-shared) +set(msvc-rt-mtd-shared $) +set(msvc-rt-mtd-static $) +set(msvc-rt-mt-shared $) +set(msvc-rt-mt-static $) + +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}:-MDd> + $<${msvc-rt-mtd-static}:-MTd> + $<${msvc-rt-mt-shared}:-MD> + $<${msvc-rt-mt-static}:-MT>) +target_compile_options(pugixml + PRIVATE + $<${msvc-rt-mtd-shared}:-MDd> + $<${msvc-rt-mtd-static}:-MTd> + $<${msvc-rt-mt-shared}:-MD> + $<${msvc-rt-mt-static}:-MT>) + +configure_package_config_file( + "${PROJECT_SOURCE_DIR}/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() + 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}) + + 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() -# 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) @@ -122,4 +220,4 @@ if(BUILD_TESTS) target_link_libraries(check pugixml) endif() add_custom_command(TARGET check POST_BUILD COMMAND check WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) -endif() +endif()]] diff --git a/pugixml-config.cmake.in b/pugixml-config.cmake.in new file mode 100644 index 0000000..91e3493 --- /dev/null +++ b/pugixml-config.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/pugixml-targets.cmake")