From 48f1455cd255df2fe73b5f293b47203ad0988199 Mon Sep 17 00:00:00 2001 From: Mike Ellery Date: Fri, 11 Oct 2019 17:24:25 -0700 Subject: [PATCH] CMake refactor for easier subdirectory inclusion --- .travis.yml | 64 ++++++++--- CMakeLists.txt | 255 ++++++++++++++++++++++++++------------------ ci/install_cmake.sh | 34 ++++++ src/ios.mm | 2 +- 4 files changed, 234 insertions(+), 121 deletions(-) create mode 100755 ci/install_cmake.sh diff --git a/.travis.yml b/.travis.yml index 6e3ffed..ca8991a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,14 @@ language: cpp +env: + global: + - CMAKE_EXTRA_CONF="-DCOMPILE_WITH_C_LOCALE=ON" + - CTEST_OUTPUT_ON_FAILURE=1 + matrix: include: - - - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 7" + + - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 7" os: linux dist: xenial addons: @@ -15,7 +20,7 @@ matrix: env: - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 8" + - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 8" os: linux dist: xenial addons: @@ -27,7 +32,7 @@ matrix: env: - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 9" + - name: "Ubuntu 16.04 LTS (Xenial Xerus) GCC 9" os: linux dist: xenial addons: @@ -39,7 +44,7 @@ matrix: env: - MATRIX_EVAL="CC=gcc-9 && CXX=g++-9" - - name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 7" + - name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 7" os: linux dist: bionic addons: @@ -51,7 +56,7 @@ matrix: env: - MATRIX_EVAL="CC=gcc-7 && CXX=g++-7" - - name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 8" + - name: "Ubuntu 18.04 LTS (Bionic Beaver) GCC 8" os: linux dist: bionic addons: @@ -63,7 +68,7 @@ matrix: env: - MATRIX_EVAL="CC=gcc-8 && CXX=g++-8" - - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 6" + - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 6" os: linux dist: bionic addons: @@ -75,7 +80,7 @@ matrix: env: - MATRIX_EVAL="CC=clang-6.0 && CXX=clang++-6.0" - - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 7" + - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 7" os: linux dist: bionic addons: @@ -87,7 +92,7 @@ matrix: env: - MATRIX_EVAL="CC=clang-7 && CXX=clang++-7" - - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 8" + - name: "Ubuntu 18.04 LTS (Bionic Beaver) Clang 8" os: linux dist: bionic addons: @@ -99,13 +104,44 @@ matrix: env: - MATRIX_EVAL="CC=clang-8 && CXX=clang++-8" + - &macos + name: xcode10 + os: osx + osx_image: xcode10.2 + env: + - CMAKE_EXTRA_CONF="" + addons: + homebrew: + packages: + - bash + - ninja + + - <<: *macos + name: xcode9 + # xcode 9 only works if we tell it to use c++14 explicitly + env: + - CMAKE_EXTRA_CONF="-DCMAKE_CXX_STANDARD=14" + osx_image: xcode9.4 + + - <<: *macos + osx_image: xcode11 + name: xcode11 before_install: - - eval "${MATRIX_EVAL}" + - eval "${MATRIX_EVAL}" + - ci/install_cmake.sh 3.15.2 + - export OPENSSL_ROOT=$(brew --prefix openssl@1.1) + - if [ "$(uname)" = "Darwin" ] ; then export PATH="$HOME/cmake/CMake.app/Contents/bin:${PATH}"; fi + - if [ "$(uname)" = "Linux" ] ; then export PATH="$HOME/cmake/bin:${PATH}"; fi -script: +cache: + directories: + - $HOME/cmake + +script: - mkdir -p build - cd build - - cmake -DENABLE_DATE_TESTING=ON -DBUILD_SHARED_LIBS=ON -DCOMPILE_WITH_C_LOCALE=ON .. - - make -j$(nproc) - - make testit -j$(nproc) \ No newline at end of file + - eval cmake -DENABLE_DATE_TESTING=ON -DBUILD_SHARED_LIBS=ON ${CMAKE_EXTRA_CONF} .. + - cmake --build . --parallel + - cmake --build . --parallel --target testit + diff --git a/CMakeLists.txt b/CMakeLists.txt index 1309b59..885e424 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,34 +1,52 @@ +#[===================================================================[ + date library by Howard Hinnant + + CMake projects that wish to use this library should consider + something like the following : + + include( FetchContent ) + FetchContent_Declare( date_src + GIT_REPOSITORY https://github.com/HowardHinnant/date.git + GIT_TAG 2.4.2 # adjust tag/branch/commit as needed + ) + FetchContent_MakeAvailable(date_src) + ... + target_link_libraries (my_target PRIVATE date::date) + +#]===================================================================] + cmake_minimum_required( VERSION 3.1.0 ) -cmake_policy( VERSION 3.12 ) +cmake_policy( VERSION 3.14 ) project( date VERSION 2.4.1 ) include( GNUInstallDirs ) -find_package( Threads REQUIRED ) +get_directory_property( has_parent PARENT_DIRECTORY ) # Override by setting on CMake command line. -set( CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard whose features are requested.") +set( CMAKE_CXX_STANDARD 17 CACHE STRING "The C++ standard whose features are requested." ) option( USE_SYSTEM_TZ_DB "Use the operating system's timezone database" OFF ) option( USE_TZ_DB_IN_DOT "Save the timezone database in the current folder" OFF ) option( BUILD_SHARED_LIBS "Build a shared version of library" OFF ) -option( ENABLE_DATE_TESTING "Enable unit tests" ON ) +option( ENABLE_DATE_TESTING "Enable unit tests" OFF ) option( DISABLE_STRING_VIEW "Disable string view" OFF ) -option( COMPILE_WITH_C_LOCALE "pass -DONLY_C_LOCALE=1 to compiler") +option( COMPILE_WITH_C_LOCALE "define ONLY_C_LOCALE=1" OFF ) +option( BUILD_TZ_LIB "build/install of TZ library" OFF ) -if(COMPILE_WITH_C_LOCALE) - #To workaround libstdc++ issue https://github.com/HowardHinnant/date/issues/388 - add_definitions(-DONLY_C_LOCALE=1) -endif() +if( ENABLE_DATE_TESTING AND NOT BUILD_TZ_LIB ) + message(WARNING "Testing requested, bug BUILD_TZ_LIB not ON - forcing the latter") + set (BUILD_TZ_LIB ON CACHE BOOL "required for testing" FORCE) +endif( ) function( print_option OPT ) - if ( NOT DEFINED PRINT_OPTION_CURR_${OPT} OR ( NOT PRINT_OPTION_CURR_${OPT} STREQUAL ${OPT} ) ) - set( PRINT_OPTION_CURR_${OPT} ${${OPT}} CACHE BOOL "" ) - mark_as_advanced(PRINT_OPTION_CURR_${OPT}) - message( "# date: ${OPT} ${${OPT}}" ) - endif( ) + if ( NOT DEFINED PRINT_OPTION_CURR_${OPT} OR ( NOT PRINT_OPTION_CURR_${OPT} STREQUAL ${OPT} ) ) + set( PRINT_OPTION_CURR_${OPT} ${${OPT}} CACHE BOOL "" ) + mark_as_advanced(PRINT_OPTION_CURR_${OPT}) + message( "# date: ${OPT} ${${OPT}}" ) + endif( ) endfunction( ) print_option( USE_SYSTEM_TZ_DB ) @@ -37,106 +55,121 @@ print_option( BUILD_SHARED_LIBS ) print_option( ENABLE_DATE_TESTING ) print_option( DISABLE_STRING_VIEW ) -set( HEADER_FOLDER "include" ) -set( SOURCE_FOLDER "src" ) -set( TEST_FOLDER "test" ) - -# This is needed so IDE's live MSVC show header files -set( HEADER_FILES - ${HEADER_FOLDER}/date/chrono_io.h - ${HEADER_FOLDER}/date/date.h - ${HEADER_FOLDER}/date/ios.h - ${HEADER_FOLDER}/date/islamic.h - ${HEADER_FOLDER}/date/iso_week.h - ${HEADER_FOLDER}/date/julian.h - ${HEADER_FOLDER}/date/tz.h - ${HEADER_FOLDER}/date/tz_private.h +#[===================================================================[ + date (header only) library +#]===================================================================] +add_library( date INTERFACE ) +add_library( date::date ALIAS date ) +target_include_directories( date INTERFACE + $ + $ ) +# adding header sources just helps IDEs +target_sources( date INTERFACE + $$/date/date.h + # the rest of these are not currently part of the public interface of the library: + $ + $ + $ ) +# public headers will get installed: +set_target_properties( date PROPERTIES PUBLIC_HEADER include/date/date.h ) +target_compile_definitions( date INTERFACE + #To workaround libstdc++ issue https://github.com/HowardHinnant/date/issues/388 + ONLY_C_LOCALE=$,1,0> + $<$:HAS_STRING_VIEW=0> ) -add_library( tz ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp ) - -if( USE_SYSTEM_TZ_DB ) - target_compile_definitions( tz PRIVATE -DUSE_AUTOLOAD=0 ) - target_compile_definitions( tz PRIVATE -DHAS_REMOTE_API=0 ) - # cannot set USE_OS_TZDB to 1 on Windows - if( NOT WIN32 ) - target_compile_definitions( tz PUBLIC -DUSE_OS_TZDB=1 ) - endif( ) -else( ) - target_compile_definitions( tz PRIVATE -DUSE_AUTOLOAD=1 ) - target_compile_definitions( tz PRIVATE -DHAS_REMOTE_API=1 ) - target_compile_definitions( tz PUBLIC -DUSE_OS_TZDB=0 ) - find_package( CURL REQUIRED ) - include_directories( SYSTEM ${CURL_INCLUDE_DIRS} ) - set( OPTIONAL_LIBRARIES ${CURL_LIBRARIES} ) -endif( ) - -if( USE_TZ_DB_IN_DOT ) - target_compile_definitions( tz PRIVATE -DINSTALL=. ) -endif( ) - -if( DISABLE_STRING_VIEW ) - target_compile_definitions( tz PRIVATE -DHAS_STRING_VIEW=0 ) -endif( ) - -if( BUILD_SHARED_LIBS ) - set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -fPIC") - set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -fPIC") - if( WIN32 ) - target_compile_definitions( tz PRIVATE -DDATE_BUILD_DLL=1 PUBLIC -DDATE_USE_DLL=1 ) +#[===================================================================[ + tz (compiled) library +#]===================================================================] +if( BUILD_TZ_LIB ) + add_library( tz ) + target_sources( tz + PUBLIC + $$/date/tz.h + $<$:$$/date/ios.h> + PRIVATE + include/date/tz_private.h + $<$:src/ios.mm> + src/tz.cpp ) + add_library( date::tz ALIAS tz ) + target_link_libraries( tz PUBLIC date ) + target_include_directories( tz PUBLIC + $ + $ ) + target_compile_definitions( tz + PRIVATE + USE_AUTOLOAD=$,0,1> + HAS_REMOTE_API=$,0,1> + $<$,$>:DATE_BUILD_DLL=1> + $<$:INSTALL=.> + PUBLIC + USE_OS_TZDB=$,$>>,1,0> + INTERFACE + $<$,$>:DATE_USE_DLL=1> ) + set(TZ_HEADERS include/date/tz.h) + if( IOS ) + list(APPEND TZ_HEADERS include/date/ios.h) + endif( ) + set_target_properties( tz PROPERTIES + POSITION_INDEPENDENT_CODE ON + PUBLIC_HEADER "${TZ_HEADERS}" + VERSION "${PROJECT_VERSION}" + SOVERSION "${PROJECT_VERSION}" ) + if( NOT MSVC ) + find_package( Threads ) + target_link_libraries( tz PUBLIC Threads::Threads ) + endif( ) + if( NOT USE_SYSTEM_TZ_DB ) + find_package( CURL REQUIRED ) + target_link_libraries( tz PRIVATE CURL::libcurl ) endif( ) endif( ) -target_link_libraries( tz ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_LIBRARIES} ) +#[===================================================================[ + installation +#]===================================================================] +set( version_config "${CMAKE_CURRENT_BINARY_DIR}/dateConfigVersion.cmake" ) -# add include folders to the library and targets that consume it -target_include_directories(tz PUBLIC - $ - $ -) -set(version_config "${CMAKE_CURRENT_BINARY_DIR}/dateConfigVersion.cmake") -set_target_properties(tz PROPERTIES VERSION "${PROJECT_VERSION}" SOVERSION "${PROJECT_VERSION}") +include( CMakePackageConfigHelpers ) +write_basic_package_version_file( "${version_config}" + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion ) -include(CMakePackageConfigHelpers) -write_basic_package_version_file("${version_config}" VERSION ${PROJECT_VERSION} COMPATIBILITY SameMajorVersion) - -# An interface library (not a compiled library), to enable automatic include_directory (for when just date.h, -# but not "tz.h and its lib" are needed) -add_library(date INTERFACE) +install( TARGETS date + EXPORT dateConfig + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date ) +export( TARGETS date NAMESPACE date:: FILE dateConfig.cmake ) -# add include folders to the INTERFACE and targets that consume it -target_include_directories(date INTERFACE - $ - $ -) +if( BUILD_TZ_LIB ) + install( TARGETS tz + EXPORT dateConfig + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/date + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ) # This is for Windows + export( TARGETS tz NAMESPACE date:: APPEND FILE dateConfig.cmake ) +endif( ) -if(WIN32 AND NOT CYGWIN) - set(DEF_INSTALL_CMAKE_DIR CMake) -else() - set(DEF_INSTALL_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/date) -endif() - -install( TARGETS tz EXPORT dateConfig - ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} - RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) # This is for Windows - -export(TARGETS date tz NAMESPACE date:: FILE dateConfig.cmake) - -install(TARGETS date EXPORT dateConfig) -install(EXPORT dateConfig NAMESPACE date:: DESTINATION ${DEF_INSTALL_CMAKE_DIR}) -install(DIRECTORY ${HEADER_FOLDER}/ DESTINATION include/) - -if ( ENABLE_DATE_TESTING ) +if( WIN32 AND NOT CYGWIN) + set( CONFIG_LOC CMake ) +else( ) + set( CONFIG_LOC "${CMAKE_INSTALL_LIBDIR}/cmake/date" ) +endif( ) +install( EXPORT dateConfig + NAMESPACE date:: + DESTINATION ${CONFIG_LOC} ) +#[===================================================================[ + testing +#]===================================================================] +if( ENABLE_DATE_TESTING ) enable_testing( ) add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} ) - add_dependencies( testit tz ) + function( add_pass_tests TEST_GLOB TEST_PREFIX ) file( GLOB_RECURSE FILENAMES ${TEST_GLOB} ) - include_directories( "${HEADER_FOLDER}/date" ) foreach( TEST_FILE ${FILENAMES} ) get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE ) @@ -148,6 +181,8 @@ if ( ENABLE_DATE_TESTING ) add_executable( ${BIN_NAME} EXCLUDE_FROM_ALL ${TEST_FILE} ) add_test( ${TST_NAME} ${BIN_NAME} ) target_link_libraries( ${BIN_NAME} tz ) + # HACK: because the test files don't use FQ includes: + target_include_directories( ${BIN_NAME} PRIVATE include/date ) add_dependencies( testit ${BIN_NAME} ) endif( ) endforeach( ) @@ -160,29 +195,37 @@ if ( ENABLE_DATE_TESTING ) get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE ) get_filename_component( TEST_EXT ${TEST_FILE} EXT ) - set( TEST_TYPE "_fail" ) + set( TEST_TYPE "_fail" ) set( PREFIX "${TEST_PREFIX}_fail_${TEST_NAME}" ) set( BIN_NAME ${PREFIX}_bin ) set( TST_NAME ${PREFIX}_test ) - #target_compile_definitions( ${BIN_NAME} PRIVATE ${TST_NAME} ) set( TEST_BIN_NAME ${CMAKE_BINARY_DIR}/${BIN_NAME} ) add_custom_target( ${BIN_NAME} - COMMAND ${PROJECT_SOURCE_DIR}/compile_fail.sh ${TEST_BIN_NAME} ${CMAKE_CXX_COMPILER} -std=c++14 -L${CMAKE_BINARY_DIR}/ -ltz -I${PROJECT_SOURCE_DIR}/${HEADER_FOLDER}/date -o ${BIN_NAME} ${TEST_FILE} + COMMAND + ${PROJECT_SOURCE_DIR}/compile_fail.sh + ${TEST_BIN_NAME} + ${CMAKE_CXX_COMPILER} + -std=c++14 + -L${CMAKE_BINARY_DIR}/ + -ltz + -I${PROJECT_SOURCE_DIR}/include + -I${PROJECT_SOURCE_DIR}/include/date + -o ${BIN_NAME} + ${TEST_FILE} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT ${TST_NAME} - ) + COMMENT ${TST_NAME} ) add_test( ${TST_NAME} "${PROJECT_SOURCE_DIR}/test_fail.sh" ${CMAKE_BINARY_DIR}/${BIN_NAME} WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/" ) #set_tests_properties( ${TST_NAME} PROPERTIES WILL_FAIL TRUE) add_dependencies( testit ${BIN_NAME} ) endforeach( ) endfunction( ) - file( GLOB children RELATIVE "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}" "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/*" ) + file( GLOB children RELATIVE "${PROJECT_SOURCE_DIR}/test" "${PROJECT_SOURCE_DIR}/test/*" ) foreach( child ${children} ) - if( IS_DIRECTORY "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" ) - set( CUR_FOLDER "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" ) + if( IS_DIRECTORY "${PROJECT_SOURCE_DIR}/test/${child}" ) + set( CUR_FOLDER "${PROJECT_SOURCE_DIR}/test/${child}" ) add_pass_tests( "${CUR_FOLDER}/*.cpp" ${child} ) if( NOT WIN32 ) add_fail_tests( "${CUR_FOLDER}/*.fail.cpp" ${child} ) diff --git a/ci/install_cmake.sh b/ci/install_cmake.sh new file mode 100755 index 0000000..2c9fa10 --- /dev/null +++ b/ci/install_cmake.sh @@ -0,0 +1,34 @@ +#!/usr/bin/env bash +set -e + +IFS=. read cm_maj cm_min cm_rel <<<"$1" +: ${cm_rel:-0} +CMAKE_ROOT=${2:-"${HOME}/cmake"} + +function cmake_version () +{ + if [[ -d ${CMAKE_ROOT} ]] ; then + local perms=$(test $(uname) = "Linux" && echo "/111" || echo "+111") + local installed=$(find ${CMAKE_ROOT} -perm ${perms} -type f -name cmake) + if [[ "${installed}" != "" ]] ; then + echo "$(${installed} --version | head -1)" + fi + fi +} + +installed=$(cmake_version) +if [[ "${installed}" != "" && ${installed} =~ ${cm_maj}.${cm_min}.${cm_rel} ]] ; then + echo "cmake already installed: ${installed}" + exit +fi + +pkgname="cmake-${cm_maj}.${cm_min}.${cm_rel}-$(uname)-x86_64.tar.gz" +tmppkg="/tmp/cmake.tar.gz" +wget --quiet https://cmake.org/files/v${cm_maj}.${cm_min}/${pkgname} -O ${tmppkg} +mkdir -p ${CMAKE_ROOT} +cd ${CMAKE_ROOT} +tar --strip-components 1 -xf ${tmppkg} +rm -f ${tmppkg} +echo "installed: $(cmake_version)" + + diff --git a/src/ios.mm b/src/ios.mm index 105e5c0..fe3bb24 100644 --- a/src/ios.mm +++ b/src/ios.mm @@ -22,7 +22,7 @@ // SOFTWARE. // -#include "ios.h" +#include "date/ios.h" #if TARGET_OS_IPHONE