diff --git a/.github/workflows/cifuzz.yml b/.github/workflows/cifuzz.yml deleted file mode 100644 index 0c38d10793ea..000000000000 --- a/.github/workflows/cifuzz.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: CIFuzz -on: [pull_request] - -permissions: - contents: read - -jobs: - Fuzzing: - runs-on: ubuntu-latest - steps: - - name: Build Fuzzers - id: build - uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master - with: - oss-fuzz-project-name: 'fmt' - dry-run: false - language: c++ - - name: Run Fuzzers - uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master - with: - oss-fuzz-project-name: 'fmt' - fuzz-seconds: 300 - dry-run: false - language: c++ - - name: Upload Crash - uses: actions/upload-artifact@v3 - if: failure() && steps.build.outcome == 'success' - with: - name: artifacts - path: ./out/artifacts diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml deleted file mode 100644 index b7737ea7bf84..000000000000 --- a/.github/workflows/doc.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: doc - -on: [push, pull_request] - -permissions: - contents: read - -jobs: - build: - # Use Ubuntu 20.04 because doxygen 1.8.13 from Ubuntu 18.04 is broken. - runs-on: ubuntu-20.04 - - steps: - - uses: actions/checkout@v3 - - - name: Add ubuntu mirrors - run: | - # Github Actions caching proxy is at times unreliable - # see https://github.com/actions/runner-images/issues/7048 - printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt - curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt - sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list - - - name: Create Build Environment - run: | - sudo apt update - sudo apt install doxygen python3-virtualenv - sudo npm install -g less clean-css - cmake -E make_directory ${{runner.workspace}}/build - - - name: Build - working-directory: ${{runner.workspace}}/build - env: - KEY: ${{secrets.KEY}} - run: $GITHUB_WORKSPACE/support/build-docs.py diff --git a/.github/workflows/linux.yml b/.github/workflows/linux.yml deleted file mode 100644 index a1ecc8211897..000000000000 --- a/.github/workflows/linux.yml +++ /dev/null @@ -1,111 +0,0 @@ -name: linux - -on: [push, pull_request] - -permissions: - contents: read - -jobs: - build: - runs-on: ubuntu-20.04 - strategy: - matrix: - cxx: [g++-4.8, g++-10, clang++-9] - build_type: [Debug, Release] - std: [11] - include: - - cxx: g++-4.8 - install: sudo apt install g++-4.8 - - cxx: g++-8 - build_type: Debug - std: 14 - install: sudo apt install g++-8 - - cxx: g++-8 - build_type: Debug - std: 17 - install: sudo apt install g++-8 - - cxx: g++-9 - build_type: Debug - std: 17 - - cxx: g++-10 - build_type: Debug - std: 17 - - cxx: g++-11 - build_type: Debug - std: 20 - install: sudo apt install g++-11 - - cxx: clang++-8 - build_type: Debug - std: 17 - cxxflags: -stdlib=libc++ - install: sudo apt install clang-8 libc++-8-dev libc++abi-8-dev - - cxx: clang++-9 - install: sudo apt install clang-9 - - cxx: clang++-9 - build_type: Debug - fuzz: -DFMT_FUZZ=ON -DFMT_FUZZ_LINKMAIN=ON - std: 17 - install: sudo apt install clang-9 - - cxx: clang++-11 - build_type: Debug - std: 20 - - cxx: clang++-11 - build_type: Debug - std: 20 - cxxflags: -stdlib=libc++ - install: sudo apt install libc++-11-dev libc++abi-11-dev - - shared: -DBUILD_SHARED_LIBS=ON - - steps: - - uses: actions/checkout@v3 - - - name: Set timezone - run: sudo timedatectl set-timezone 'Asia/Yekaterinburg' - - - name: Add repositories for older GCC - run: | - # Below two repos provide GCC 4.8, 5.5 and 6.4 - sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic main' - sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic universe' - # Below two repos additionally update GCC 6 to 6.5 - # sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic-updates main' - # sudo apt-add-repository 'deb http://azure.archive.ubuntu.com/ubuntu/ bionic-updates universe' - if: ${{ matrix.cxx == 'g++-4.8' }} - - - name: Add ubuntu mirrors - run: | - # Github Actions caching proxy is at times unreliable - # see https://github.com/actions/runner-images/issues/7048 - printf 'http://azure.archive.ubuntu.com/ubuntu\tpriority:1\n' | sudo tee /etc/apt/mirrors.txt - curl http://mirrors.ubuntu.com/mirrors.txt | sudo tee --append /etc/apt/mirrors.txt - sudo sed -i 's~http://azure.archive.ubuntu.com/ubuntu/~mirror+file:/etc/apt/mirrors.txt~' /etc/apt/sources.list - - - name: Create Build Environment - run: | - sudo apt update - ${{matrix.install}} - sudo apt install locales-all - cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - env: - CXX: ${{matrix.cxx}} - CXXFLAGS: ${{matrix.cxxflags}} - run: | - cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.fuzz}} ${{matrix.shared}} \ - -DCMAKE_CXX_STANDARD=${{matrix.std}} -DFMT_DOC=OFF \ - -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ - -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE - - - name: Build - working-directory: ${{runner.workspace}}/build - run: | - threads=`nproc` - cmake --build . --config ${{matrix.build_type}} --parallel $threads - - - name: Test - working-directory: ${{runner.workspace}}/build - run: ctest -C ${{matrix.build_type}} - env: - CTEST_OUTPUT_ON_FAILURE: True diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml deleted file mode 100644 index 475dc77fc4cf..000000000000 --- a/.github/workflows/macos.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: macos - -on: [push, pull_request] - -permissions: - contents: read - -jobs: - build: - runs-on: macos-11 - strategy: - matrix: - build_type: [Debug, Release] - std: [11, 17] - include: - - shared: -DBUILD_SHARED_LIBS=ON - - steps: - - uses: actions/checkout@v3 - - - name: Set timezone - run: sudo systemsetup -settimezone 'Asia/Yekaterinburg' - - - name: Create Build Environment - run: cmake -E make_directory ${{runner.workspace}}/build - - - name: Configure - working-directory: ${{runner.workspace}}/build - run: | - cmake -DCMAKE_BUILD_TYPE=${{matrix.build_type}} ${{matrix.shared}} \ - -DCMAKE_CXX_STANDARD=${{matrix.std}} \ - -DCMAKE_CXX_VISIBILITY_PRESET=hidden -DCMAKE_VISIBILITY_INLINES_HIDDEN=ON \ - -DFMT_DOC=OFF -DFMT_PEDANTIC=ON -DFMT_WERROR=ON $GITHUB_WORKSPACE - - - name: Build - working-directory: ${{runner.workspace}}/build - run: | - threads=`sysctl -n hw.logicalcpu` - cmake --build . --config ${{matrix.build_type}} --parallel $threads - - - name: Test - working-directory: ${{runner.workspace}}/build - run: ctest -C ${{matrix.build_type}} - env: - CTEST_OUTPUT_ON_FAILURE: True diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index d48b13d03d3c..e56fd66f7eb6 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -13,32 +13,12 @@ jobs: # windows-2019 has MSVC 2019 installed; # windows-2022 has MSVC 2022 installed: # https://github.com/actions/virtual-environments. - os: [windows-2019] - platform: [Win32, x64] - toolset: [v140, v141, v142] - standard: [14, 17, 20] - shared: ["", -DBUILD_SHARED_LIBS=ON] + os: [windows-2022] + platform: [x64] + toolset: [v143] + standard: [20] + shared: [""] build_type: [Debug, Release] - exclude: - - { toolset: v140, standard: 17 } - - { toolset: v140, standard: 20 } - - { toolset: v141, standard: 14 } - - { toolset: v141, standard: 20 } - - { toolset: v142, standard: 14 } - - { platform: Win32, toolset: v140 } - - { platform: Win32, toolset: v141 } - - { platform: Win32, standard: 14 } - - { platform: Win32, standard: 20 } - - { platform: x64, toolset: v140, shared: -DBUILD_SHARED_LIBS=ON } - - { platform: x64, toolset: v141, shared: -DBUILD_SHARED_LIBS=ON } - - { platform: x64, standard: 14, shared: -DBUILD_SHARED_LIBS=ON } - - { platform: x64, standard: 20, shared: -DBUILD_SHARED_LIBS=ON } - include: - - os: windows-2022 - platform: x64 - toolset: v143 - build_type: Debug - standard: 20 steps: - uses: actions/checkout@v3 @@ -78,22 +58,28 @@ jobs: shell: msys2 {0} strategy: matrix: - sys: [ mingw64, ucrt64 ] + cxx: [ clang++ ] + lib: [ libc++, libstdc++ ] steps: - name: Set timezone run: tzutil /s "Ekaterinburg Standard Time" shell: cmd + - uses: actions/checkout@v3 - uses: msys2/setup-msys2@v2 with: release: false - msystem: ${{matrix.sys}} - pacboy: cc:p cmake:p ninja:p lld:p - - uses: actions/checkout@v3 + msystem: ucrt64 + pacboy: cmake:u ninja:u clang:u libc++:u gcc-libs:u - name: Configure - run: cmake -B ../build -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug - env: { LDFLAGS: -fuse-ld=lld } + run: | + cmake -B ../build -G "Ninja" \ + -DBUILD_SHARED_LIBS=ON -DCMAKE_BUILD_TYPE=Debug + env: + CXX: ${{matrix.cxx}} + CXXFLAGS: ${{format('-stdlib={0} -std={1}', matrix.lib, 'c++20')}} + - name: Build - run: cmake --build ../build + run: cmake -j `nproc` --build ../build - name: Test run: ctest -j `nproc` --test-dir ../build env: diff --git a/CMakeLists.txt b/CMakeLists.txt index 4a20522c12ce..8fba299bad63 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ -cmake_minimum_required(VERSION 3.8...3.25) +cmake_minimum_required(VERSION 3.26) # Fallback for using newer policies on CMake <3.12. -if(${CMAKE_VERSION} VERSION_LESS 3.12) +if (${CMAKE_VERSION} VERSION_LESS 3.12) cmake_policy(VERSION ${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}) -endif() +endif () # Determine if fmt is built as a subproject (using add_subdirectory) # or if it is the master project. @@ -15,6 +15,10 @@ if (NOT DEFINED FMT_MASTER_PROJECT) endif () endif () +# Maby you must set C++ extensions being off. Clang's modules support may have trouble with extensions. +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS NO) + # Joins arguments and places the results in ${result_var}. function(join result_var) set(result "") @@ -25,14 +29,26 @@ function(join result_var) endfunction() function(enable_module target) + message(STATUS "FMT_MODULE: Build the CXX-MODULE") if (MSVC) - set(BMI ${CMAKE_BINARY_DIR}/fmt.ifc) + if (${CMAKE_GENERATOR} STREQUAL "Ninja") + set(_BMI ${CMAKE_BINARY_DIR}/fmt.ifc) + else () + set(_BMI ${CMAKE_CURRENT_BINARY_DIR}/fmt.ifc) + endif () + target_compile_options(${target} + PRIVATE /interface /dxifcInlineFunctions- + INTERFACE /reference fmt=${_BMI}) + elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(_BMI ${CMAKE_BINARY_DIR}/fmt.cc.pcm) target_compile_options(${target} - PRIVATE /interface - INTERFACE /reference fmt=${BMI}) + PRIVATE -fmodule-output=${_BMI} -x c++-module + INTERFACE -fmodule-file=fmt=${_BMI}) endif () - set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${BMI}) - set_source_files_properties(${BMI} PROPERTIES GENERATED ON) + set_target_properties(${target} PROPERTIES ADDITIONAL_CLEAN_FILES ${_BMI}) + set_source_files_properties(${_BMI} PROPERTIES GENERATED ON) + + set(BMI ${_BMI} PARENT_SCOPE) endfunction() include(CMakeParseArguments) @@ -80,29 +96,31 @@ option(FMT_TEST "Generate the test target." ${FMT_MASTER_PROJECT}) option(FMT_FUZZ "Generate the fuzz target." OFF) option(FMT_CUDA_TEST "Generate the cuda-test target." OFF) option(FMT_OS "Include core requiring OS (Windows/Posix) " ON) -option(FMT_MODULE "Build a module instead of a traditional library." OFF) +option(FMT_MODULE "Build a module instead of a traditional library." ON) option(FMT_SYSTEM_HEADERS "Expose headers with marking them as system." OFF) -set(FMT_CAN_MODULE OFF) -if (CMAKE_CXX_STANDARD GREATER 17 AND MSVC AND MSVC_VERSION GREATER 1933) - set(FMT_CAN_MODULE ON) +set(FMT_CAN_MODULE ${FMT_MODULE}) +if (CMAKE_CXX_STANDARD GREATER 17) + if (MSVC_VERSION GREATER 1933 OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(FMT_CAN_MODULE ON) + endif () endif () -if (NOT FMT_CAN_MODULE) +if (FMT_MODULE AND NOT FMT_CAN_MODULE) set(FMT_MODULE OFF) - message(STATUS "Module support is disabled.") + message(WARNING "Module support is disabled!") endif () if (FMT_TEST AND FMT_MODULE) # The tests require {fmt} to be compiled as traditional library - message(STATUS "Testing is incompatible with build mode 'module'.") + message(WARNING "FMT_MODULE: Some test are incompatible and disabled!") endif () set(FMT_SYSTEM_HEADERS_ATTRIBUTE "") if (FMT_SYSTEM_HEADERS) set(FMT_SYSTEM_HEADERS_ATTRIBUTE SYSTEM) endif () -if(CMAKE_SYSTEM_NAME STREQUAL "MSDOS") +if (CMAKE_SYSTEM_NAME STREQUAL "MSDOS") set(FMT_TEST OFF) message(STATUS "MSDOS is incompatible with gtest") -endif() +endif () # Get version from core.h file(READ include/fmt/core.h core_h) @@ -152,16 +170,16 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") -Wconversion -Wundef -Wno-ctor-dtor-privacy -Wno-format-nonliteral) if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.6) - set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} + list(APPEND PEDANTIC_COMPILE_FLAGS -Wno-dangling-else -Wno-unused-local-typedefs) endif () if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) - set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wdouble-promotion + list(APPEND PEDANTIC_COMPILE_FLAGS -Wdouble-promotion -Wtrampolines -Wzero-as-null-pointer-constant -Wuseless-cast -Wvector-operation-performance -Wsized-deallocation -Wshadow) endif () if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.0) - set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wshift-overflow=2 + list(APPEND PEDANTIC_COMPILE_FLAGS -Wshift-overflow=2 -Wnull-dereference -Wduplicated-cond) endif () set(WERROR_FLAG -Werror) @@ -173,7 +191,7 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") -Wno-gnu-zero-variadic-macro-arguments) check_cxx_compiler_flag(-Wzero-as-null-pointer-constant HAS_NULLPTR_WARNING) if (HAS_NULLPTR_WARNING) - set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} + list(APPEND PEDANTIC_COMPILE_FLAGS -Wzero-as-null-pointer-constant) endif () set(WERROR_FLAG -Werror) @@ -218,7 +236,7 @@ if (FMT_MODULE) set(FMT_SOURCES src/fmt.cc) elseif (FMT_OS) set(FMT_SOURCES src/format.cc src/os.cc) -else() +else () set(FMT_SOURCES src/format.cc) endif () @@ -231,12 +249,14 @@ endif () if (FMT_PEDANTIC) target_compile_options(fmt PRIVATE ${PEDANTIC_COMPILE_FLAGS}) endif () + if (FMT_MODULE) + target_compile_features(fmt PUBLIC cxx_std_20) enable_module(fmt) +else () + target_compile_features(fmt PUBLIC cxx_std_11) endif () -target_compile_features(fmt PUBLIC cxx_std_11) - target_include_directories(fmt ${FMT_SYSTEM_HEADERS_ATTRIBUTE} PUBLIC $ $) @@ -260,7 +280,7 @@ if (BUILD_SHARED_LIBS) endif () if (FMT_SAFE_DURATION_CAST) target_compile_definitions(fmt PUBLIC FMT_SAFE_DURATION_CAST) -endif() +endif () add_library(fmt-header-only INTERFACE) add_library(fmt::fmt-header-only ALIAS fmt-header-only) diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 000000000000..0ebcdd27ca4a --- /dev/null +++ b/TODO.txt @@ -0,0 +1,72 @@ +bash-3.2$ popd +/Users/clausklein/Workspace/cpp/fmt + +CXX=clang-16 cmake -S . -B build -G Ninja -D CMAKE_CXX_COMPILER_LAUNCHER=/usr/local/bin/ccache -D CMAKE_BUILD_TYPE=Debug -D CMAKE_PREFIX_PATH=/Users/clausklein/Workspace/cpp/stagedir -D CMAKE_CXX_STANDARD=20 + +-- CMake version: 3.26.3 +-- The CXX compiler identification is Clang 16.0.1 +-- Detecting CXX compiler ABI info +-- Detecting CXX compiler ABI info - done +-- Check for working CXX compiler: /usr/local/opt/llvm/bin/clang-16 - skipped +-- Detecting CXX compile features +-- Detecting CXX compile features - done +CMake Warning at CMakeLists.txt:120 (message): + FMT_MODULE: Some test are incompatible and disabled! + + +-- Version: 9.1.1 +-- Build type: Debug +-- Performing Test HAS_NULLPTR_WARNING +-- Performing Test HAS_NULLPTR_WARNING - Success +-- FMT_MODULE: Build the CXX-MODULE +-- Performing Test CMAKE_HAVE_LIBC_PTHREAD +-- Performing Test CMAKE_HAVE_LIBC_PTHREAD - Success +-- Found Threads: TRUE +-- FMT_MODULE: Build the CXX-MODULE +-- ADD_FMT_TEST_MODULE: Test module-test +-- Configuring done (2.2s) +-- Generating done (0.0s) +-- Build files have been written to: /Users/clausklein/Workspace/cpp/fmt/build +bash-3.2$ + +pushd build +ninja test-module +ninja + +#XXX clang-16: error: linker command failed with exit code 1 (use -v to see invocation) +#XXX ninja: build stopped: subcommand failed. + +clang++ -g -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk \ + -Wl,-search_paths_first -Wl,-headerpad_max_install_names test/CMakeFiles/test-module.dir/__/src/fmt.cc.o \ + test/CMakeFiles/module-test.dir/module-test.cc.o test/CMakeFiles/module-test.dir/test-main.cc.o -o bin/module-test \ + test/libtest-main.a fmt.cc.pcm test/gtest/libgtest.a + +Undefined symbols for architecture x86_64: + "fmt::v9::vsystem_error(int, fmt::v9::basic_string_view, fmt::v9::basic_format_args>)", referenced from: + std::__1::system_error fmt::v9::system_error<>(int, fmt::v9::basic_format_string) in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::dup(int)", referenced from: + output_redirect::output_redirect(__sFILE*) in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::dup2(int)", referenced from: + output_redirect::output_redirect(__sFILE*) in libtest-main.a(gtest-extra.cc.o) + output_redirect::restore() in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::pipe(fmt::v9::file&, fmt::v9::file&)", referenced from: + output_redirect::output_redirect(__sFILE*) in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::read(void*, unsigned long)", referenced from: + output_redirect::restore_and_read() in libtest-main.a(gtest-extra.cc.o) + read(fmt::v9::file&, unsigned long) in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::close()", referenced from: + fmt::v9::file::operator=(fmt::v9::file&&) in libtest-main.a(gtest-extra.cc.o) + output_redirect::restore() in libtest-main.a(gtest-extra.cc.o) + output_redirect::restore_and_read() in libtest-main.a(gtest-extra.cc.o) + "fmt::v9::file::~file()", referenced from: + output_redirect::output_redirect(__sFILE*) in libtest-main.a(gtest-extra.cc.o) + output_redirect::~output_redirect() in libtest-main.a(gtest-extra.cc.o) +ld: symbol(s) not found for architecture x86_64 +clang-16: error: linker command failed with exit code 1 (use -v to see invocation) +bash-3.2$ + +find . -name '*.pcm' | xargs ls -l +-rw-r--r-- 1 clausklein staff 21291916 Apr 24 12:44 ./CMakeFiles/fmt.dir/src/fmt.cc.pcm +lrwxr-xr-x 1 clausklein staff 75 Apr 24 12:44 ./fmt.cc.pcm -> /Users/clausklein/Workspace/cpp/fmt/build/CMakeFiles/fmt.dir/src/fmt.cc.pcm +-rw-r--r-- 1 clausklein staff 21291916 Apr 24 12:45 ./test/CMakeFiles/test-module.dir/__/src/fmt.cc.pcm +bash-3.2$ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 2f14bd3fc827..99de49ce40e7 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -6,7 +6,7 @@ set(TEST_MAIN_SRC test-main.cc gtest-extra.cc gtest-extra.h util.cc) add_library(test-main STATIC ${TEST_MAIN_SRC}) target_include_directories(test-main PUBLIC $) -target_link_libraries(test-main gtest fmt) +target_link_libraries(test-main gtest) function(add_fmt_executable name) add_executable(${name} ${ARGN}) @@ -31,19 +31,21 @@ function(add_fmt_test name) set(sources ${name}.cc ${ADD_FMT_TEST_UNPARSED_ARGUMENTS}) if (ADD_FMT_TEST_HEADER_ONLY) - set(sources ${sources} ${TEST_MAIN_SRC} ../src/os.cc) + message(STATUS "ADD_FMT_TEST_HEADER_ONLY: Test ${name}") + set(sources ${sources} ${TEST_MAIN_SRC} ${PROJECT_SOURCE_DIR}/src/os.cc) set(libs gtest fmt-header-only) if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(PEDANTIC_COMPILE_FLAGS ${PEDANTIC_COMPILE_FLAGS} -Wno-weak-vtables) + list(APPEND PEDANTIC_COMPILE_FLAGS -Wno-weak-vtables) endif () elseif (ADD_FMT_TEST_MODULE) - set(libs gtest test-module) + message(STATUS "ADD_FMT_TEST_MODULE: Test ${name}") + set(libs test-main test-module) set_source_files_properties(${name}.cc PROPERTIES OBJECT_DEPENDS test-module) else () set(libs test-main fmt) endif () add_fmt_executable(${name} ${sources}) - target_link_libraries(${name} ${libs}) + target_link_libraries(${name} PRIVATE ${libs}) # Define if certain C++ features can be used. if (FMT_PEDANTIC) @@ -55,56 +57,54 @@ function(add_fmt_test name) add_test(NAME ${name} COMMAND ${name}) endfunction() -if (FMT_MODULE) - return () -endif () - -add_fmt_test(args-test) -add_fmt_test(assert-test) -add_fmt_test(chrono-test) -add_fmt_test(color-test) -add_fmt_test(core-test) -add_fmt_test(gtest-extra-test) -add_fmt_test(format-test mock-allocator.h) -if (MSVC) - target_compile_options(format-test PRIVATE /bigobj) -endif () -if (NOT (MSVC AND BUILD_SHARED_LIBS)) - add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc) -endif () -add_fmt_test(ostream-test) -add_fmt_test(compile-test) -add_fmt_test(compile-fp-test HEADER_ONLY) -if (MSVC) - # Without this option, MSVC returns 199711L for the __cplusplus macro. - target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus) -endif() -add_fmt_test(printf-test) -add_fmt_test(ranges-test ranges-odr-test.cc) +if (NOT FMT_MODULE) + add_fmt_test(args-test) + add_fmt_test(assert-test) + add_fmt_test(chrono-test) + add_fmt_test(color-test) + add_fmt_test(core-test) + add_fmt_test(gtest-extra-test) + add_fmt_test(format-test mock-allocator.h) + if (MSVC) + target_compile_options(format-test PRIVATE /bigobj) + endif () + if (NOT (MSVC AND BUILD_SHARED_LIBS)) + add_fmt_test(format-impl-test HEADER_ONLY header-only-test.cc) + endif () + add_fmt_test(ostream-test) + add_fmt_test(compile-test) + add_fmt_test(compile-fp-test HEADER_ONLY) + if (MSVC) + # Without this option, MSVC returns 199711L for the __cplusplus macro. + target_compile_options(compile-fp-test PRIVATE /Zc:__cplusplus) + endif () + add_fmt_test(printf-test) + add_fmt_test(ranges-test ranges-odr-test.cc) -add_fmt_test(scan-test) -check_symbol_exists(strptime "time.h" HAVE_STRPTIME) -if (HAVE_STRPTIME) - target_compile_definitions(scan-test PRIVATE FMT_HAVE_STRPTIME) -endif () + add_fmt_test(scan-test) + check_symbol_exists(strptime "time.h" HAVE_STRPTIME) + if (HAVE_STRPTIME) + target_compile_definitions(scan-test PRIVATE FMT_HAVE_STRPTIME) + endif () -add_fmt_test(std-test) -try_compile(compile_result_unused - ${CMAKE_CURRENT_BINARY_DIR} - SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc - OUTPUT_VARIABLE RAWOUTPUT) -string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}") -if (STDLIBFS) - target_link_libraries(std-test ${STDLIBFS}) -endif () -add_fmt_test(unicode-test HEADER_ONLY) -if (MSVC) - target_compile_options(unicode-test PRIVATE /utf-8) + add_fmt_test(std-test) + try_compile(compile_result_unused + ${CMAKE_CURRENT_BINARY_DIR} + SOURCES ${CMAKE_CURRENT_LIST_DIR}/detect-stdfs.cc + OUTPUT_VARIABLE RAWOUTPUT) + string(REGEX REPLACE ".*libfound \"([^\"]*)\".*" "\\1" STDLIBFS "${RAWOUTPUT}") + if (STDLIBFS) + target_link_libraries(std-test ${STDLIBFS}) + endif () + add_fmt_test(unicode-test HEADER_ONLY) + if (MSVC) + target_compile_options(unicode-test PRIVATE /utf-8) + endif () + add_fmt_test(xchar-test) + add_fmt_test(enforce-checks-test) + target_compile_definitions(enforce-checks-test PRIVATE + -DFMT_ENFORCE_COMPILE_STRING) endif () -add_fmt_test(xchar-test) -add_fmt_test(enforce-checks-test) -target_compile_definitions(enforce-checks-test PRIVATE - -DFMT_ENFORCE_COMPILE_STRING) if (FMT_CAN_MODULE) # The tests need {fmt} to be compiled as traditional library @@ -117,15 +117,23 @@ if (FMT_CAN_MODULE) $) enable_module(test-module) + #XXX add_fmt_test(module-test HEADER_ONLY test-main.cc) add_fmt_test(module-test MODULE test-main.cc) if (MSVC) target_compile_options(test-module PRIVATE /utf-8 /Zc:__cplusplus /Zc:externConstexpr /Zc:inline) target_compile_options(module-test PRIVATE /utf-8 /Zc:__cplusplus /Zc:externConstexpr /Zc:inline) + else () + target_compile_options(module-test PRIVATE -x c++ --std=c++20 -fmodule-file=fmt=${BMI}) + target_link_libraries(module-test PRIVATE ${CMAKE_BINARY_DIR}/${BMI}) endif () endif () +if (FMT_CAN_MODULE) + return () +endif () + if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC) foreach (flag_var CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE @@ -133,13 +141,13 @@ if (NOT DEFINED MSVC_STATIC_RUNTIME AND MSVC) if (${flag_var} MATCHES "^(/|-)(MT|MTd)") set(MSVC_STATIC_RUNTIME ON) break() - endif() + endif () endforeach() -endif() +endif () if (NOT MSVC_STATIC_RUNTIME) add_fmt_executable(posix-mock-test - posix-mock-test.cc ../src/format.cc ${TEST_MAIN_SRC}) + posix-mock-test.cc ${PROJECT_SOURCE_DIR}/src/format.cc ${TEST_MAIN_SRC}) target_include_directories( posix-mock-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_link_libraries(posix-mock-test gtest) @@ -159,7 +167,7 @@ if (FMT_PEDANTIC) check_cxx_compiler_flag(-fno-exceptions HAVE_FNO_EXCEPTIONS_FLAG) endif () if (HAVE_FNO_EXCEPTIONS_FLAG) - add_library(noexception-test ../src/format.cc noexception-test.cc) + add_library(noexception-test ${PROJECT_SOURCE_DIR}/src/format.cc noexception-test.cc) target_include_directories( noexception-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_options(noexception-test PRIVATE -fno-exceptions) @@ -167,7 +175,7 @@ if (FMT_PEDANTIC) endif () # Test that the library compiles without locale. - add_library(nolocale-test ../src/format.cc) + add_library(nolocale-test ${PROJECT_SOURCE_DIR}/src/format.cc) target_include_directories( nolocale-test PRIVATE ${PROJECT_SOURCE_DIR}/include) target_compile_definitions( diff --git a/test/gtest-extra.h b/test/gtest-extra.h index ef2a04e7ca14..03a07a2af494 100644 --- a/test/gtest-extra.h +++ b/test/gtest-extra.h @@ -12,12 +12,7 @@ #include -#ifdef FMT_MODULE_TEST -import fmt; -#else -# include "fmt/os.h" -#endif // FMG_MODULE_TEST - +#include "fmt/os.h" #include "gmock/gmock.h" #define FMT_TEST_THROW_(statement, expected_exception, expected_message, fail) \ diff --git a/test/gtest/CMakeLists.txt b/test/gtest/CMakeLists.txt index 0cccc61fec5a..dc436b7883f5 100644 --- a/test/gtest/CMakeLists.txt +++ b/test/gtest/CMakeLists.txt @@ -9,7 +9,7 @@ add_library(gtest STATIC gmock-gtest-all.cc gmock/gmock.h gtest/gtest.h gtest/gtest-spi.h) target_compile_definitions(gtest PUBLIC GTEST_HAS_STD_WSTRING=1) target_include_directories(gtest SYSTEM PUBLIC .) -target_compile_features(gtest PUBLIC cxx_std_11) +target_compile_features(gtest PRIVATE cxx_std_20) find_package(Threads) if (Threads_FOUND) diff --git a/test/module-test.cc b/test/module-test.cc index 1e82eafe3b1c..0f51cedd114a 100644 --- a/test/module-test.cc +++ b/test/module-test.cc @@ -15,18 +15,20 @@ # define FMT_HIDE_MODULE_BUGS #endif -#define FMT_MODULE_TEST - #include #include #include +#include #include #include #include +#include #include #include #include #include +#include +#include #if (__has_include() || defined(__APPLE__) || \ defined(__linux__)) && \ @@ -41,7 +43,6 @@ #else # define FMT_POSIX(call) call #endif -#define FMT_OS_H_ // don't pull in os.h directly or indirectly import fmt; @@ -53,13 +54,8 @@ static bool macro_leaked = false; #endif -// Include sources to pick up functions and classes from the module rather than -// from the non-modular library which is baked into the 'test-main' library. -// This averts linker problems: -// - strong ownership model: missing linker symbols -// - weak ownership model: duplicate linker symbols -#include "gtest-extra.cc" -#include "util.cc" +#define FMT_OS_H_ // don't pull in os.h, neither directly nor indirectly +#include "gtest-extra.h" // an implicitly exported namespace must be visible [module.interface]/2.2 TEST(module_test, namespace) { @@ -75,9 +71,8 @@ bool oops_detail_namespace_is_visible; namespace fmt { bool namespace_detail_invisible() { #if defined(FMT_HIDE_MODULE_BUGS) && defined(_MSC_FULL_VER) && \ - ((_MSC_VER == 1929 && _MSC_FULL_VER <= 192930136) || \ - (_MSC_VER == 1930 && _MSC_FULL_VER <= 193030704)) - // bug in msvc up to 16.11.5 / 17.0-pre5: + _MSC_FULL_VER <= 193700000 + // bug in msvc up to at least 17.7: // the namespace is visible even when it is neither // implicitly nor explicitly exported @@ -140,7 +135,7 @@ TEST(module_test, format_to) { EXPECT_EQ("42", std::string_view(buffer)); fmt::memory_buffer mb; - fmt::format_to(mb, "{}", 42); + fmt::format_to(std::back_inserter(mb), "{}", 42); EXPECT_EQ("42", std::string_view(buffer)); std::wstring w; @@ -152,7 +147,7 @@ TEST(module_test, format_to) { EXPECT_EQ(L"42", std::wstring_view(wbuffer)); fmt::wmemory_buffer wb; - fmt::format_to(wb, L"{}", 42); + fmt::format_to(std::back_inserter(wb), L"{}", 42); EXPECT_EQ(L"42", std::wstring_view(wbuffer)); } @@ -211,8 +206,8 @@ TEST(module_test, dynamic_format_args) { TEST(module_test, vformat) { EXPECT_EQ("42", fmt::vformat("{}", fmt::make_format_args(42))); - EXPECT_EQ(L"42", fmt::vformat(fmt::to_string_view(L"{}"), - fmt::make_wformat_args(42))); + EXPECT_EQ(L"42", + fmt::vformat(fmt::wstring_view(L"{}"), fmt::make_wformat_args(42))); } TEST(module_test, vformat_to) { @@ -245,9 +240,9 @@ TEST(module_test, vformat_to_n) { auto wstore = fmt::make_wformat_args(12345); std::wstring w; auto wresult = fmt::vformat_to_n(std::back_inserter(w), 1, - fmt::to_string_view(L"{}"), wstore); + fmt::wstring_view(L"{}"), wstore); wchar_t wbuffer[4] = {0}; - fmt::vformat_to_n(wbuffer, 3, fmt::to_string_view(L"{:}"), wstore); + fmt::vformat_to_n(wbuffer, 3, fmt::wstring_view(L"{:}"), wstore); } std::string as_string(std::wstring_view text) { @@ -258,22 +253,18 @@ std::string as_string(std::wstring_view text) { TEST(module_test, print) { EXPECT_WRITE(stdout, fmt::print("{}µ", 42), "42µ"); EXPECT_WRITE(stderr, fmt::print(stderr, "{}µ", 4.2), "4.2µ"); - if (false) { - EXPECT_WRITE(stdout, fmt::print(L"{}µ", 42), as_string(L"42µ")); - EXPECT_WRITE(stderr, fmt::print(stderr, L"{}µ", 4.2), as_string(L"4.2µ")); - } + EXPECT_WRITE(stdout, fmt::print(L"{}µ", 42), as_string(L"42µ")); + EXPECT_WRITE(stderr, fmt::print(stderr, L"{}µ", 4.2), as_string(L"4.2µ")); } TEST(module_test, vprint) { EXPECT_WRITE(stdout, fmt::vprint("{:}µ", fmt::make_format_args(42)), "42µ"); EXPECT_WRITE(stderr, fmt::vprint(stderr, "{}", fmt::make_format_args(4.2)), "4.2"); - if (false) { - EXPECT_WRITE(stdout, fmt::vprint(L"{:}µ", fmt::make_wformat_args(42)), - as_string(L"42µ")); - EXPECT_WRITE(stderr, fmt::vprint(stderr, L"{}", fmt::make_wformat_args(42)), - as_string(L"42")); - } + EXPECT_WRITE(stdout, fmt::vprint(L"{:}µ", fmt::make_wformat_args(42)), + as_string(L"42µ")); + EXPECT_WRITE(stderr, fmt::vprint(stderr, L"{}", fmt::make_wformat_args(42)), + as_string(L"42")); } TEST(module_test, named_args) { @@ -284,9 +275,7 @@ TEST(module_test, named_args) { TEST(module_test, literals) { using namespace fmt::literals; EXPECT_EQ("42", fmt::format("{answer}", "answer"_a = 42)); - EXPECT_EQ("42", "{}"_format(42)); EXPECT_EQ(L"42", fmt::format(L"{answer}", L"answer"_a = 42)); - EXPECT_EQ(L"42", L"{}"_format(42)); } TEST(module_test, locale) { @@ -320,7 +309,7 @@ TEST(module_test, string_view) { TEST(module_test, memory_buffer) { fmt::basic_memory_buffer buffer; - fmt::format_to(buffer, "{}", "42"); + fmt::format_to(std::back_inserter(buffer), "{}", "42"); EXPECT_EQ("42", to_string(buffer)); fmt::memory_buffer nbuffer(std::move(buffer)); EXPECT_EQ("42", to_string(nbuffer)); @@ -395,27 +384,20 @@ struct test_formatter : fmt::formatter { bool check() { return true; } }; -struct test_dynamic_formatter : fmt::dynamic_formatter<> { - bool check() { return true; } -}; - -TEST(module_test, formatter) { - EXPECT_TRUE(test_formatter{}.check()); - EXPECT_TRUE(test_dynamic_formatter{}.check()); -} +TEST(module_test, formatter) { EXPECT_TRUE(test_formatter{}.check()); } TEST(module_test, join) { int arr[3] = {1, 2, 3}; std::vector vec{1.0, 2.0, 3.0}; std::initializer_list il{1, 2, 3}; - auto sep = fmt::to_string_view(", "); + auto sep = fmt::string_view(", "); EXPECT_EQ("1, 2, 3", to_string(fmt::join(arr + 0, arr + 3, sep))); EXPECT_EQ("1, 2, 3", to_string(fmt::join(arr, sep))); EXPECT_EQ("1, 2, 3", to_string(fmt::join(vec.begin(), vec.end(), sep))); EXPECT_EQ("1, 2, 3", to_string(fmt::join(vec, sep))); EXPECT_EQ("1, 2, 3", to_string(fmt::join(il, sep))); - auto wsep = fmt::to_string_view(L", "); + auto wsep = fmt::wstring_view(L", "); EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(arr + 0, arr + 3, wsep))); EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(arr, wsep))); EXPECT_EQ(L"1, 2, 3", fmt::format(L"{}", fmt::join(il, wsep))); @@ -426,7 +408,6 @@ TEST(module_test, time) { EXPECT_TRUE(fmt::localtime(time_now).tm_year > 120); EXPECT_TRUE(fmt::gmtime(time_now).tm_year > 120); auto chrono_now = std::chrono::system_clock::now(); - EXPECT_TRUE(fmt::localtime(chrono_now).tm_year > 120); EXPECT_TRUE(fmt::gmtime(chrono_now).tm_year > 120); } @@ -453,34 +434,16 @@ TEST(module_test, weekday) { EXPECT_EQ("Mon", fmt::format(std::locale::classic(), "{}", fmt::weekday(1))); } -TEST(module_test, to_string_view) { - using fmt::to_string_view; - fmt::string_view nsv{to_string_view("42")}; - EXPECT_EQ("42", nsv); - fmt::wstring_view wsv{to_string_view(L"42")}; - EXPECT_EQ(L"42", wsv); -} - TEST(module_test, printf) { EXPECT_WRITE(stdout, fmt::printf("%f", 42.123456), "42.123456"); EXPECT_WRITE(stdout, fmt::printf("%d", 42), "42"); - if (false) { - EXPECT_WRITE(stdout, fmt::printf(L"%f", 42.123456), - as_string(L"42.123456")); - EXPECT_WRITE(stdout, fmt::printf(L"%d", 42), as_string(L"42")); - } + EXPECT_WRITE(stdout, fmt::printf(L"%f", 42.123456), as_string(L"42.123456")); + EXPECT_WRITE(stdout, fmt::printf(L"%d", 42), as_string(L"42")); } TEST(module_test, fprintf) { EXPECT_WRITE(stderr, fmt::fprintf(stderr, "%d", 42), "42"); - std::ostringstream os; - fmt::fprintf(os, "%s", "bla"); - EXPECT_EQ("bla", os.str()); - EXPECT_WRITE(stderr, fmt::fprintf(stderr, L"%d", 42), as_string(L"42")); - std::wostringstream ws; - fmt::fprintf(ws, L"%s", L"bla"); - EXPECT_EQ(L"bla", ws.str()); } TEST(module_test, sprintf) { @@ -490,25 +453,15 @@ TEST(module_test, sprintf) { TEST(module_test, vprintf) { EXPECT_WRITE(stdout, fmt::vprintf("%d", fmt::make_printf_args(42)), "42"); - if (false) { - EXPECT_WRITE(stdout, fmt::vprintf(L"%d", fmt::make_wprintf_args(42)), - as_string(L"42")); - } + EXPECT_WRITE(stdout, fmt::vprintf(L"%d", fmt::make_wprintf_args(42)), + as_string(L"42")); } TEST(module_test, vfprintf) { auto args = fmt::make_printf_args(42); EXPECT_WRITE(stderr, fmt::vfprintf(stderr, "%d", args), "42"); - std::ostringstream os; - fmt::vfprintf(os, "%d", args); - EXPECT_EQ("42", os.str()); auto wargs = fmt::make_wprintf_args(42); - if (false) { - EXPECT_WRITE(stderr, fmt::vfprintf(stderr, L"%d", wargs), as_string(L"42")); - } - std::wostringstream ws; - fmt::vfprintf(ws, L"%d", wargs); - EXPECT_EQ(L"42", ws.str()); + EXPECT_WRITE(stderr, fmt::vfprintf(stderr, L"%d", wargs), as_string(L"42")); } TEST(module_test, vsprintf) { @@ -552,21 +505,27 @@ TEST(module_test, custom_context) { EXPECT_TRUE(!custom_arg); } -struct disabled_formatter {}; - -TEST(module_test, has_formatter) { - EXPECT_FALSE( - (fmt::has_formatter::value)); -} - -TEST(module_test, is_formattable) { - EXPECT_FALSE(fmt::is_formattable::value); -} - TEST(module_test, compile_format_string) { using namespace fmt::literals; +#ifdef __clang__ + fmt::println("\033[0;33m[=disabled=] {}\033[0;0m", "Clang 16.0 fails to import user-defined literals"); +#else EXPECT_EQ("42", fmt::format("{0:x}"_cf, 0x42)); EXPECT_EQ(L"42", fmt::format(L"{:}"_cf, 42)); EXPECT_EQ("4.2", fmt::format("{arg:3.1f}"_cf, "arg"_a = 4.2)); EXPECT_EQ(L" 42", fmt::format(L"{arg:>3}"_cf, L"arg"_a = L"42")); +#endif } + +TEST(module_test, std_types) { + EXPECT_EQ(R"("42")", fmt::format("{}", std::filesystem::path("42"))); + EXPECT_EQ(R"(optional("42"))", + fmt::format("{}", std::optional("42"))); + EXPECT_EQ("none", fmt::format("{}", std::optional())); + EXPECT_EQ("variant(42)", + fmt::format("{}", std::variant(42))); + EXPECT_EQ("monostate", fmt::format("{}", std::monostate())); + EXPECT_EQ("system:0", fmt::format("{}", std::error_code())); + EXPECT_EQ("0", fmt::format("{}", std::thread::id())); + EXPECT_EQ("42", fmt::format("{}", std::runtime_error("42"))); +} \ No newline at end of file diff --git a/test/util.h b/test/util.h index a4e8561596fb..9120e22e0c2a 100644 --- a/test/util.h +++ b/test/util.h @@ -10,11 +10,7 @@ #include #include -#ifdef FMT_MODULE_TEST -import fmt; -#else -# include "fmt/os.h" -#endif // FMT_MODULE_TEST +#include "fmt/os.h" #ifdef _MSC_VER # define FMT_VSNPRINTF vsprintf_s