diff --git a/.travis.yml b/.travis.yml new file mode 100755 index 0000000..5923fe2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,50 @@ +language: cpp + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + packages: + - g++-6 + - clang-5.0 + +matrix: + include: + - os: linux + env: CXX_COMPILER=g++-6 BUILD_TYPE=Debug + - os: linux + env: CXX_COMPILER=g++-6 BUILD_TYPE=Release + - os: linux + env: CXX_COMPILER=clang++-5.0 BUILD_TYPE=Debug + - os: linux + env: CXX_COMPILER=clang++-5.0 BUILD_TYPE=Release + - os: osx + osx_image: xcode8.3 + env: CXX_COMPILER=clang++ BUILD_TYPE=Debug + - os: osx + osx_image: xcode8.3 + env: CXX_COMPILER=clang++ BUILD_TYPE=Release + - os: linux + env: CXX_COMPILER=g++-6 BUILD_TYPE=Debug COVERAGE_FLAGS="--coverage" + +script: + - mkdir build + - cd build + - > + cmake -DCMAKE_BUILD_TYPE=${BUILD_TYPE} \ + -DCMAKE_CXX_FLAGS="$COVERAGE_FLAGS" \ + -DCMAKE_CXX_COMPILER=${CXX_COMPILER} \ + -DCMAKE_VERBOSE_MAKEFILE=ON \ + -DCTEST_DROP_SITE_CDASH=TRUE \ + -DDROP_METHOD="http" \ + -DDROP_SITE="my.cdash.org" \ + -DDROP_LOCATION="/submit.php?project=mio" \ + -DBUILDNAME="$(uname -s)-${CXX_COMPILER}-${BUILD_TYPE}" .. + - ctest -VV -M Experimental -T Start \ + && ctest -VV -M Experimental -T Build \ + && ctest -VV -M Experimental -T Test + - if [[ -n "${COVERAGE_FLAGS+x}" ]]; then ctest -VV -M Experimental -T Coverage; fi + - ctest -VV -M Experimental -T Submit + + diff --git a/CMakeLists.txt b/CMakeLists.txt index 339430f..54f8768 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,18 +10,38 @@ cmake_minimum_required(VERSION 3.8) # if(DEFINED PROJECT_NAME) set(subproject ON) + if(NOT DEFINED INSTALL_SUBPROJECTS) + set(INSTALL_SUBPROJECTS ON CACHE BOOL "Install subproject dependencies") + endif() else() set(subproject OFF) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) endif() -project(mio VERSION 1.0.0 LANGUAGES C CXX) +project(mio VERSION 1.1.0 LANGUAGES C CXX) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake") -include (CTest) -include (CMakeDependentOption) +include(CMakeDependentOption) +include(CMakePackageConfigHelpers) +include(CTest) +include(GNUInstallDirs) # Generate 'compile_commands.json' for clang_complete set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# +# mio requires C++ 11 support, at a minimum. The `CMAKE_CXX_STANDARD` variable +# is referenced when a target is created to initialize the CXX_STANDARD target +# property. +# +# ** NOTE ** +# This is a directory scope variable. This has several implicitations. +# +# 1. It DOES NOT propegate to parent scopes (such as parent projects) +# 2. It hides cache variables of the same name for this directory and below +# +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + # # The `mio.testing` options only appear as cmake-gui and ccmake options iff # mio is the highest level project. In the case that mio is a subproject, these @@ -33,41 +53,47 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # CMAKE_DEPENDENT_OPTION(mio.tests "Build the mio tests and integrate with ctest" - ${BUILD_TESTING} "NOT subproject" OFF) + ON "BUILD_TESTING; NOT subproject" OFF) + +# +# On Windows, so as to be a "good citizen", mio offers two mechanisms to control +# the imported surface area of the Windows API. The default `mio` target sets +# the necessary flags for a minimal Win API (`WIN32_LEAN_AND_MEAN`, etc.) on +# linking targets. This is, in our view, the conservative behavior. +# +# However, an option is published in the cache allowing client to opt out of +# these compiler definintions. This preference will persist in the installed +# cmake configuration file, but can be modified by downstream users by way of +# the same cmake cache variable. This allows intermediate consumers (e.g. other +# libraries) to defer this decision making to downstream clients. +# +# Beyond the option-based mechanism, two additional targets, +# mio::mio_min_winapi and mio::mio_full_winapi, are specified below for those +# that expressly requiring either the minimal or full windows API, respectively. +# +CMAKE_DEPENDENT_OPTION(mio.windows.full_api + "Configure mio without WIN32_LEAN_AND_MEAN and NOMINMAX definitions" + OFF "WIN32" ON) + +# +# When the end user is consuming mio as a nested subproject, an option +# is provided such that the user may exlude mio from the set of installed +# cmake projects. This accomodates end users building executables or +# compiled libraries which privately link to mio, but wish to only ship their +# artifacts in an installation +# +CMAKE_DEPENDENT_OPTION(mio.installation + "Include mio in the install set" + "${INSTALL_SUBPROJECTS}" "subproject" ON) +mark_as_advanced(mio.installation) # # mio has no compiled components. As such, we declare it as an `INTERFACE` # library, which denotes a collection of target properties to be applied # transitively to linking targets. In our case, this amounts to an include -# directory and project header files. +# directory and (potentially) some preprocessor definitions. # -add_library(mio_base INTERFACE) - -# -# mio requires C++ 11 support, at a minimum. Setting the `cxx_std_11` compile -# features ensures that the corresponding C++ standard flag is populated in -# targets linking to mio -# -target_compile_features(mio_base INTERFACE cxx_std_11) - -# -# On Windows, so as to be a "good citizen", mio offers two different -# targets that control the imported surface area of the Windows API. The -# default `mio` target sets the necessary flags for a minimal Win API -# (`WIN32_LEAN_AND_MEAN`, etc.), while the `mio_full_winapi` target sets -# none of these flags so will not disable any of the modules. -# -if(WIN32) - include(WinApiLevels) -else() - # On non-Windows systems, the `mio` and `mio_base` targets are - # effectively identical. - add_library(mio INTERFACE) - target_link_libraries(mio - INTERFACE mio_base - ) -endif() - +add_library(mio INTERFACE) add_library(mio::mio ALIAS mio) # @@ -75,9 +101,47 @@ add_library(mio::mio ALIAS mio) # and installaion. Here we use a CMake generator expression to dispatch # on how the configuration under which this library is being consumed. # -target_include_directories(mio_base INTERFACE - $ - $) +# We define the generator expression as a variable, such that the logic +# need not be repeated when populating source file paths. +# +string(CONCAT prefix + "$" + "$") + +target_include_directories(mio INTERFACE ${prefix}) + +if(NOT mio.windows.full_api) + target_compile_definitions(mio INTERFACE + $ + $) +endif() + +if(WIN32) + add_library(mio_full_winapi INTERFACE) + add_library(mio::mio_full_winapi ALIAS mio_full_winapi) + target_include_directories(mio_full_winapi INTERFACE ${prefix}) + + add_library(mio_min_winapi INTERFACE) + add_library(mio::mio_min_winapi ALIAS mio_full_winapi) + target_compile_definitions(mio INTERFACE WIN32_LEAN_AND_MEAN NOMINMAX) + target_include_directories(mio_min_winapi INTERFACE ${prefix}) +endif() + +# +# In order to collect mio's header files in IDE tools such as XCode or Visual +# Studio, there must exist a target adding any such header files as source files. +# +# Given mio is an interface target, source files may only be added with the +# INTERFACE keyword, which consequently propegate to linking targets. This +# behavior isn't desirable to all clients. +# +# To accomodate, a second target is declared which collects the header files, +# which links to the primary mio target. As such, the header files are available +# in IDE tools. +# +add_library(mio-headers INTERFACE) +add_library(mio::mio-headers ALIAS mio-headers) +target_link_libraries(mio-headers INTERFACE mio) add_subdirectory(include/mio) @@ -85,68 +149,75 @@ if(mio.tests) add_subdirectory(test) endif() -# -# Non-testing header files (preserving relative paths) are installed to the -# `include` subdirectory of the `$INSTALL_DIR/${CMAKE_INSTALL_PREFIX}` -# directory. Source file permissions preserved. -# -install(DIRECTORY include/ - DESTINATION include - USE_SOURCE_PERMISSIONS - FILES_MATCHING PATTERN "*.*pp") +if(mio.installation) + # + # Non-testing header files (preserving relative paths) are installed to the + # `include` subdirectory of the `$INSTALL_DIR/${CMAKE_INSTALL_PREFIX}` + # directory. Source file permissions preserved. + # + install(DIRECTORY include/ + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" + FILES_MATCHING PATTERN "*.*pp") -# -# As a header-only library, there are no target components to be installed -# directly (the PUBLIC_HEADER property is not white listed for INTERFACE -# targets for some reason). -# -# However, it is worthwhile export our target description in order to later -# generate a CMake configuration file for consumption by CMake's `find_package` -# intrinsic -# -install(TARGETS mio_base mio EXPORT mioConfig) -install(EXPORT mioConfig - FILE mioConfig.cmake - NAMESPACE mio:: - DESTINATION share/cmake/mio - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + # + # As a header-only library, there are no target components to be installed + # directly (the PUBLIC_HEADER property is not white listed for INTERFACE + # targets for some reason). + # + # However, it is worthwhile export our target description in order to later + # generate a CMake configuration file for consumption by CMake's `find_package` + # intrinsic + # + install(TARGETS mio mio-headers EXPORT mioTargets) -include(CMakePackageConfigHelpers) # provides `write_basic_package_version_file` -write_basic_package_version_file("mioConfigVersion.cmake" - VERSION ${mio_VERSION} - COMPATIBILITY SameMajorVersion) + if(WIN32) + install(TARGETS mio_full_winapi mio_min_winapi EXPORT mioTargets) + endif() -install(FILES "${CMAKE_CURRENT_BINARY_DIR}/mioConfigVersion.cmake" - DESTINATION share/cmake/mio - PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ) + install(EXPORT mioTargets + FILE mio-targets.cmake + NAMESPACE mio:: + DESTINATION share/cmake/mio) -# -# Rudimentary CPack support. -# -# CPack provides a mechanism to generate installation packaging for a project, -# e.g., self-extracting shell scripts, compressed tarballs, Debian Package files, -# RPM Package Manager files, Windows NSIS installation wizards, -# Apple Disk Images (.dmg), etc. -# -# Any system libraries required (runtimes, threading, etc) should be bundled -# with the project for this type of installation. The -# `InstallRequiredSystemLibraries` CMake module attempts to provide this -# functionality in an automated way. Additional libraries may be specified as -# -# ```cmake -# list(APPEND CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS ) -# ``` -# -# A packaged installation can be generated by calling -# -# ```sh -# cpack -G --config CPackConfig.cmake -# ``` -# -# See `cpack --help` or the CPack documentation for more information. -# -include( InstallRequiredSystemLibraries ) -set( CPACK_PACKAGE_VENDOR "mandreyel" ) -set( CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE" ) -set( CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/mandreyel/mio" ) -include( CPack ) + write_basic_package_version_file("mio-config-version.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + + configure_file( + "${PROJECT_SOURCE_DIR}/cmake/mio-config.cmake.in" + "${PROJECT_BINARY_DIR}/mio-config.cmake" + @ONLY) + + install(FILES + "${PROJECT_BINARY_DIR}/mio-config-version.cmake" + "${PROJECT_BINARY_DIR}/mio-config.cmake" + DESTINATION share/cmake/mio) + + # + # Rudimentary CPack support. + # + # CPack provides a mechanism to generate installation packaging for a project, + # e.g., self-extracting shell scripts, compressed tarballs, Debian Package files, + # RPM Package Manager files, Windows NSIS installation wizards, + # Apple Disk Images (.dmg), etc. + # + # A packaged installation can be generated by calling + # + # ```sh + # cpack -G --config CPackConfig.cmake + # ``` + # + # See `cpack --help` or the CPack documentation for more information. + # + if(NOT subproject) + set(CPACK_PACKAGE_VENDOR "mandreyel") + set(CPACK_PACKAGE_DESCRIPTION_SUMMARY + "Cross-platform C++11 header-only library for memory mapped file IO") + set(CMAKE_PROJECT_HOMEPAGE_URL "https://github.com/mandreyel/mio") + set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") + set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") + set(CPACK_PACKAGE_VERSION_MINOR "${PROJECT_VERSION_MINOR}") + set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") + include(CPack) + endif() +endif() diff --git a/cmake/CTestCustom.cmake b/cmake/CTestCustom.cmake new file mode 100644 index 0000000..1e68e7f --- /dev/null +++ b/cmake/CTestCustom.cmake @@ -0,0 +1,3 @@ +set(CTEST_CUSTOM_COVERAGE_EXCLUDE + ".*test.*" + ".*c[+][+].*") diff --git a/cmake/WinApiLevels.cmake b/cmake/WinApiLevels.cmake deleted file mode 100644 index 5f3ebad..0000000 --- a/cmake/WinApiLevels.cmake +++ /dev/null @@ -1,14 +0,0 @@ -add_library(mio_full_winapi INTERFACE) -target_link_libraries(mio_full_winapi - INTERFACE mio_base -) -add_library(mio::mio_full_winapi ALIAS mio_full_winapi) - -add_library(mio INTERFACE) -target_link_libraries(mio - INTERFACE mio_full_winapi -) -target_compile_definitions(mio - INTERFACE WIN32_LEAN_AND_MEAN NOMINMAX -) -install(TARGETS mio_full_winapi EXPORT mioConfig) diff --git a/cmake/mio-config.cmake.in b/cmake/mio-config.cmake.in new file mode 100644 index 0000000..e8eaabb --- /dev/null +++ b/cmake/mio-config.cmake.in @@ -0,0 +1,13 @@ +include(CMakeDependentOption) + +CMAKE_DEPENDENT_OPTION(mio.windows.full_api + "Configure mio without WIN32_LEAN_AND_MEAN and NOMINMAX definitions" + @mio.windows.full_api@ "WIN32" ON) + +include("${CMAKE_CURRENT_LIST_DIR}/mio-targets.cmake") + +if(NOT mio.windows.full_api) + set_propery(TARGET mio::mio APPEND PROPERTY INTERFACE_COMPILE_DEFINITIONS + WIN32_LEAN_AND_MEAN + NOMINMAX) +endif() diff --git a/include/mio/CMakeLists.txt b/include/mio/CMakeLists.txt index c2d495c..1da153e 100644 --- a/include/mio/CMakeLists.txt +++ b/include/mio/CMakeLists.txt @@ -3,14 +3,9 @@ # doing so populates these files in the source listing when CMake is used # to generate XCode and Visual Studios projects # -target_sources(mio_base INTERFACE - $ - $) +target_sources(mio-headers INTERFACE + "${prefix}/mio/mmap.hpp" + "${prefix}/mio/page.hpp" + "${prefix}/mio/shared_mmap.hpp") add_subdirectory(detail) diff --git a/include/mio/detail/CMakeLists.txt b/include/mio/detail/CMakeLists.txt index d4f818c..de957ea 100644 --- a/include/mio/detail/CMakeLists.txt +++ b/include/mio/detail/CMakeLists.txt @@ -1,10 +1,3 @@ -# -# iff mio is the highest level project, include the implementation -# detail files in the source listing for CMake-generated IDE projects -# -if(NOT subproject) - target_sources(mio_base INTERFACE - $) -endif() +target_sources(mio-headers INTERFACE + "${prefix}/mio/detail/mmap.ipp" + "${prefix}/mio/detail/string_util.hpp") diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6bfc47e..3787691 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,3 +1,8 @@ +configure_file( + "${PROJECT_SOURCE_DIR}/cmake/CTestCustom.cmake" + "${PROJECT_BINARY_DIR}/CTestCustom.cmake" + COPYONLY) + add_executable(mio.test test.cpp) target_link_libraries(mio.test PRIVATE mio::mio) add_test(NAME mio.test COMMAND mio.test) @@ -10,6 +15,11 @@ if(WIN32) add_executable(mio.fullwinapi.test test.cpp) target_link_libraries(mio.fullwinapi.test - PRIVATE mio::mio_full_winapi) - add_test(NAME mio.fullwinapi.test COMMAND mio.test) + PRIVATE mio::mio_full_winapi) + add_test(NAME mio.fullwinapi.test COMMAND mio.fullwinapi.test) + + add_executable(mio.fullwinapi.test test.cpp) + target_link_libraries(mio.fullwinapi.test + PRIVATE mio::mio_min_winapi) + add_test(NAME mio.minwinapi.test COMMAND mio.minwinapi.test) endif()