From 5ec0e3168610b2389b2177de1261ff1cc88f184b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 3 Jan 2019 23:33:01 +0300 Subject: [PATCH 001/309] Added Appveyor and Travis CI config files. --- .travis.yml | 279 +++++++++++++++++++++++++++++++++++++++++++++++++++ appveyor.yml | 105 +++++++++++++++++++ 2 files changed, 384 insertions(+) create mode 100644 .travis.yml create mode 100644 appveyor.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..eead1b5997 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,279 @@ +# Copyright 2019 Andrey Semashev +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +language: cpp + +sudo: false + +python: "2.7" + +os: + - linux + - osx + +branches: + only: + - master + - develop + +env: + matrix: + - BOGUS_JOB=true + +matrix: + + exclude: + - env: BOGUS_JOB=true + + include: +# gcc, Linux + - os: linux + env: TOOLSET=gcc COMPILER=g++ CXXSTD64=03,11 + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - g++-4.7 + - g++-4.7-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - g++-4.8 + - g++-4.8-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - g++-4.9 + - g++-4.9-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD64=03,11,14 CXXSTD32=03,11 + addons: + apt: + packages: + - g++-5 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + addons: + apt: + packages: + - g++-6 + - g++-6-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + addons: + apt: + packages: + - g++-7 + - g++-7-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + env: TOOLSET=gcc COMPILER=g++-8 CXXSTD64=03,11,14,17,03-gnu,11-gnu,14-gnu,17-gnu CXXSTD32=03,11 + addons: + apt: + packages: + - g++-8 + - g++-8-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + + - os: linux + compiler: g++-8 + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD64=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + addons: + apt: + packages: + - g++-8 + sources: + - ubuntu-toolchain-r-test + +# clang, Linux + - os: linux + env: TOOLSET=clang COMPILER=clang++ CXXSTD64=03,11 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - clang-3.5 + - g++-4.9-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.5 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - clang-3.6 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.6 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD64=03,11 CXXSTD32=03,11 + addons: + apt: + packages: + - clang-3.7 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.7 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + addons: + apt: + packages: + - clang-3.8 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-precise-3.8 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + addons: + apt: + packages: + - clang-3.9 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-3.9 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + addons: + apt: + packages: + - clang-4.0 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-4.0 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + addons: + apt: + packages: + - clang-5.0 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-5.0 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + addons: + apt: + packages: + - clang-6.0 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-6.0 + + - os: linux + env: TOOLSET=clang COMPILER=clang++-7 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + addons: + apt: + packages: + - clang-7 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-7 + + - os: linux + compiler: clang++-libc++ + env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD64=03,11,14,1z + addons: + apt: + packages: + - libc++-dev + + - os: linux + compiler: clang++-libc++ + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD64=03,11,14,1z UBSAN_OPTIONS=print_stacktrace=1 + addons: + apt: + packages: + - libc++-dev + +# clang, OS X, 64-bit + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD64=03,11,14,1z + osx_image: xcode9.4 + + +install: + - cd .. + - git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule init tools/boostdep + - git submodule init tools/build + - git submodule init tools/boost_install + - git submodule init libs/headers + - git submodule init libs/config + - git submodule update --jobs 4 + - cp -r $TRAVIS_BUILD_DIR/* libs/log + - python tools/boostdep/depinst/depinst.py log + - ./bootstrap.sh + - ./b2 headers + +script: + - |- + echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam + - BUILD_JOBS=`(nproc || sysctl -n hw.ncpu) 2> /dev/null` + - if [ -n "$CXXSTD64" ]; then echo ""; echo "Testing 64-bit targets"; echo ""; ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET address-model=64 cxxstd=$CXXSTD64 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}; fi + - if [ -n "$CXXSTD32" ]; then echo ""; echo "Testing 32-bit targets"; echo ""; ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET address-model=32 cxxstd=$CXXSTD32 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}; fi + +notifications: + email: + on_success: always diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000000..da313cb94b --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,105 @@ +# Copyright 2019 Andrey Semashev +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +version: 1.0.{build}-{branch} + +shallow_clone: true + +branches: + only: + - master + - develop + +environment: + matrix: +# AppVeyor doesn't provide 64-bit compilers for these MSVC versions +# - TOOLSET: msvc-9.0 +# ADDRESS_MODEL: 64 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - TOOLSET: msvc-10.0 +# ADDRESS_MODEL: 64 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 +# - TOOLSET: msvc-11.0 +# ADDRESS_MODEL: 64 +# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-12.0 + ADDRESS_MODEL: 64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.0 + ADDRESS_MODEL: 64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.1 + ADDRESS_MODEL: 64 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - TOOLSET: gcc + ADDRESS_MODEL: 64 + CXXSTD: 03,11,03-gnu,11-gnu + ADDPATH: C:\cygwin64\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + ADDRESS_MODEL: 64 + CXXSTD: 03,11,14,03-gnu,11-gnu,14-gnu + ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + ADDRESS_MODEL: 64 + CXXSTD: 03,11,14,17,03-gnu,11-gnu,14-gnu,17-gnu + ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + + - TOOLSET: msvc-9.0 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-10.0 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-11.0 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-12.0 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.0 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: msvc-14.1 + ADDRESS_MODEL: 32 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - TOOLSET: gcc + ADDRESS_MODEL: 32 + CXXSTD: 03,11,03-gnu,11-gnu + ADDPATH: C:\cygwin\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + ADDRESS_MODEL: 32 + CXXSTD: 03,11,03-gnu,11-gnu + ADDPATH: C:\mingw\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: gcc + ADDRESS_MODEL: 32 + CXXSTD: 03,11,14,03-gnu,11-gnu,14-gnu + ADDPATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + +install: + - cd .. + - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root + - cd boost-root + - git submodule init tools/boostdep + - git submodule init tools/build + - git submodule init tools/boost_install + - git submodule init libs/headers + - git submodule init libs/config + - git submodule update --jobs 4 + - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\log + - python tools/boostdep/depinst/depinst.py log + - cmd /c bootstrap + - b2 headers + +build: off + +test_script: + - PATH=%ADDPATH%;%PATH% + - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% + - b2 -j %NUMBER_OF_PROCESSORS% libs/log/test variant=release toolset=%TOOLSET% address-model=%ADDRESS_MODEL% %CXXSTD% %B2_ARGS% From 551ad9e6c4382fc103f9b8b703ce025abc5bc602 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 3 Jan 2019 23:39:25 +0300 Subject: [PATCH 002/309] Added CI badges to the readme. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 83e666b537..a91f6cd89a 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,11 @@ Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/bo * Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). * Discussions about the library are held on the [Boost developers mailing list](https://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](https://www.boost.org/community/policy.html) before posting and add the `[log]` tag at the beginning of the subject line. +### Build status + +Master: [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) +Develop: [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) + ### License Distributed under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). From 1b6db19c4198925748d5978b8dbb021fce817e4a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 4 Jan 2019 19:14:29 +0300 Subject: [PATCH 003/309] Updated CI configs to fix git checkouts. Boost.Log tests include compilation of all examples, so depinst needs to pull dependencies of examples, in addition to the library itself and its tests. Also, added --jobs argument to the `git submodule update` executed by depinst and increased the number of jobs to 8. --- .travis.yml | 5 +++-- appveyor.yml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index eead1b5997..58f963fdb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -253,6 +253,7 @@ matrix: install: + - GIT_FETCH_JOBS=8 - cd .. - git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root @@ -261,9 +262,9 @@ install: - git submodule init tools/boost_install - git submodule init libs/headers - git submodule init libs/config - - git submodule update --jobs 4 + - git submodule update --jobs $GIT_FETCH_JOBS - cp -r $TRAVIS_BUILD_DIR/* libs/log - - python tools/boostdep/depinst/depinst.py log + - python tools/boostdep/depinst/depinst.py --include example --git_args "--jobs $GIT_FETCH_JOBS" log - ./bootstrap.sh - ./b2 headers diff --git a/appveyor.yml b/appveyor.yml index da313cb94b..2909f571e4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,6 +83,7 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 install: + - GIT_FETCH_JOBS=8 - cd .. - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root - cd boost-root @@ -91,9 +92,9 @@ install: - git submodule init tools/boost_install - git submodule init libs/headers - git submodule init libs/config - - git submodule update --jobs 4 + - git submodule update --jobs %GIT_FETCH_JOBS% - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\log - - python tools/boostdep/depinst/depinst.py log + - python tools/boostdep/depinst/depinst.py --include example --git_args "--jobs %GIT_FETCH_JOBS%" log - cmd /c bootstrap - b2 headers From a14c56dc7fc99ac5ed97a2db46956e0037ffaf40 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 00:47:05 +0300 Subject: [PATCH 004/309] Corrected variable initialization in Appveyor CI. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 2909f571e4..d08f854b04 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -83,7 +83,7 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 install: - - GIT_FETCH_JOBS=8 + - set GIT_FETCH_JOBS=8 - cd .. - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root - cd boost-root From 9ddccb5e5c0155d07bae03ce3dc0b7e8f8e5f931 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 04:02:01 +0300 Subject: [PATCH 005/309] Added env variables that allow to disable building examples and standalone teader tests while testing. --- test/Jamfile.v2 | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ccda7a1bf0..422857fd60 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -9,6 +9,7 @@ import testing ; import path ; import regex ; +import os ; project : requirements @@ -74,16 +75,21 @@ rule test_all { local all_rules ; local file ; - local headers_path = [ path.make $(BOOST_ROOT)/libs/log/include/boost/log ] ; - for file in [ path.glob-tree $(headers_path) : *.hpp : detail ] + + if ! [ os.environ BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ] { - local rel_file = [ path.relative-to $(headers_path) $(file) ] ; - # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end. - # All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes. - local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ; - #ECHO $(rel_file) ; - all_rules += [ compile compile/self_contained_header.cpp : "BOOST_LOG_TEST_HEADER=$(rel_file)" $(file) : $(test_name) ] ; + local headers_path = [ path.make $(BOOST_ROOT)/libs/log/include/boost/log ] ; + for file in [ path.glob-tree $(headers_path) : *.hpp : detail ] + { + local rel_file = [ path.relative-to $(headers_path) $(file) ] ; + # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end. + # All '/' are replaced with '-' because apparently test scripts have a problem with test names containing slashes. + local test_name = [ regex.replace ~hdr/$(rel_file) "/" "-" ] ; + #ECHO $(rel_file) ; + all_rules += [ compile compile/self_contained_header.cpp : "BOOST_LOG_TEST_HEADER=$(rel_file)" $(file) : $(test_name) ] ; + } } + for file in [ glob compile/*.cpp ] { if [ path.basename $(file) ] != "self_contained_header.cpp" @@ -100,8 +106,13 @@ rule test_all all_rules += [ run $(file) ] ; } + if ! [ os.environ BOOST_LOG_TEST_WITHOUT_EXAMPLES ] + { + all_rules += [ build-project ../example ] ; + } + #ECHO All rules: $(all_rules) ; return $(all_rules) ; } -test-suite log : [ test_all ] [ build-project ../example ] ; +test-suite log : [ test_all ] ; From 4b0cc5a30f1efc11fae06a724b47e41d26ae3410 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 04:53:16 +0300 Subject: [PATCH 006/309] Reduced the amount of CI tests, enabled global visibility for UBSan. Disabled separate 32-bit and GNU C++ builds for CI. For most jobs also disabled building examples and self-contained header tests. For UBSan jobs enabled global visibility in attempt to work around the bogus errors about calling virtual functions through a pointer to a base class. --- .travis.yml | 69 ++++++++++++++++++++++++++++++++-------------------- appveyor.yml | 19 +++++++++------ 2 files changed, 55 insertions(+), 33 deletions(-) diff --git a/.travis.yml b/.travis.yml index 58f963fdb9..9bb01f4464 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,10 +29,10 @@ matrix: include: # gcc, Linux - os: linux - env: TOOLSET=gcc COMPILER=g++ CXXSTD64=03,11 + env: TOOLSET=gcc COMPILER=g++ CXXSTD=03,11 EXTRA_TESTS=1 - os: linux - env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=03,11 addons: apt: packages: @@ -43,7 +43,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=03,11 addons: apt: packages: @@ -54,7 +54,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=03,11 addons: apt: packages: @@ -65,7 +65,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-5 CXXSTD64=03,11,14 CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14 addons: apt: packages: @@ -76,7 +76,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-6 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z addons: apt: packages: @@ -87,7 +87,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,17 addons: apt: packages: @@ -98,7 +98,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - env: TOOLSET=gcc COMPILER=g++-8 CXXSTD64=03,11,14,17,03-gnu,11-gnu,14-gnu,17-gnu CXXSTD32=03,11 + env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 addons: apt: packages: @@ -110,7 +110,7 @@ matrix: - os: linux compiler: g++-8 - env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD64=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: apt: packages: @@ -120,10 +120,10 @@ matrix: # clang, Linux - os: linux - env: TOOLSET=clang COMPILER=clang++ CXXSTD64=03,11 + env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 - os: linux - env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11 addons: apt: packages: @@ -135,7 +135,7 @@ matrix: - llvm-toolchain-precise-3.5 - os: linux - env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11 addons: apt: packages: @@ -147,7 +147,7 @@ matrix: - llvm-toolchain-precise-3.6 - os: linux - env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD64=03,11 CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11 addons: apt: packages: @@ -159,7 +159,7 @@ matrix: - llvm-toolchain-precise-3.7 - os: linux - env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z addons: apt: packages: @@ -171,7 +171,7 @@ matrix: - llvm-toolchain-precise-3.8 - os: linux - env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=03,11,14,1z addons: apt: packages: @@ -183,7 +183,7 @@ matrix: - llvm-toolchain-trusty-3.9 - os: linux - env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z addons: apt: packages: @@ -195,7 +195,7 @@ matrix: - llvm-toolchain-trusty-4.0 - os: linux - env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD64=03,11,14,1z CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z addons: apt: packages: @@ -207,7 +207,7 @@ matrix: - llvm-toolchain-trusty-5.0 - os: linux - env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17 addons: apt: packages: @@ -219,7 +219,19 @@ matrix: - llvm-toolchain-trusty-6.0 - os: linux - env: TOOLSET=clang COMPILER=clang++-7 CXXSTD64=03,11,14,17 CXXSTD32=03,11 + env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 + addons: + apt: + packages: + - clang-7 + - g++-5-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-trusty-7 + + - os: linux + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: @@ -232,7 +244,7 @@ matrix: - os: linux compiler: clang++-libc++ - env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD64=03,11,14,1z + env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=03,11,14,1z addons: apt: packages: @@ -240,15 +252,19 @@ matrix: - os: linux compiler: clang++-libc++ - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD64=03,11,14,1z UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=03,11,14,1z UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - libc++-dev -# clang, OS X, 64-bit +# clang, OS X + - os: osx + env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 EXTRA_TESTS=1 + osx_image: xcode9.4 + - os: osx - env: TOOLSET=clang COMPILER=clang++ CXXSTD64=03,11,14,1z + env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z osx_image: xcode9.4 @@ -264,7 +280,8 @@ install: - git submodule init libs/config - git submodule update --jobs $GIT_FETCH_JOBS - cp -r $TRAVIS_BUILD_DIR/* libs/log - - python tools/boostdep/depinst/depinst.py --include example --git_args "--jobs $GIT_FETCH_JOBS" log + - if [ -n "$EXTRA_TESTS" ]; then DEPINST_ARG_INCLUDE_EXAMPLES="--include example"; fi + - python tools/boostdep/depinst/depinst.py $DEPINST_ARG_INCLUDE_EXAMPLES --git_args "--jobs $GIT_FETCH_JOBS" log - ./bootstrap.sh - ./b2 headers @@ -272,8 +289,8 @@ script: - |- echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam - BUILD_JOBS=`(nproc || sysctl -n hw.ncpu) 2> /dev/null` - - if [ -n "$CXXSTD64" ]; then echo ""; echo "Testing 64-bit targets"; echo ""; ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET address-model=64 cxxstd=$CXXSTD64 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}; fi - - if [ -n "$CXXSTD32" ]; then echo ""; echo "Testing 32-bit targets"; echo ""; ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET address-model=32 cxxstd=$CXXSTD32 ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}; fi + - if [ -z "$EXTRA_TESTS" ]; then export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1; export BOOST_LOG_TEST_WITHOUT_EXAMPLES=1; fi + - ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET cxxstd=$CXXSTD ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on visibility=global} ${LINKFLAGS:+linkflags=$LINKFLAGS} notifications: email: diff --git a/appveyor.yml b/appveyor.yml index d08f854b04..1bca9e9772 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,20 +31,23 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.1 ADDRESS_MODEL: 64 + EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11,03-gnu,11-gnu + CXXSTD: 03,11 ADDPATH: C:\cygwin64\bin + EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11,14,03-gnu,11-gnu,14-gnu + CXXSTD: 03,11,14 ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin + EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11,14,17,03-gnu,11-gnu,14-gnu,17-gnu + CXXSTD: 03,11,14,17 ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -68,17 +71,17 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11,03-gnu,11-gnu + CXXSTD: 03,11 ADDPATH: C:\cygwin\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11,03-gnu,11-gnu + CXXSTD: 03,11 ADDPATH: C:\mingw\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11,14,03-gnu,11-gnu,14-gnu + CXXSTD: 03,11,14 ADDPATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -94,7 +97,8 @@ install: - git submodule init libs/config - git submodule update --jobs %GIT_FETCH_JOBS% - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\log - - python tools/boostdep/depinst/depinst.py --include example --git_args "--jobs %GIT_FETCH_JOBS%" log + - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include example" + - python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" log - cmd /c bootstrap - b2 headers @@ -102,5 +106,6 @@ build: off test_script: - PATH=%ADDPATH%;%PATH% + - if "%EXTRA_TESTS%" == "" set BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 & set BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - b2 -j %NUMBER_OF_PROCESSORS% libs/log/test variant=release toolset=%TOOLSET% address-model=%ADDRESS_MODEL% %CXXSTD% %B2_ARGS% From 413d0c323580108eb341a8a4ba2e83ca27c9cfaf Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 14:47:40 +0300 Subject: [PATCH 007/309] Corrected variable expansion in Appveyor CI config. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 1bca9e9772..fd5a8cbf07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -97,7 +97,7 @@ install: - git submodule init libs/config - git submodule update --jobs %GIT_FETCH_JOBS% - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\log - - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include example" + - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES=--include;example - python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" log - cmd /c bootstrap - b2 headers From 46560ff9fb11dd0561ff1d0a20643b043f852495 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 15:04:26 +0300 Subject: [PATCH 008/309] Removed unnecessary optimization in the check for an operator keyword. Modern compilers are able to optimize memcmp to a single cmp instruction with a constant, which was the intention of the optimization. This should fix UBSan errors. --- src/named_scope_format_parser.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/named_scope_format_parser.cpp b/src/named_scope_format_parser.cpp index 729f1fb2f4..b7a602a716 100644 --- a/src/named_scope_format_parser.cpp +++ b/src/named_scope_format_parser.cpp @@ -59,12 +59,7 @@ BOOST_FORCEINLINE bool is_name_character(char c) //! The function checks if there is 'operator' keyword at the specified position BOOST_FORCEINLINE bool is_operator_keyword(const char* p) { -#if defined(__i386__) || defined(__x86_64__) || defined(_M_AMD64) || defined(_M_IX86) - // Intel architecture allows unaligned accesses, so just compare with the whole keyword at once - return *reinterpret_cast< const uint64_t* >(p) == UINT64_C(0x726f74617265706f); -#else return std::memcmp(p, "operator", 8) == 0; -#endif } //! The function tries to parse operator signature From 6542145845a90dbdc0b01ea9f6dd99ed04485c1a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 15:34:14 +0300 Subject: [PATCH 009/309] Try a newer Xcode image to workaround CI job hangs. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9bb01f4464..f48fb38542 100644 --- a/.travis.yml +++ b/.travis.yml @@ -261,11 +261,11 @@ matrix: # clang, OS X - os: osx env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 EXTRA_TESTS=1 - osx_image: xcode9.4 + osx_image: xcode10.1 - os: osx env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z - osx_image: xcode9.4 + osx_image: xcode10.1 install: From e823f884679e8cfb949a36a17a4516cd72d7feca Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 21:15:33 +0300 Subject: [PATCH 010/309] Added support for a separate target file name pattern in text file sink. This allows to have different file names when actively writing the log file and when rotating. In particular, this solves the problem with appending to the previous file, when the log files are also collected and are supposed to have distincs names. --- doc/changelog.qbk | 6 + doc/sink_backends.qbk | 86 ++++++- doc/utilities.qbk | 17 +- example/doc/sinks_file.cpp | 3 +- example/rotating_file/main.cpp | 13 +- .../boost/log/keywords/target_file_name.hpp | 40 ++++ include/boost/log/sinks/text_file_backend.hpp | 33 ++- include/boost/log/utility/setup/file.hpp | 6 +- src/setup/init_from_settings.cpp | 6 + src/text_file_backend.cpp | 224 +++++++++++------- 10 files changed, 317 insertions(+), 117 deletions(-) create mode 100644 include/boost/log/keywords/target_file_name.hpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 5f6a7e68ed..c509070b67 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.16, Boost 1.70] + +[*New features:] + +* Added support for generating another log file name before collecting the file in the [link log.detailed.sink_backends.text_file text file sink backend]. This allows to combine [link log.detailed.sink_backends.text_file.appending appending] to an existing log file with timestamps and file counters in log filenames, and, consequently, [link log.detailed.sink_backends.text_file.file_collection file collection] in general. To enable this feature, one must set the target file name pattern in the text file sink backend (using the `target_file_name` named parameter, `text_file_backend::set_target_file_name_pattern` method call or "TargetFileName" sink parameter in the [link log.detailed.utilities.setup.settings settings]). This pattern will be used to generate a new file name when the file is finished writing and is about to be collected. Therefore, the original (active) file name can be set to a stable pattern (e.g. "app.log") so that appending to a previously written file works. Then the target file name can include a timestamp or a counter (e.g. "app-2019-01-05.log"), so that different rotated files don't conflict in the target storage. + [heading 2.15, Boost 1.69] [*General changes:] diff --git a/doc/sink_backends.qbk b/doc/sink_backends.qbk index 77e53ff8d3..1f580a344b 100644 --- a/doc/sink_backends.qbk +++ b/doc/sink_backends.qbk @@ -31,18 +31,32 @@ Although it is possible to write logs into files with the [link log.detailed.sin * Flexible log file naming * Placing the rotated files into a special location in the file system * Deleting the oldest files in order to free more space on the file system +* Similar to [link log.detailed.sink_backends.text_ostream text stream backend], the file sink backend also supports the auto-flush feature The backend is called [class_sinks_text_file_backend]. [warning This sink uses __boost_filesystem__ internally, which may cause problems on process termination. See [link log.rationale.why_crash_on_term here] for more details.] -[heading File rotation] +[section:file_rotation File rotation] -File rotation is implemented by the sink backend itself. The file name pattern and rotation thresholds can be specified when the [class_sinks_text_file_backend] backend is constructed. +File rotation happens when the sink detects that one or more rotation conditions are met and a new file needs to be created. It is implemented by the sink backend and includes the following steps: + +# If the log file is currently open, invoke the [link log.detailed.sink_backends.text_file.open_close_handlers file close handler] and close the file. +# If a target file name pattern is set, generate a new target file name and rename the log file to that generated name. +# If a [link log.detailed.sink_backends.text_file.file_collection file collector] is configured, pass the log file to it for collection. At this point the file collector may remove older log files to free up some space and move the new file into the target storage. +# When a new log record needs to be written, generate a new file name for the new file and create a file with that name. If [link log.detailed.sink_backends.text_file.appending file appending] is enabled and a file with that name exists, the file is opened in append mode instead of overwriting. + +It is important to note that there are three kinds of file names or paths involved in this process: + +* The file name that is used to create or open the log file to actively write to. This is called an /active/ file name and is specified by the `file_name` named parameter of the sink backend constructor or by calling the `set_file_name_pattern` method. +* The file name that is generated when the log file is closed and about to be collected. This is called a /target/ file name, because it defines how the log files will be named in the target storage. Target file name is optional, it can be specified by the `target_file_name` named parameter or by calling the `set_target_file_name_pattern` method. +* The target storage location, which is a directory with previously rotated log files, managed by a [link log.detailed.sink_backends.text_file.file_collection file collector]. Multiple sinks can share the same target storage. + +The file name patterns and rotation conditions can be specified when the [class_sinks_text_file_backend] backend is constructed. [example_sinks_file] -[note The file size at rotation can be imprecise. The implementation counts the number of characters written to the file, but the underlying API can introduce additional auxiliary data, which would increase the log file's actual size on disk. For instance, it is well known that Windows and DOS operating systems have a special treatment with regard to new-line characters. Each new-line character is written as a two byte sequence 0x0D 0x0A instead of a single 0x0A. Other platform-specific character translations are also known. The actual size on disk can also be less than the number of written characters on compressed filesystems.] +[note The file size at rotation can be imprecise. The implementation counts the number of bytes written to the file, but the underlying API can introduce additional auxiliary data, which would increase the log file's actual size on disk. For instance, it is well known that Windows and DOS operating systems have a special treatment with regard to new-line characters. Each new-line character is written as a two byte sequence 0x0D 0x0A instead of a single 0x0A. Other platform-specific character translations are also known. The actual size on disk can also be less than the number of written characters on compressed filesystems.] The time-based rotation is not limited by only time points. There are following options available out of the box: @@ -86,7 +100,8 @@ If none of the above applies, one can specify his own predicate for time-based r boost::shared_ptr< sinks::text_file_backend > backend = boost::make_shared< sinks::text_file_backend >( - keywords::file_name = "file_%5N.log", + keywords::file_name = "file.log", + keywords::target_file_name = "file_%5N.log", keywords::time_based_rotation = &is_it_time_to_rotate ); @@ -103,14 +118,15 @@ In addition to time and size-based file rotation the backend also performs rotat boost::shared_ptr< sinks::text_file_backend > backend = boost::make_shared< sinks::text_file_backend >( - keywords::file_name = "file_%5N.log", + keywords::file_name = "file.log", + keywords::target_file_name = "file_%5N.log", keywords::enable_final_rotation = false ); // ... } -The file name pattern may contain a number of wildcards, like the one you can see in the example above. Supported placeholders are: +Both active and target file name patterns may contain a number of wildcards, like the one you can see in the example above. Supported placeholders are: * Current date and time components. The placeholders conform to the ones specified by __boost_date_time__ library. * File counter (`%N`) with an optional width specification in the `printf`-like format. The file counter will always be decimal, zero filled to the specified width. @@ -126,17 +142,25 @@ A few quick examples: [[file\_%Y-%m-%d\_%H-%M-%S.%N.log] [file\_2008-07-05\_13-44-23.1.log, file\_2008-07-06\_16-00-10.2.log...]] ] -[important Although all __boost_date_time__ format specifiers will work, there are restrictions on some of them, if you intend to scan for old log files. This functionality is discussed in the next section.] +[important Although all __boost_date_time__ format specifiers will work, there are restrictions on some of them, if you intend to scan for old log files. This functionality is discussed [link log.detailed.sink_backends.text_file.file_scanning here].] + +Note that, as described above, active and target file names are generated at different points in time. Specifically, the active file name is generated when the log file is originally created, and the target file name - when the file is closed. Timestamps used to construct these file names will reflect that difference. + +[tip When [link log.detailed.sink_backends.text_file.appending file appending] is needed, it is recommended to avoid any placeholders in the active file name pattern. Otherwise appending won't happen because of the different active log file names. You can use the target file name pattern to add a timestamp or counter to the log file after rotation.] + +[endsect] + +[section:open_close_handlers File open and close handlers] -The sink backend allows hooking into the file rotation process in order to perform pre- and post-rotation actions. This can be useful to maintain log file validity by writing headers and footers. For example, this is how we could modify the `init_logging` function in order to write logs into XML files: +The sink backend allows hooking into the file rotation process in order to perform pre- and post-rotation actions. This can be useful to maintain log file validity by writing headers and footers. For example, this is how we could modify the `init_logging` function from our previous examples in order to write logs into XML files: [example_sinks_xml_file] [@boost:/libs/log/example/doc/sinks_xml_file.cpp See the complete code]. -Finally, the sink backend also supports the auto-flush feature, like the [link log.detailed.sink_backends.text_ostream text stream backend] does. +[endsect] -[heading Managing rotated files] +[section:file_collection Managing rotated files] After being closed, the rotated files can be collected. In order to do so one has to set up a file collector by specifying the target directory where to collect the rotated files and, optionally, size thresholds. For example, we can modify the `init_logging` function to place rotated files into a distinct directory and limit total size of the files. Let's assume the following function is called by `init_logging` with the constructed sink: @@ -148,15 +172,53 @@ One can create multiple file sink backends that collect files into the same targ [warning The collector does not resolve log file name clashes between different sink backends, so if the clash occurs the behavior is undefined, in general. Depending on the circumstances, the files may overwrite each other or the operation may fail entirely.] -The file collector provides another useful feature. Suppose you ran your application 5 times and you have 5 log files in the "logs" directory. The file sink backend and file collector provide a `scan_for_files` method that searches the target directory for these files and takes them into account. So, if it comes to deleting files, these files are not forgotten. What's more, if the file name pattern in the backend involves a file counter, scanning for older files allows updating the counter to the most recent value. Here is the final version of our `init_logging` function: +[endsect] + +[section:file_scanning Scanning for rotated files] + +The file collector provides another useful feature. Suppose you ran your application 5 times and you have 5 log files in the "logs" directory. The file sink backend and file collector provide a `scan_for_files` method that searches the target directory for these files and takes them into account. So, if it comes to deleting files, these files are not forgotten. What's more, if a file name pattern in the backend involves a file counter, scanning for older files allows updating the counter to the most recent value. Here is the final version of our `init_logging` function: [example_sinks_xml_file_final] -There are two methods of file scanning: the scan that involves file name matching with the file name pattern (the default) and the scan that assumes that all files in the target directory are log files. The former applies certain restrictions on the placeholders that can be used within the file name pattern, in particular only file counter placeholder and these placeholders of __boost_date_time__ are supported: `%y`, `%Y`, `%m`, `%d`, `%H`, `%M`, `%S`, `%f`. The latter scanning method, in its turn, has its own drawback: it does not allow updating the file counter in the backend. It is also considered to be more dangerous as it may result in unintended file deletion, so be cautious. The all-files scanning method can be enabled by passing it as an additional parameter to the `scan_for_files` call: +There are two methods of file scanning: the scan that involves file name matching with the target file name pattern (the default) and the scan that assumes that all files in the target directory are log files. The former applies certain restrictions on the placeholders that can be used within the file name pattern, in particular only file counter placeholder and these placeholders of __boost_date_time__ are supported: `%y`, `%Y`, `%m`, `%d`, `%H`, `%M`, `%S`, `%f`. The latter scanning method, in its turn, has its own drawback: it does not allow updating the file counter in the backend. It is also considered to be more dangerous as it may result in unintended file deletion, so be cautious. The all-files scanning method can be enabled by passing it as an additional parameter to the `scan_for_files` call: // Look for all files in the target directory backend->scan_for_files(sinks::file::scan_all); +When scanning for matching file names, if the target file name is not set then the active file name pattern is used instead. + +[endsect] + +[section:appending Appending to the previously written files] + +The sink backend supports appending to the previously written files (e.g. left from a previous run of your application). In order to enable this mode, one has to add `std::ios_base::app` to the file open mode used by the backend. This can be done with the `open_mode` named parameter of the backend constructor or the `set_open_mode` method. + + void init_logging() + { + // ... + + boost::shared_ptr< sinks::text_file_backend > backend = + boost::make_shared< sinks::text_file_backend >( + keywords::file_name = "file.log", + keywords::target_file_name = "file_%5N.log", + keywords::open_mode = std::ios_base::out | std::ios_base::app, + keywords::enable_final_rotation = false + ); + + // ... + } + +When initializing from [link log.detailed.utilities.setup.settings settings], the "Append" parameter of the "TextFile" sink enables appending. + +In order for file appending to actually happen, it is important that the name of the newly opened log file matches the previously written file. Othewise, the sink will simply create a new file under the new name. There are several recommendations to follow when file appending is desirable: + +* Don't use placeholders in the active file name pattern. This will ensure that every time the sink opens a file for writing, that file has the same name. +* Use a distinct target file name pattern, preferably with date, time or counter placeholders. This will ensure that when the file is rotated and collected, it doesn't clash with the previously written files, and that the newly opened file will have a different name from the previous one. +* Disable file rotation on sink destruction. This will leave the last actively written log file in its original location and with the original name so that it can be picked up by a future run of your application. +* Prefer a stable location and file name for the actively written log files. The library will not find the previously written file if its name or directory changes between application runs. + +[endsect] + [endsect] [section:text_multifile Text multi-file backend] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index a5db499af6..d51c4416bf 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -557,7 +557,10 @@ Besides the common settings that all sinks support, some sink backends also acce [table "TextFile" sink settings [[Parameter] [Format] [Description]] [[FileName] [File name pattern] - [The file name pattern for the sink backend. This parameter is mandatory.] + [The active file name pattern for the sink backend. This parameter is mandatory.] +] +[[TargetFileName] [File name pattern] + [The target file name pattern for the sink backend. If not specified, active file name is preserved after rotation.] ] [[Format] [Format string as described [link log.detailed.utilities.setup.filter_formatter here]] [Log record formatter to be used by the sink. If not specified, the default formatter is used.] @@ -566,22 +569,22 @@ Besides the common settings that all sinks support, some sink backends also acce [Enables or disables the auto-flush feature of the backend. If not specified, the default value `false` is assumed.] ] [[Append] ["true" or "false"] - [Enables or disables appending to the existing file instead of overwriting it. If not specified, the default value `false` is assumed.] + [Enables or disables [link log.detailed.sink_backends.text_file.appending appending] to the existing file instead of overwriting it. If not specified, the default value `false` is assumed.] ] [[RotationSize] [Unsigned integer] - [File size, in bytes, upon which file rotation will be performed. If not specified, no size-based rotation will be made.] + [File size, in bytes, upon which [link log.detailed.sink_backends.text_file.file_rotation file rotation] will be performed. If not specified, no size-based rotation will be made.] ] [[RotationInterval] [Unsigned integer] - [Time interval, in seconds, upon which file rotation will be performed. See also the RotationTimePoint parameter and the note below.] + [Time interval, in seconds, upon which [link log.detailed.sink_backends.text_file.file_rotation file rotation] will be performed. See also the RotationTimePoint parameter and the note below.] ] [[RotationTimePoint] [Time point format string, see below] - [Time point or a predicate that detects at what moment of time to perform log file rotation. See also the RotationInterval parameter and the note below.] + [Time point or a predicate that detects at what moment of time to perform log [link log.detailed.sink_backends.text_file.file_rotation file rotation]. See also the RotationInterval parameter and the note below.] ] [[EnableFinalRotation] ["true" or "false"] [Enables or disables final file rotation on sink destruction, which typically happens on program termination. If not specified, the default value `true` is assumed.] ] [[Target] [File system path to a directory] - [Target directory name, in which the rotated files will be stored. If this parameter is specified, rotated file collection is enabled. Otherwise the feature is not enabled, and all corresponding parameters are ignored.] + [Target directory name, in which the rotated files will be stored. If this parameter is specified, rotated [link log.detailed.sink_backends.text_file.file_collection file collection] is enabled. Otherwise the feature is not enabled and all corresponding parameters are ignored.] ] [[MaxSize] [Unsigned integer] [Total size of files in the target directory, in bytes, upon which the oldest file will be deleted. If not specified, no size-based file cleanup will be performed.] @@ -593,7 +596,7 @@ Besides the common settings that all sinks support, some sink backends also acce [Total number of files in the target directory, upon which the oldest file will be deleted. If not specified, no count-based file cleanup will be performed.] ] [[ScanForFiles] ["All" or "Matching"] - [Mode of scanning for old files in the target directory, see [enumref boost::log::sinks::file::scan_method `scan_method`]. If not specified, no scanning will be performed.] + [Mode of [link log.detailed.sink_backends.text_file.file_scanning scanning] for old files in the target directory, see [enumref boost::log::sinks::file::scan_method `scan_method`]. If not specified, no scanning will be performed.] ] ] diff --git a/example/doc/sinks_file.cpp b/example/doc/sinks_file.cpp index 8a3b552f47..79f213b1eb 100644 --- a/example/doc/sinks_file.cpp +++ b/example/doc/sinks_file.cpp @@ -27,7 +27,8 @@ void init_logging() boost::shared_ptr< sinks::text_file_backend > backend = boost::make_shared< sinks::text_file_backend >( - keywords::file_name = "file_%5N.log", /*< file name pattern >*/ + keywords::file_name = "file.log", /*< active file name pattern >*/ + keywords::target_file_name = "file_%5N.log", /*< target file name pattern >*/ keywords::rotation_size = 5 * 1024 * 1024, /*< rotate the file upon reaching 5 MiB size... >*/ keywords::time_based_rotation = sinks::file::rotation_at_time_point(12, 0, 0) /*< ...or every day, at noon, whichever comes first >*/ ); diff --git a/example/rotating_file/main.cpp b/example/rotating_file/main.cpp index d2144c8124..bb221f6eb3 100644 --- a/example/rotating_file/main.cpp +++ b/example/rotating_file/main.cpp @@ -48,16 +48,17 @@ int main(int argc, char* argv[]) // Create a text file sink typedef sinks::synchronous_sink< sinks::text_file_backend > file_sink; shared_ptr< file_sink > sink(new file_sink( - keywords::file_name = "%Y%m%d_%H%M%S_%5N.log", // file name pattern - keywords::rotation_size = 16384 // rotation size, in characters + keywords::file_name = "file.log", // file name pattern + keywords::target_file_name = "%Y%m%d_%H%M%S_%5N.log", // file name pattern + keywords::rotation_size = 16384 // rotation size, in characters )); // Set up where the rotated files will be stored sink->locked_backend()->set_file_collector(sinks::file::make_collector( - keywords::target = "logs", // where to store rotated files - keywords::max_size = 16 * 1024 * 1024, // maximum total size of the stored files, in bytes - keywords::min_free_space = 100 * 1024 * 1024, // minimum free space on the drive, in bytes - keywords::max_files = 512 // maximum number of stored files + keywords::target = "logs", // where to store rotated files + keywords::max_size = 16 * 1024 * 1024, // maximum total size of the stored files, in bytes + keywords::min_free_space = 100 * 1024 * 1024, // minimum free space on the drive, in bytes + keywords::max_files = 512 // maximum number of stored files )); // Upon restart, scan the target directory for files matching the file_name pattern diff --git a/include/boost/log/keywords/target_file_name.hpp b/include/boost/log/keywords/target_file_name.hpp new file mode 100644 index 0000000000..ea32ec9dbd --- /dev/null +++ b/include/boost/log/keywords/target_file_name.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file keywords/target.hpp + * \author Andrey Semashev + * \date 05.01.2019 + * + * The header contains the \c target_file_name keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_TARGET_FILE_NAME_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_TARGET_FILE_NAME_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword allows to pass the target file name for file sink +BOOST_PARAMETER_KEYWORD(tag, target_file_name) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_TARGET_FILE_NAME_HPP_INCLUDED_ diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 899b5c49bc..486e55a9d7 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -371,7 +372,7 @@ class text_file_backend : * Constructor. Creates a sink backend with the specified named parameters. * The following named parameters are supported: * - * \li \c file_name - Specifies the file name pattern where logs are actually written to. The pattern may + * \li \c file_name - Specifies the active file name pattern where logs are actually written to. The pattern may * contain directory and file name portions, but only the file name may contain * placeholders. The backend supports Boost.DateTime placeholders for injecting * current time and date into the file name. Also, an additional %N placeholder is @@ -379,6 +380,10 @@ class text_file_backend : * may also contain width specification in the printf-compatible form (e.g. %5N). The * printed file counter will always be zero-filled. If \c file_name is not specified, * pattern "%5N.log" will be used. + * \li \c target_file_name - Specifies the target file name pattern to use to rename the log file on rotation, + * before passing it to the file collector. The pattern may contain the same + * placeholders as the \c file_name parameter. By default, no renaming is done, + * i.e. the written log file keeps its name according to \c file_name. * \li \c open_mode - File open mode. The mode should be presented in form of mask compatible to * std::ios_base::openmode. If not specified, trunc | out will be used. * \li \c rotation_size - Specifies the approximate size, in characters written, of the temporary file @@ -409,7 +414,7 @@ class text_file_backend : BOOST_LOG_API ~text_file_backend(); /*! - * The method sets file name wildcard for the files being written. The wildcard supports + * The method sets the active file name wildcard for the files being written. The wildcard supports * date and time injection into the file name. * * \param pattern The name pattern for the file being written. @@ -420,6 +425,22 @@ class text_file_backend : set_file_name_pattern_internal(filesystem::path(pattern)); } + /*! + * The method sets the target file name wildcard for the files being rotated. The wildcard supports + * date and time injection into the file name. + * + * This pattern will be used when the log file is being rotated, to rename the just written + * log file (which has the name according to the pattern in the \c file_name constructor parameter or + * set by a call to \c set_file_name_pattern), just before passing the file to the file collector. + * + * \param pattern The name pattern for the file being rotated. + */ + template< typename PathT > + void set_target_file_name_pattern(PathT const& pattern) + { + set_target_file_name_pattern_internal(filesystem::path(pattern)); + } + /*! * The method sets the file open mode * @@ -502,7 +523,7 @@ class text_file_backend : * as if they were rotated. * * The file scan can be performed in two ways: either all files in the target directory will - * be considered as log files, or only those files that satisfy the file name pattern. + * be considered as log files, or only those files that satisfy the target file name pattern. * See documentation on sinks::file::collector::scan_for_files for more information. * * \pre File collector and the proper file name pattern have already been set. @@ -541,6 +562,7 @@ class text_file_backend : { construct( filesystem::path(args[keywords::file_name | filesystem::path()]), + filesystem::path(args[keywords::target_file_name | filesystem::path()]), args[keywords::open_mode | (std::ios_base::trunc | std::ios_base::out)], args[keywords::rotation_size | (std::numeric_limits< uintmax_t >::max)()], args[keywords::time_based_rotation | time_based_rotation_predicate()], @@ -550,14 +572,17 @@ class text_file_backend : //! Constructor implementation BOOST_LOG_API void construct( filesystem::path const& pattern, + filesystem::path const& target_file_name, std::ios_base::openmode mode, uintmax_t rotation_size, time_based_rotation_predicate const& time_based_rotation, bool auto_flush, bool enable_final_rotation); - //! The method sets file name mask + //! The method sets file name pattern BOOST_LOG_API void set_file_name_pattern_internal(filesystem::path const& pattern); + //! The method sets target file name pattern + BOOST_LOG_API void set_target_file_name_pattern_internal(filesystem::path const& pattern); //! Closes the currently open file void close_file(); diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index f559174f83..361799b6bf 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -134,7 +134,11 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, BOOST_LOG_INIT_LOG_TO_F * The function initializes the logging library to write logs to a file stream. * * \param args A number of named arguments. The following parameters are supported: - * \li \c file_name The file name or its pattern. This parameter is mandatory. + * \li \c file_name The active file name or its pattern. This parameter is mandatory. + * \li \c target_file_name - Specifies the target file name pattern to use to rename the log file on rotation, + * before passing it to the file collector. The pattern may contain the same + * placeholders as the \c file_name parameter. By default, no renaming is done, + * i.e. the written log file keeps its name according to \c file_name. * \li \c open_mode The mask that describes the open mode for the file. See std::ios_base::openmode. * \li \c rotation_size The size of the file at which rotation should occur. See basic_text_file_backend. * \li \c time_based_rotation The predicate for time-based file rotations. See basic_text_file_backend. diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 67d341a259..f49c9a2a3c 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -439,6 +439,12 @@ class default_text_file_sink_factory : else BOOST_LOG_THROW_DESCR(missing_value, "File name is not specified"); + // Target file name + if (optional< string_type > target_file_name_param = params["TargetFileName"]) + { + backend->set_target_file_name_pattern(filesystem::path(target_file_name_param.get())); + } + // File rotation size if (optional< string_type > rotation_size_param = params["RotationSize"]) { diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 7f8d76f81e..9006ff9cab 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -89,7 +89,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::rename(from, to, ec); if (ec) { - if (ec.value() == system::errc::cross_device_link) + if (BOOST_LIKELY(ec.value() == system::errc::cross_device_link)) { // Attempt to manually move the file instead filesystem::copy_file(from, to); @@ -466,7 +466,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { path_string_type::const_iterator p = p_it; unsigned int width = 0; - if (!parse_counter_placeholder(p, p_end, width)) + if (!sinks::parse_counter_placeholder(p, p_end, width)) { BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported placeholder used in pattern for file scanning")); } @@ -506,6 +506,87 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { return false; } + //! The function parses file name pattern and splits it into path and filename and creates a function object that will generate the actual filename from the pattern + void parse_file_name_pattern(filesystem::path const& pattern, filesystem::path& storage_dir, filesystem::path& file_name_pattern, boost::log::aux::light_function< path_string_type (unsigned int) >& file_name_generator) + { + // Note: avoid calling Boost.Filesystem functions that involve path::codecvt() + // https://svn.boost.org/trac/boost/ticket/9119 + + typedef file_char_traits< path_char_type > traits_t; + + file_name_pattern = pattern.filename(); + path_string_type name_pattern = file_name_pattern.native(); + storage_dir = filesystem::absolute(pattern.parent_path()); + + // Let's try to find the file counter placeholder + unsigned int placeholder_count = 0; + unsigned int width = 0; + bool counter_found = false; + path_string_type::size_type counter_pos = 0; + path_string_type::const_iterator end = name_pattern.end(); + path_string_type::const_iterator it = name_pattern.begin(); + + do + { + it = std::find(it, end, traits_t::percent); + if (it == end) + break; + path_string_type::const_iterator placeholder_begin = it++; + if (it == end) + break; + if (*it == traits_t::percent) + { + // An escaped percent detected + ++it; + continue; + } + + ++placeholder_count; + + if (!counter_found) + { + path_string_type::const_iterator it2 = it; + if (sinks::parse_counter_placeholder(it2, end, width)) + { + // We've found the file counter placeholder in the pattern + counter_found = true; + counter_pos = placeholder_begin - name_pattern.begin(); + name_pattern.erase(counter_pos, it2 - placeholder_begin); + --placeholder_count; + it = name_pattern.begin() + counter_pos; + end = name_pattern.end(); + } + } + } + while (it != end); + + // Construct the formatter functor + if (placeholder_count > 0) + { + if (counter_found) + { + // Both counter and date/time placeholder in the pattern + file_name_generator = boost::bind(date_and_time_formatter(), + boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1), _1); + } + else + { + // Only date/time placeholders in the pattern + file_name_generator = boost::bind(date_and_time_formatter(), name_pattern, _1); + } + } + else if (counter_found) + { + // Only counter placeholder in the pattern + file_name_generator = boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1); + } + else + { + // No placeholders detected + file_name_generator = empty_formatter(name_pattern); + } + } + class file_collector_repository; @@ -795,7 +876,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (!is_in_target_dir) { // Move/rename the file to the target storage - move_file(src_path, info.m_Path); + sinks::move_file(src_path, info.m_Path); } m_Files.push_back(info); @@ -856,7 +937,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { unsigned int file_number = 0; bool file_number_parsed = false; if (method != file::scan_matching || - match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed)) + sinks::match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed)) { info.m_Size = filesystem::file_size(info.m_Path); total_size += info.m_Size; @@ -932,19 +1013,19 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Checks if the time point is valid void check_time_point_validity(unsigned char hour, unsigned char minute, unsigned char second) { - if (hour >= 24) + if (BOOST_UNLIKELY(hour >= 24)) { std::ostringstream strm; strm << "Time point hours value is out of range: " << static_cast< unsigned int >(hour); BOOST_THROW_EXCEPTION(std::out_of_range(strm.str())); } - if (minute >= 60) + if (BOOST_UNLIKELY(minute >= 60)) { std::ostringstream strm; strm << "Time point minutes value is out of range: " << static_cast< unsigned int >(minute); BOOST_THROW_EXCEPTION(std::out_of_range(strm.str())); } - if (second >= 60) + if (BOOST_UNLIKELY(second >= 60)) { std::ostringstream strm; strm << "Time point seconds value is out of range: " << static_cast< unsigned int >(second); @@ -983,7 +1064,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - check_time_point_validity(hour, minute, second); + sinks::check_time_point_validity(hour, minute, second); } //! Creates a rotation time point of each specified weekday at the specified time @@ -1000,7 +1081,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - check_time_point_validity(hour, minute, second); + sinks::check_time_point_validity(hour, minute, second); } //! Creates a rotation time point of each specified day of month at the specified time @@ -1017,7 +1098,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - check_time_point_validity(hour, minute, second); + sinks::check_time_point_validity(hour, minute, second); } //! Checks if it's time to rotate the file @@ -1130,6 +1211,13 @@ struct text_file_backend::implementation //! File name generator (according to m_FileNamePattern) boost::log::aux::light_function< path_string_type (unsigned int) > m_FileNameGenerator; + //! Target file name pattern + filesystem::path m_TargetFileNamePattern; + //! Target directory to store files in + filesystem::path m_TargetStorageDir; + //! Target file name generator (according to m_TargetFileNamePattern) + boost::log::aux::light_function< path_string_type (unsigned int) > m_TargetFileNameGenerator; + //! Stored files counter unsigned int m_FileCounter; @@ -1192,6 +1280,7 @@ BOOST_LOG_API text_file_backend::~text_file_backend() //! Constructor implementation BOOST_LOG_API void text_file_backend::construct( filesystem::path const& pattern, + filesystem::path const& target_file_name, std::ios_base::openmode mode, uintmax_t rotation_size, time_based_rotation_predicate const& time_based_rotation, @@ -1200,6 +1289,7 @@ BOOST_LOG_API void text_file_backend::construct( { m_pImpl = new implementation(rotation_size, auto_flush, enable_final_rotation); set_file_name_pattern_internal(pattern); + set_target_file_name_pattern_internal(target_file_name); set_time_based_rotation(time_based_rotation); set_open_mode(mode); } @@ -1311,89 +1401,32 @@ BOOST_LOG_API void text_file_backend::flush() m_pImpl->m_File.flush(); } -//! The method sets file name mask +//! The method sets file name pattern BOOST_LOG_API void text_file_backend::set_file_name_pattern_internal(filesystem::path const& pattern) { - // Note: avoid calling Boost.Filesystem functions that involve path::codecvt() - // https://svn.boost.org/trac/boost/ticket/9119 - typedef file_char_traits< path_char_type > traits_t; - filesystem::path p = pattern; - if (p.empty()) - p = filesystem::path(traits_t::default_file_name_pattern()); - - m_pImpl->m_FileNamePattern = p.filename(); - path_string_type name_pattern = m_pImpl->m_FileNamePattern.native(); - m_pImpl->m_StorageDir = filesystem::absolute(p.parent_path()); - - // Let's try to find the file counter placeholder - unsigned int placeholder_count = 0; - unsigned int width = 0; - bool counter_found = false; - path_string_type::size_type counter_pos = 0; - path_string_type::const_iterator end = name_pattern.end(); - path_string_type::const_iterator it = name_pattern.begin(); - - do - { - it = std::find(it, end, traits_t::percent); - if (it == end) - break; - path_string_type::const_iterator placeholder_begin = it++; - if (it == end) - break; - if (*it == traits_t::percent) - { - // An escaped percent detected - ++it; - continue; - } - - ++placeholder_count; - if (!counter_found) - { - path_string_type::const_iterator it2 = it; - if (parse_counter_placeholder(it2, end, width)) - { - // We've found the file counter placeholder in the pattern - counter_found = true; - counter_pos = placeholder_begin - name_pattern.begin(); - name_pattern.erase(counter_pos, it2 - placeholder_begin); - --placeholder_count; - it = name_pattern.begin() + counter_pos; - end = name_pattern.end(); - } - } - } - while (it != end); + sinks::parse_file_name_pattern + ( + !pattern.empty() ? pattern : filesystem::path(traits_t::default_file_name_pattern()), + m_pImpl->m_StorageDir, + m_pImpl->m_FileNamePattern, + m_pImpl->m_FileNameGenerator + ); +} - // Construct the formatter functor - if (placeholder_count > 0) - { - if (counter_found) - { - // Both counter and date/time placeholder in the pattern - m_pImpl->m_FileNameGenerator = boost::bind(date_and_time_formatter(), - boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1), _1); - } - else - { - // Only date/time placeholders in the pattern - m_pImpl->m_FileNameGenerator = - boost::bind(date_and_time_formatter(), name_pattern, _1); - } - } - else if (counter_found) +//! The method sets target file name pattern +BOOST_LOG_API void text_file_backend::set_target_file_name_pattern_internal(filesystem::path const& pattern) +{ + if (!pattern.empty()) { - // Only counter placeholder in the pattern - m_pImpl->m_FileNameGenerator = - boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1); + sinks::parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator); } else { - // No placeholders detected - m_pImpl->m_FileNameGenerator = empty_formatter(name_pattern); + m_pImpl->m_TargetStorageDir.clear(); + m_pImpl->m_TargetFileNamePattern.clear(); + m_pImpl->m_TargetFileNameGenerator.clear(); } } @@ -1428,6 +1461,20 @@ BOOST_LOG_API void text_file_backend::rotate_file() filesystem::path prev_file_name = m_pImpl->m_FileName; close_file(); + if (!!m_pImpl->m_TargetFileNameGenerator) + { + filesystem::path new_file_name; + new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); + + if (new_file_name != prev_file_name) + { + filesystem::create_directories(new_file_name.parent_path()); + sinks::move_file(prev_file_name, new_file_name); + + prev_file_name.swap(new_file_name); + } + } + if (!!m_pImpl->m_pFileCollector) { // Check if the file has not been deleted by another process @@ -1475,10 +1522,15 @@ BOOST_LOG_API filesystem::path text_file_backend::get_current_file_name() const //! Performs scanning of the target directory for log files BOOST_LOG_API uintmax_t text_file_backend::scan_for_files(file::scan_method method, bool update_counter) { - if (m_pImpl->m_pFileCollector) + if (BOOST_LIKELY(!!m_pImpl->m_pFileCollector)) { unsigned int* counter = update_counter ? &m_pImpl->m_FileCounter : static_cast< unsigned int* >(NULL); - return m_pImpl->m_pFileCollector->scan_for_files(method, m_pImpl->m_FileNamePattern, counter); + return m_pImpl->m_pFileCollector->scan_for_files + ( + method, + m_pImpl->m_TargetFileNamePattern.empty() ? m_pImpl->m_FileNamePattern : m_pImpl->m_TargetFileNamePattern, + counter + ); } else { From 5ed3f69c3b8beca6454347de9bf43e0c4f4c6bd6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 21:50:29 +0300 Subject: [PATCH 011/309] Disabled OS X CI jobs because of timeouts. --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index f48fb38542..5b182eb228 100644 --- a/.travis.yml +++ b/.travis.yml @@ -259,13 +259,14 @@ matrix: - libc++-dev # clang, OS X - - os: osx - env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 EXTRA_TESTS=1 - osx_image: xcode10.1 - - - os: osx - env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z - osx_image: xcode10.1 +# OS X jobs time out for some reason +# - os: osx +# env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 EXTRA_TESTS=1 +# osx_image: xcode10.1 +# +# - os: osx +# env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z +# osx_image: xcode10.1 install: From 691859e288014864063aafc163fdb4845d225b92 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 5 Jan 2019 21:57:42 +0300 Subject: [PATCH 012/309] Trying to work around cmd quirks with variable expansion. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index fd5a8cbf07..6c2fa23727 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -97,7 +97,7 @@ install: - git submodule init libs/config - git submodule update --jobs %GIT_FETCH_JOBS% - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\log - - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES=--include;example + - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include=example" - python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" log - cmd /c bootstrap - b2 headers From 958ced0edd756b466bb4204306b5553fec286822 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 02:00:44 +0300 Subject: [PATCH 013/309] Work around MSVC name lookup bugs. The compiler fails to find a symbol defined in an anonymous namespace, if the name is qualified up to the namespace enclosing the anonymous namespace. --- src/text_file_backend.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 9006ff9cab..cef1c8dee7 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -466,7 +466,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { path_string_type::const_iterator p = p_it; unsigned int width = 0; - if (!sinks::parse_counter_placeholder(p, p_end, width)) + if (!parse_counter_placeholder(p, p_end, width)) { BOOST_THROW_EXCEPTION(std::invalid_argument("Unsupported placeholder used in pattern for file scanning")); } @@ -546,7 +546,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (!counter_found) { path_string_type::const_iterator it2 = it; - if (sinks::parse_counter_placeholder(it2, end, width)) + if (parse_counter_placeholder(it2, end, width)) { // We've found the file counter placeholder in the pattern counter_found = true; @@ -876,7 +876,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (!is_in_target_dir) { // Move/rename the file to the target storage - sinks::move_file(src_path, info.m_Path); + move_file(src_path, info.m_Path); } m_Files.push_back(info); @@ -937,7 +937,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { unsigned int file_number = 0; bool file_number_parsed = false; if (method != file::scan_matching || - sinks::match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed)) + match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed)) { info.m_Size = filesystem::file_size(info.m_Path); total_size += info.m_Size; @@ -1064,7 +1064,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - sinks::check_time_point_validity(hour, minute, second); + check_time_point_validity(hour, minute, second); } //! Creates a rotation time point of each specified weekday at the specified time @@ -1081,7 +1081,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - sinks::check_time_point_validity(hour, minute, second); + check_time_point_validity(hour, minute, second); } //! Creates a rotation time point of each specified day of month at the specified time @@ -1098,7 +1098,7 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( m_Second(second), m_Previous(date_time::not_a_date_time) { - sinks::check_time_point_validity(hour, minute, second); + check_time_point_validity(hour, minute, second); } //! Checks if it's time to rotate the file @@ -1406,7 +1406,7 @@ BOOST_LOG_API void text_file_backend::set_file_name_pattern_internal(filesystem: { typedef file_char_traits< path_char_type > traits_t; - sinks::parse_file_name_pattern + parse_file_name_pattern ( !pattern.empty() ? pattern : filesystem::path(traits_t::default_file_name_pattern()), m_pImpl->m_StorageDir, @@ -1420,7 +1420,7 @@ BOOST_LOG_API void text_file_backend::set_target_file_name_pattern_internal(file { if (!pattern.empty()) { - sinks::parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator); + parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator); } else { @@ -1469,7 +1469,7 @@ BOOST_LOG_API void text_file_backend::rotate_file() if (new_file_name != prev_file_name) { filesystem::create_directories(new_file_name.parent_path()); - sinks::move_file(prev_file_name, new_file_name); + move_file(prev_file_name, new_file_name); prev_file_name.swap(new_file_name); } From 61639024c980b019e235de65ac0784bd929ee9a9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 02:10:12 +0300 Subject: [PATCH 014/309] Added _XOPEN_SOURCE=600 define for Cygwin, which is needed for pthread rwlocks. --- build/log-platform-config.jam | 1 + 1 file changed, 1 insertion(+) diff --git a/build/log-platform-config.jam b/build/log-platform-config.jam index de776c29e2..cee01cc100 100644 --- a/build/log-platform-config.jam +++ b/build/log-platform-config.jam @@ -32,6 +32,7 @@ rule set-platform-defines ( properties * ) if cygwin in $(properties) { result += __USE_W32_SOCKETS ; + result += _XOPEN_SOURCE=600 ; } } else if solaris in $(properties) From 947d4361d4a9af980271c74fd11c270ab6157f45 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 02:17:19 +0300 Subject: [PATCH 015/309] Added a check for message compiler on Windows when building examples. Disable event log examples when message compiler is not available. This should hopefully fix MinGW failures in CI. --- example/doc/Jamfile.v2 | 56 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 10 deletions(-) diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index ead4e80c94..71ab56b542 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -6,9 +6,45 @@ # import path ; +import configure ; + +rule has-config-flag ( flag : properties * ) +{ + if ( "$(flag)" in $(properties) || "$(flag)=1" in $(properties) ) + { + return 1 ; + } + else + { + return ; + } +} + +rule check-message-compiler ( properties * ) +{ + local result ; + + if windows in $(properties) + { + if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] + { + local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ; + if ! $(has_mc) + { + result += BOOST_LOG_WITHOUT_EVENT_LOG=1 ; + } + } + } + else + { + result += BOOST_LOG_WITHOUT_EVENT_LOG=1 ; + } +} project : requirements + @check-message-compiler + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE @@ -55,17 +91,17 @@ project # Compiles each .cpp file in this directory into a separate executable rule compile_all { - #ECHO executing compile_all rule ; - local all_rules = ; - for local file in [ glob *.cpp ] - { - local exename = [ MATCH "([^.]*).cpp$" : [ path.basename $(file) ] ] ; - #ECHO "exename = $(exename)" ; - all_rules += [ exe $(exename) : $(file) ] ; - } + #ECHO executing compile_all rule ; + local all_rules = ; + for local file in [ glob *.cpp ] + { + local exename = [ MATCH "([^.]*).cpp$" : [ path.basename $(file) ] ] ; + #ECHO "exename = $(exename)" ; + all_rules += [ exe $(exename) : $(file) ] ; + } - #ECHO $(all_rules) ; - return $(all_rules) ; + #ECHO $(all_rules) ; + return $(all_rules) ; } compile_all ; From 136fd2bdfd4d5fad706153d934cfab41afd821fa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 14:13:32 +0300 Subject: [PATCH 016/309] CI compilation fixes for Cygwin and MinGW. Some tests pull in pthread rwlock and therefore need _XOPEN_SOURCE=600 or higher to compile. Added platform defines to tests and examples for good measure. For MinGW worked around Boost.Build error when BOOST_LOG_WITHOUT_EVENT_LOG is defined. --- example/advanced_usage/Jamfile.v2 | 4 ++++ example/async_log/Jamfile.v2 | 4 ++++ example/basic_usage/Jamfile.v2 | 4 ++++ example/bounded_async_log/Jamfile.v2 | 4 ++++ example/doc/Jamfile.v2 | 13 +++++++++++-- example/event_log/Jamfile.v2 | 4 ++++ example/keywords/Jamfile.v2 | 4 ++++ example/multiple_files/Jamfile.v2 | 4 ++++ example/multiple_threads/Jamfile.v2 | 4 ++++ example/native_syslog/Jamfile.v2 | 4 ++++ example/rotating_file/Jamfile.v2 | 4 ++++ example/settings_file/Jamfile.v2 | 4 ++++ example/settings_file_formatter_factory/Jamfile.v2 | 4 ++++ example/syslog/Jamfile.v2 | 4 ++++ example/trivial/Jamfile.v2 | 4 ++++ example/wide_char/Jamfile.v2 | 4 ++++ test/Jamfile.v2 | 3 +++ 17 files changed, 74 insertions(+), 2 deletions(-) diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index 03ea037964..b0ed79c0d3 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index 7af11ffeb8..29073a900e 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index b46fd3e0d5..9c741b6af3 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index be5887e517..9948059e9b 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 71ab56b542..8dd6146040 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -7,6 +7,7 @@ import path ; import configure ; +import ../../build/log-platform-config ; rule has-config-flag ( flag : properties * ) { @@ -31,18 +32,26 @@ rule check-message-compiler ( properties * ) local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ; if ! $(has_mc) { - result += BOOST_LOG_WITHOUT_EVENT_LOG=1 ; + result = BOOST_LOG_WITHOUT_EVENT_LOG ; } } + else + { + # This branch is needed to fix building with MinGW + result = BOOST_LOG_WITHOUT_EVENT_LOG ; + } } else { - result += BOOST_LOG_WITHOUT_EVENT_LOG=1 ; + result = BOOST_LOG_WITHOUT_EVENT_LOG ; } + + return $(result) ; } project : requirements + @log-platform-config.set-platform-defines @check-message-compiler shared:BOOST_ALL_DYN_LINK diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index c14b289608..157ab205ee 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -7,6 +7,7 @@ import os ; import configure ; +import ../../build/log-platform-config ; rule has-config-flag ( flag : properties * ) { @@ -39,10 +40,13 @@ rule check-message-compiler ( properties * ) { result += no ; } + + return $(result) ; } project : requirements + @log-platform-config.set-platform-defines @check-message-compiler shared diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index 1e4a40cb56..3f433869d9 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index 29566c3f1c..1bdecd49cf 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 66dc00f01e..0cfce3211d 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index 3ec07049bb..0a65fbe9ee 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index a9b4748bba..4087748fa4 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index d5ce605a1e..4d25379826 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/settings_file_formatter_factory/Jamfile.v2 b/example/settings_file_formatter_factory/Jamfile.v2 index 6098f8a35b..087908121f 100644 --- a/example/settings_file_formatter_factory/Jamfile.v2 +++ b/example/settings_file_formatter_factory/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index 2632be9bc0..56827995d1 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 7ea90e1d41..2ca6571e9a 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index ea89208d12..e2ea1fafb3 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -5,8 +5,12 @@ # http://www.boost.org/LICENSE_1_0.txt) # +import ../../build/log-platform-config ; + project : requirements + @log-platform-config.set-platform-defines + shared:BOOST_ALL_DYN_LINK msvc:_SCL_SECURE_NO_WARNINGS msvc:_SCL_SECURE_NO_DEPRECATE diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 422857fd60..671b5ba4bc 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -10,9 +10,12 @@ import testing ; import path ; import regex ; import os ; +import ../build/log-platform-config ; project : requirements + @log-platform-config.set-platform-defines + common # Disable warnings about using 'insecure' standard C functions From fae655dbbd6f63843d0b3335903746920a3cc3e9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 19:51:37 +0300 Subject: [PATCH 017/309] Don't use Boost.ASIO-related features in examples when Boost.ASIO is not available. --- example/syslog/main.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/example/syslog/main.cpp b/example/syslog/main.cpp index e95c1fa756..18db091955 100644 --- a/example/syslog/main.cpp +++ b/example/syslog/main.cpp @@ -73,8 +73,10 @@ int main(int argc, char* argv[]) sink->locked_backend()->set_severity_mapper(mapping); +#if !defined(BOOST_LOG_NO_ASIO) // Set the remote address to sent syslog messages to sink->locked_backend()->set_target_address("localhost"); +#endif // Add the sink to the core logging::core::get()->add_sink(sink); From effd8568a4c71bdde12dcb249e91938556927506 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 6 Jan 2019 19:51:48 +0300 Subject: [PATCH 018/309] Disable Boost.Interprocess on Cygwin. Boost.Interprocess doesn't compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 Also, disable affected tests and examples. --- build/Jamfile.v2 | 2 ++ example/doc/Jamfile.v2 | 3 +++ example/doc/sinks_ipc_logger.cpp | 11 +++++++++++ example/doc/sinks_ipc_receiver.cpp | 11 +++++++++++ example/doc/util_ipc_reliable_mq_writer.cpp | 11 +++++++++++ test/Jamfile.v2 | 3 +++ test/run/sink_text_ipc_mq_backend.cpp | 11 +++++++++++ test/run/util_ipc_object_name.cpp | 11 +++++++++++ test/run/util_ipc_reliable_mq.cpp | 11 +++++++++++ 9 files changed, 74 insertions(+) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 27a7d6fe80..45695d427f 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -227,6 +227,8 @@ project boost/log cygwin:ws2_32 cygwin:mswsock cygwin:advapi32 + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + cygwin:BOOST_LOG_WITHOUT_IPC linux:rt diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 8dd6146040..850f4f74a3 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -88,6 +88,9 @@ project intel-linux:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" intel-darwin:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + cygwin:BOOST_LOG_WITHOUT_IPC + /boost/log//boost_log /boost/log//boost_log_setup /boost/date_time//boost_date_time diff --git a/example/doc/sinks_ipc_logger.cpp b/example/doc/sinks_ipc_logger.cpp index f5adeb23db..d203370ad9 100644 --- a/example/doc/sinks_ipc_logger.cpp +++ b/example/doc/sinks_ipc_logger.cpp @@ -6,6 +6,8 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #include #include #include @@ -81,3 +83,12 @@ int main() return 0; } //] + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) diff --git a/example/doc/sinks_ipc_receiver.cpp b/example/doc/sinks_ipc_receiver.cpp index 70e304693c..9fb4a7b724 100644 --- a/example/doc/sinks_ipc_receiver.cpp +++ b/example/doc/sinks_ipc_receiver.cpp @@ -6,6 +6,8 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #include #include #include @@ -55,3 +57,12 @@ int main() return 0; } //] + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) diff --git a/example/doc/util_ipc_reliable_mq_writer.cpp b/example/doc/util_ipc_reliable_mq_writer.cpp index 13c7457393..737adc3582 100644 --- a/example/doc/util_ipc_reliable_mq_writer.cpp +++ b/example/doc/util_ipc_reliable_mq_writer.cpp @@ -5,6 +5,8 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #include #include #include @@ -79,3 +81,12 @@ int main() return 0; } //] + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 671b5ba4bc..ffea968bf3 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -56,6 +56,9 @@ project gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + cygwin:BOOST_LOG_WITHOUT_IPC + /boost/log//boost_log /boost/log//boost_log_setup /boost/date_time//boost_date_time diff --git a/test/run/sink_text_ipc_mq_backend.cpp b/test/run/sink_text_ipc_mq_backend.cpp index e94463e6e9..e26f53a88b 100644 --- a/test/run/sink_text_ipc_mq_backend.cpp +++ b/test/run/sink_text_ipc_mq_backend.cpp @@ -14,6 +14,8 @@ * \brief The test verifies that \c text_ipc_message_queue_backend works as expected. */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #define BOOST_TEST_MODULE sink_text_ipc_mq_backend #include @@ -54,3 +56,12 @@ BOOST_AUTO_TEST_CASE(text_ipc_message_queue_backend) BOOST_CHECK(queue.try_receive(msg)); BOOST_CHECK(equal_strings(msg, message)); } + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) diff --git a/test/run/util_ipc_object_name.cpp b/test/run/util_ipc_object_name.cpp index 42ad03c7d5..11e63e852a 100644 --- a/test/run/util_ipc_object_name.cpp +++ b/test/run/util_ipc_object_name.cpp @@ -12,6 +12,8 @@ * \brief The test verifies that \c ipc::object_name works. */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #define BOOST_TEST_MODULE util_ipc_object_name #include @@ -164,3 +166,12 @@ BOOST_AUTO_TEST_CASE(name_equivalence) BOOST_CHECK_NE(name1, name2); } } + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index d4b68ff865..3886572933 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -14,6 +14,8 @@ * \brief The test verifies that \c ipc::reliable_message_queue works. */ +#if !defined(BOOST_LOG_WITHOUT_IPC) + #define BOOST_TEST_MODULE util_ipc_reliable_mq #include @@ -461,3 +463,12 @@ BOOST_AUTO_TEST_CASE(stop_reset_local) } #endif // !defined(BOOST_LOG_NO_THREADS) + +#else // !defined(BOOST_LOG_WITHOUT_IPC) + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_LOG_WITHOUT_IPC) From 3e6fee47518f324a9eac14f7908742d02db9f09d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Jan 2019 00:56:24 +0300 Subject: [PATCH 019/309] Counter compiler optimizations when checking for SSSE3 and AVX2. The compiler is able to optimize away most of the instructions that we test, which results in checking only the compiler support for intrinsics, and not the assembler capability to translate SSSE3 and AVX2 instructions from assembler into the actual binary code. This commit forces the compiler to actually emit instructions in the assembler, which then tests binutils capability to translate those into binary code. --- config/x86-ext/avx2.cpp | 4 ++++ config/x86-ext/ssse3.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/config/x86-ext/avx2.cpp b/config/x86-ext/avx2.cpp index fcc1b9215e..3ee051f173 100644 --- a/config/x86-ext/avx2.cpp +++ b/config/x86-ext/avx2.cpp @@ -7,10 +7,14 @@ #include +void pretend_used(__m256i*); + int main(int, char*[]) { __m256i mm = _mm256_setzero_si256(); + pretend_used(&mm); mm = _mm256_shuffle_epi8(_mm256_alignr_epi8(mm, mm, 10), mm); + pretend_used(&mm); _mm256_zeroupper(); return 0; } diff --git a/config/x86-ext/ssse3.cpp b/config/x86-ext/ssse3.cpp index f7bfb30847..4bcfe2bc75 100644 --- a/config/x86-ext/ssse3.cpp +++ b/config/x86-ext/ssse3.cpp @@ -7,9 +7,13 @@ #include +void pretend_used(__m128i*); + int main(int, char*[]) { __m128i mm = _mm_setzero_si128(); + pretend_used(&mm); mm = _mm_shuffle_epi8(_mm_alignr_epi8(mm, mm, 10), mm); + pretend_used(&mm); return 0; } From 1138b47fce14281511de8f5785430eefea96f157 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 14 Jan 2019 20:16:20 +0300 Subject: [PATCH 020/309] Removed linking with Boost.System. Since Boost.System is now header-only, no need to link with the library. --- build/Jamfile.v2 | 1 - example/advanced_usage/Jamfile.v2 | 1 - example/async_log/Jamfile.v2 | 1 - example/basic_usage/Jamfile.v2 | 1 - example/bounded_async_log/Jamfile.v2 | 1 - example/doc/Jamfile.v2 | 1 - example/event_log/Jamfile.v2 | 1 - example/keywords/Jamfile.v2 | 1 - example/multiple_files/Jamfile.v2 | 1 - example/multiple_threads/Jamfile.v2 | 1 - example/native_syslog/Jamfile.v2 | 1 - example/rotating_file/Jamfile.v2 | 1 - example/settings_file/Jamfile.v2 | 1 - example/settings_file_formatter_factory/Jamfile.v2 | 1 - example/syslog/Jamfile.v2 | 1 - example/trivial/Jamfile.v2 | 1 - example/wide_char/Jamfile.v2 | 1 - test/Jamfile.v2 | 1 - 18 files changed, 18 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 45695d427f..a172767ab5 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -215,7 +215,6 @@ project boost/log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/atomic//boost_atomic multi:/boost/thread//boost_thread diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index b0ed79c0d3..542bd18b6d 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index 29073a900e..bb2438d433 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index 9c741b6af3..56a9d5eb5a 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -49,7 +49,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread ; diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index 9948059e9b..36e47a29a1 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 850f4f74a3..1ef9938880 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -95,7 +95,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index 157ab205ee..bcc17f46b4 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -86,7 +86,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index 3f433869d9..54db6e1126 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -49,7 +49,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread ; diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index 1bdecd49cf..81e3e5dda1 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 0cfce3211d..269a0cb795 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index 0a65fbe9ee..51ee1c2e15 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index 4087748fa4..f91c942ebe 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index 4d25379826..8459f7d76f 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -49,7 +49,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread ; diff --git a/example/settings_file_formatter_factory/Jamfile.v2 b/example/settings_file_formatter_factory/Jamfile.v2 index 087908121f..540d97ceaa 100644 --- a/example/settings_file_formatter_factory/Jamfile.v2 +++ b/example/settings_file_formatter_factory/Jamfile.v2 @@ -49,7 +49,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread ; diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index 56827995d1..a4d1a97108 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/thread//boost_thread multi ; diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 2ca6571e9a..3a02bf3832 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -48,7 +48,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread ; diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index e2ea1fafb3..7a3c518edd 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -49,7 +49,6 @@ project /boost/log//boost_log_setup /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/locale//boost_locale /boost/thread//boost_thread multi diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ffea968bf3..1124693230 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -64,7 +64,6 @@ project /boost/date_time//boost_date_time /boost/regex//boost_regex /boost/filesystem//boost_filesystem - /boost/system//boost_system /boost/test//boost_unit_test_framework single:BOOST_LOG_NO_THREADS multi:/boost/thread//boost_thread From e21753da4e4fae650e35b96c3d23b9ea493ffb35 Mon Sep 17 00:00:00 2001 From: Adrien Date: Tue, 15 Jan 2019 14:08:06 +0100 Subject: [PATCH 021/309] Fixes typo in the tutorial, "formatter" being used in place of "filter" --- doc/tutorial.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index cc5734227c..bf81b443a1 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -340,7 +340,7 @@ Like with formatters, it is also possible to use custom functions as filters. __ [example_tutorial_filtering_bind] -As you can see, the custom formatter receives attribute values wrapped into the [link log.detailed.utilities.value_ref `value_ref`] template. This wrapper contains an optional reference to the attribute value of the specified type; the reference is valid if the log record contains the attribute value of the required type. The relational operators used in `my_filter` can be applied unconditionally because they will automatically return `false` if the reference is not valid. The rest is done with the `bind` expression which will recognize the `severity` and `tag_attr` keywords and extract the corresponding values before passing them to `my_filter`. +As you can see, the custom filter receives attribute values wrapped into the [link log.detailed.utilities.value_ref `value_ref`] template. This wrapper contains an optional reference to the attribute value of the specified type; the reference is valid if the log record contains the attribute value of the required type. The relational operators used in `my_filter` can be applied unconditionally because they will automatically return `false` if the reference is not valid. The rest is done with the `bind` expression which will recognize the `severity` and `tag_attr` keywords and extract the corresponding values before passing them to `my_filter`. [note Because of limitations related to the integration with __boost_phoenix__ (see [ticket 7996]), it is required to explicitly specify the fallback policy in case if the attribute value is missing, when attribute keywords are used with `phoenix::bind` or `phoenix::function`. In the example above, this is done by calling `or_none`, which results in an empty [link log.detailed.utilities.value_ref `value_ref`] if the value is not found. In other contexts this policy is the default. There are [link log.detailed.expressions.attr.fallback_policies other policies] that can be used instead.] From 2dd530b8c303ad0aa150faf2ec85605b3b36dc50 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 16 Jan 2019 23:57:25 +0300 Subject: [PATCH 022/309] Work around Boost.Parameter difference between develop and master for file_name. This commit reworks file_name parameter handling for the file sink setup helper. Boost.Parameter was modified recently in develop, which made it incompatible with the previous implementation of the file_name helpers. At the same time, it has not been merged to master, and the master version is not compatible with the new implementation. To resolve this, avoid mentioning the actual type of the tagged argument constructed from the assignment to the named parameter keyword. This type refers to Boost.Parameter implementation details namespace, so as a bonus we reduce the dependency on Boost.Parameter implementation details. See: https://github.com/boostorg/parameter/issues/65 --- include/boost/log/utility/setup/file.hpp | 46 +++++++++++++++++------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index 361799b6bf..b66f06c2cc 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -15,9 +15,11 @@ #ifndef BOOST_LOG_UTILITY_SETUP_FILE_HPP_INCLUDED_ #define BOOST_LOG_UTILITY_SETUP_FILE_HPP_INCLUDED_ +#include #include #include #include // for is_named_argument +#include #include #include #include @@ -96,18 +98,36 @@ shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > return pSink; } -//! The function wraps the argument into a file_name named argument, if needed -template< typename T > -inline T const& wrap_file_name(T const& arg, mpl::true_) +//! The trait wraps the argument into a file_name named argument, if needed +template< typename T, bool IsNamedArgument = parameter::aux::is_named_argument< T >::value > +struct file_name_param_traits { - return arg; -} + static shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > wrap_add_file_log(T const& file_name_arg) + { + return aux::add_file_log(file_name_arg); + } + + template< typename ArgsT > + static shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > wrap_add_file_log(T const& file_name_arg, ArgsT const& args) + { + return aux::add_file_log((args, file_name_arg)); + } +}; + template< typename T > -inline typename parameter::aux::tag< keywords::tag::file_name, T const& >::type -wrap_file_name(T const& arg, mpl::false_) +struct file_name_param_traits< T, false > { - return keywords::file_name = arg; -} + static shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > wrap_add_file_log(T const& file_name_arg) + { + return aux::add_file_log(keywords::file_name = file_name_arg); + } + + template< typename ArgsT > + static shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > wrap_add_file_log(T const& file_name_arg, ArgsT const& args) + { + return aux::add_file_log((args, (keywords::file_name = file_name_arg))); + } +}; } // namespace aux @@ -117,11 +137,11 @@ wrap_file_name(T const& arg, mpl::false_) template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ inline shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > add_file_log(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg))\ {\ - return aux::add_file_log((\ - aux::wrap_file_name(arg0, typename parameter::aux::is_named_argument< T0 >::type())\ + return aux::file_name_param_traits< T0 >::wrap_add_file_log(\ + arg0\ BOOST_PP_COMMA_IF(BOOST_PP_GREATER(n, 1))\ - BOOST_PP_ENUM_SHIFTED_PARAMS(n, arg)\ - ));\ + BOOST_PP_EXPR_IF(BOOST_PP_GREATER(n, 1), (BOOST_PP_ENUM_SHIFTED_PARAMS(n, arg)))\ + );\ } BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, BOOST_LOG_INIT_LOG_TO_FILE_INTERNAL, ~) From c0d0fd33f325c818589e11d55af4636ef1a3b17c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 8 Feb 2019 17:30:29 +0300 Subject: [PATCH 023/309] Added a note about compiler TLS intrinsics not removing Boost.Thread dependency. Some users mistakenly assumed that enabling compiler TLS intrinsics would remove the need for Boost.Thread. This added note should remove that confusion. --- doc/log.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/log.qbk b/doc/log.qbk index 51d9cd2bb1..43e8ddac5c 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -255,6 +255,8 @@ The library provides the `BOOST_LOG_USE_COMPILER_TLS` configuration macro that a Note that the `BOOST_LOG_USE_COMPILER_TLS` macro only controls use of TLS in Boost.Log but not in other libraries used by Boost.Log. For example, __boost_asio__ uses compiler-supplied TLS by default. In order to build Boost.Log binaries completely free from use of compiler-supplied TLS, this feature has to be disabled in those other libraries as well (in case of __boost_asio__ this can be achieved by defining `BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION` when building and using Boost). +Also note that enabling builtin compiler support for TLS does not remove the dependency on __boost_thread__ or lower level OS threading primitives, including those implementing TLS. The purpose of using compiler intrinsics for TLS is better performance rather than reducing dependencies. + [heading Notes about native `wchar_t` support] Some compilers, most notably MSVC, have an option to disable the native `wchar_t` type, emulating it with a typedef for one of the standard integral types. From the C++ language perspective this behavior is not conforming but it may be useful for compatibility with some legacy code which is difficult to update. From 1f5ac28873b8cf07d9fe7a7dba9361474f119a1c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 8 Feb 2019 22:23:54 +0300 Subject: [PATCH 024/309] Updated Boost.Parameter tools for compatibility with its updated version. Boost.Parameter added new named parameter wrappers for compatibility with Boost.MP11. The SFINAE helper used to detect named parameters in Boost.Log has been updated to work with these new types and potentially any new types that may come in the future. --- include/boost/log/detail/parameter_tools.hpp | 24 ++++++++------------ 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/include/boost/log/detail/parameter_tools.hpp b/include/boost/log/detail/parameter_tools.hpp index 55695e3cde..9f86cc230e 100644 --- a/include/boost/log/detail/parameter_tools.hpp +++ b/include/boost/log/detail/parameter_tools.hpp @@ -16,7 +16,9 @@ #ifndef BOOST_LOG_DETAIL_PARAMETER_TOOLS_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_PARAMETER_TOOLS_HPP_INCLUDED_ +#include #include +#include #include #include #include @@ -121,26 +123,20 @@ struct make_arg_list< ArgT0, BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(BOOST_LOG_MAX_PAR #endif +#if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) + template< typename T, typename R > -struct enable_if_named_parameters {}; +using enable_if_named_parameters = boost::enable_if_c< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >::value || boost::is_base_of< empty_arg_list, T >::value, R >; -template< typename R > -struct enable_if_named_parameters< empty_arg_list, R > -{ - typedef R type; -}; +#else // !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) -template< typename Keyword, typename Arg, typename R > -struct enable_if_named_parameters< boost::parameter::aux::tagged_argument< Keyword, Arg >, R > +template< typename T, typename R > +struct enable_if_named_parameters : + public boost::enable_if_c< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >::value || boost::is_base_of< empty_arg_list, T >::value, R > { - typedef R type; }; -template< typename TaggedArg, typename Next, typename R > -struct enable_if_named_parameters< boost::parameter::aux::arg_list< TaggedArg, Next >, R > -{ - typedef R type; -}; +#endif // !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) } // namespace aux From 4f5e669376e0ca4d063aaf35d5682efc671525cc Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 9 Feb 2019 06:05:14 +0300 Subject: [PATCH 025/309] Use sort-circuiting mpl::or_ to avoid extra is_base_of instantiation. --- include/boost/log/detail/parameter_tools.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/include/boost/log/detail/parameter_tools.hpp b/include/boost/log/detail/parameter_tools.hpp index 9f86cc230e..8ca2c5dbee 100644 --- a/include/boost/log/detail/parameter_tools.hpp +++ b/include/boost/log/detail/parameter_tools.hpp @@ -16,6 +16,7 @@ #ifndef BOOST_LOG_DETAIL_PARAMETER_TOOLS_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_PARAMETER_TOOLS_HPP_INCLUDED_ +#include #include #include #include @@ -126,13 +127,13 @@ struct make_arg_list< ArgT0, BOOST_PP_ENUM_PARAMS(BOOST_PP_DEC(BOOST_LOG_MAX_PAR #if !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template< typename T, typename R > -using enable_if_named_parameters = boost::enable_if_c< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >::value || boost::is_base_of< empty_arg_list, T >::value, R >; +using enable_if_named_parameters = boost::enable_if_c< boost::mpl::or_< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >, boost::is_base_of< empty_arg_list, T > >::value, R >; #else // !defined(BOOST_NO_CXX11_TEMPLATE_ALIASES) template< typename T, typename R > struct enable_if_named_parameters : - public boost::enable_if_c< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >::value || boost::is_base_of< empty_arg_list, T >::value, R > + public boost::enable_if_c< boost::mpl::or_< boost::is_base_of< boost::parameter::aux::tagged_argument_base, T >, boost::is_base_of< empty_arg_list, T > >::value, R > { }; From d7a87119e683081ed9daca4d2f83c1afeacbc77a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Apr 2019 20:14:58 +0300 Subject: [PATCH 026/309] Fixed incorrect matching of digits in a file name against a placeholder. If a file name pattern ended with a placeholder, e.g. a file counter, file names fitting that pattern would not be matched by scan_for_files, leaving such files unmanaged. Fixes https://github.com/boostorg/log/issues/78. --- doc/changelog.qbk | 8 +++++++- src/text_file_backend.cpp | 4 +++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index c509070b67..5b3129cf5e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2018. + Copyright Andrey Semashev 2007 - 2019. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.17, Boost 1.71] + +[*Bug fixes:] + +* Fixed incorrect parsing of components of the rotated file names while scanning for files in the [link log.detailed.sink_backends.text_file text file sink backend]. If the file name pattern ended with a placeholder (for example, a file counter), the `scan_for_files` method would not find files matching that patter in the target storage, leaving them unmanaged. In particular, such files would not be deleted to free target storage. ([github_issue 78]) + [heading 2.16, Boost 1.70] [*New features:] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index cef1c8dee7..d601255b52 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -390,8 +390,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { for (; n > 0; --n) { + if (it == end) + return false; path_char_type c = *it++; - if (!traits_t::is_digit(c) || it == end) + if (!traits_t::is_digit(c)) return false; } return true; From 2154cafa46675df4e3c986ad5f2c34d1caf2afaa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Apr 2019 20:34:44 +0300 Subject: [PATCH 027/309] Optimized file status requesting while scanning for files. --- src/text_file_backend.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index d601255b52..dcb8fd678e 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -919,9 +919,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { uintmax_t total_size = 0; for (; it != end; ++it) { + filesystem::directory_entry const& dir_entry = *it; file_info info; - info.m_Path = *it; - status = filesystem::status(info.m_Path, ec); + info.m_Path = dir_entry.path(); + status = dir_entry.status(ec); if (status.type() == filesystem::regular_file) { // Check that there are no duplicates in the resulting list From 3925052c302d34c4fccaabf1fcdb22393c2e1a19 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 May 2019 21:02:36 +0300 Subject: [PATCH 028/309] Added explicit support for std::string_view in formatting_ostream. Explicit output operators allow to enable character code conversion, if one is needed, on string view output. This is in line with the existing support for other string types. --- doc/changelog.qbk | 4 ++ .../boost/log/utility/formatting_ostream.hpp | 41 ++++++++++++++++++- test/run/src_record_ostream.cpp | 15 +++++++ test/run/util_formatting_ostream.cpp | 19 +++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 5b3129cf5e..b5799c655b 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -11,6 +11,10 @@ [heading 2.17, Boost 1.71] +[*New features:] + +* Improved support for C++17 `std::string_view` in [class_log_basic_formatting_ostream]. The string view can now participate in character code conversion on output. + [*Bug fixes:] * Fixed incorrect parsing of components of the rotated file names while scanning for files in the [link log.detailed.sink_backends.text_file text file sink backend]. If the file name pattern ended with a placeholder (for example, a file counter), the `scan_for_files` method would not find files matching that patter in the target storage, leaving them unmanaged. In particular, such files would not be deleted to free target storage. ([github_issue 78]) diff --git a/include/boost/log/utility/formatting_ostream.hpp b/include/boost/log/utility/formatting_ostream.hpp index b39feeb664..18de3a7a2d 100644 --- a/include/boost/log/utility/formatting_ostream.hpp +++ b/include/boost/log/utility/formatting_ostream.hpp @@ -27,6 +27,9 @@ #include #include #include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif #include #include #include @@ -547,6 +550,15 @@ class basic_formatting_ostream return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); } +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + template< typename OtherCharT, typename OtherTraitsT > + friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type + operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str) + { + return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); + } +#endif + template< typename OtherCharT, typename OtherTraitsT > friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str) @@ -576,6 +588,15 @@ class basic_formatting_ostream return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); } +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + template< typename OtherCharT, typename OtherTraitsT > + friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type + operator<< (basic_formatting_ostream& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str) + { + return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); + } +#endif + template< typename OtherCharT, typename OtherTraitsT > friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type operator<< (basic_formatting_ostream& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str) @@ -606,6 +627,15 @@ class basic_formatting_ostream return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); } +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + template< typename OtherCharT, typename OtherTraitsT > + friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type + operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT > const& str) + { + return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); + } +#endif + template< typename OtherCharT, typename OtherTraitsT > friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT > const& str) @@ -635,6 +665,15 @@ class basic_formatting_ostream return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); } +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + template< typename OtherCharT, typename OtherTraitsT > + friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type + operator<< (basic_formatting_ostream&& strm, std::basic_string_view< OtherCharT, OtherTraitsT >& str) + { + return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); + } +#endif + template< typename OtherCharT, typename OtherTraitsT > friend typename aux::enable_if_streamable_char_type< OtherCharT, basic_formatting_ostream& >::type operator<< (basic_formatting_ostream&& strm, basic_string_literal< OtherCharT, OtherTraitsT >& str) @@ -656,7 +695,7 @@ class basic_formatting_ostream { return strm.formatted_write(str.data(), static_cast< std::streamsize >(str.size())); } -#endif +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) protected: void init_stream() diff --git a/test/run/src_record_ostream.cpp b/test/run/src_record_ostream.cpp index adba3408e1..2200e119c7 100644 --- a/test/run/src_record_ostream.cpp +++ b/test/run/src_record_ostream.cpp @@ -21,6 +21,9 @@ #include #include #include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif #include #include #include @@ -243,6 +246,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types) test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >(); test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >(); +#endif } // Test support for filler character setup @@ -252,6 +258,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types) test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >(); test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >(); +#endif } // Test support for text alignment @@ -261,6 +270,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types) test::BOOST_NESTED_TEMPLATE alignment< const CharT* >(); test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >(); +#endif } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -271,6 +283,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types) test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >(); test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >(); +#endif } #endif diff --git a/test/run/util_formatting_ostream.cpp b/test/run/util_formatting_ostream.cpp index d9e1ae4957..9585f4f032 100644 --- a/test/run/util_formatting_ostream.cpp +++ b/test/run/util_formatting_ostream.cpp @@ -21,6 +21,9 @@ #include #include #include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif #include #include #include @@ -198,6 +201,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(width_formatting, CharT, char_types) test::BOOST_NESTED_TEMPLATE width_formatting< const CharT* >(); test::BOOST_NESTED_TEMPLATE width_formatting< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE width_formatting< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE width_formatting< std::basic_string_view< CharT > >(); +#endif } // Test support for filler character setup @@ -207,6 +213,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(fill_formatting, CharT, char_types) test::BOOST_NESTED_TEMPLATE fill_formatting< const CharT* >(); test::BOOST_NESTED_TEMPLATE fill_formatting< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE fill_formatting< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE fill_formatting< std::basic_string_view< CharT > >(); +#endif } // Test support for text alignment @@ -216,6 +225,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(alignment, CharT, char_types) test::BOOST_NESTED_TEMPLATE alignment< const CharT* >(); test::BOOST_NESTED_TEMPLATE alignment< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE alignment< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE alignment< std::basic_string_view< CharT > >(); +#endif } #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -226,6 +238,9 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(rvalue_stream, CharT, char_types) test::BOOST_NESTED_TEMPLATE rvalue_stream< const CharT* >(); test::BOOST_NESTED_TEMPLATE rvalue_stream< typename test::string_type >(); test::BOOST_NESTED_TEMPLATE rvalue_stream< boost::basic_string_view< CharT > >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test::BOOST_NESTED_TEMPLATE rvalue_stream< std::basic_string_view< CharT > >(); +#endif } #endif @@ -464,6 +479,10 @@ BOOST_AUTO_TEST_CASE(character_code_conversion) test_widening_code_conversion< std::string >(); test_narrowing_code_conversion< boost::wstring_view >(); test_widening_code_conversion< boost::string_view >(); +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + test_narrowing_code_conversion< std::wstring_view >(); + test_widening_code_conversion< std::string_view >(); +#endif } #endif From d66ab73a5f3291b0b16624d60e18cae9e11b9cc7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 May 2019 21:38:04 +0300 Subject: [PATCH 029/309] Added forwarding of pointer type in Boost.Log streams. When a user defines an output operator for std::basic_ostream and a pointer to a user-defined type, that operator use to be ignored because of the implicit cast to const void* that happened when operator<< for formatting_ostream or record_ostream was called. We now forward the pointer type to the operator<< for std::ostream, so it is either cast then or user's operator<< is picked. Fixes https://github.com/boostorg/log/issues/84. --- doc/changelog.qbk | 1 + include/boost/log/sources/record_ostream.hpp | 32 ++++++++++++--- .../boost/log/utility/formatting_ostream.hpp | 40 ++++++++++++++++--- test/run/src_record_ostream.cpp | 17 +++++++- test/run/util_formatting_ostream.cpp | 17 +++++++- 5 files changed, 93 insertions(+), 14 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index b5799c655b..31ef9042fe 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -18,6 +18,7 @@ [*Bug fixes:] * Fixed incorrect parsing of components of the rotated file names while scanning for files in the [link log.detailed.sink_backends.text_file text file sink backend]. If the file name pattern ended with a placeholder (for example, a file counter), the `scan_for_files` method would not find files matching that patter in the target storage, leaving them unmanaged. In particular, such files would not be deleted to free target storage. ([github_issue 78]) +* Updated [class_log_basic_formatting_ostream] and [class_log_basic_record_ostream] to make it possible to overload stream output operators for pointers to user-defined types. User-defined `operator<<` overloads taking `std::basic_ostream` and a pointer argument should now be picked up by the compiler when the pointer is being written to one of Boost.Log streams. ([github_issue 84]) [heading 2.16, Boost 1.70] diff --git a/include/boost/log/sources/record_ostream.hpp b/include/boost/log/sources/record_ostream.hpp index 87274a2774..d8eb899566 100644 --- a/include/boost/log/sources/record_ostream.hpp +++ b/include/boost/log/sources/record_ostream.hpp @@ -62,6 +62,14 @@ struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T, { }; +template< typename StreamT, typename T, typename R > +struct enable_record_ostream_pointer_operator {}; +template< typename CharT, typename T, typename R > +struct enable_record_ostream_pointer_operator< basic_record_ostream< CharT >, T, R > : + public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R > +{ +}; + } // namespace aux /*! @@ -326,12 +334,6 @@ class basic_record_ostream : return *this; } - basic_record_ostream& operator<< (const void* value) - { - static_cast< base_type& >(*this) << value; - return *this; - } - basic_record_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf) { static_cast< base_type& >(*this) << buf; @@ -391,6 +393,15 @@ operator<< (StreamT& strm, T& value) return strm; } +template< typename StreamT, typename T > +inline typename boost::log::aux::enable_record_ostream_pointer_operator< StreamT, T, StreamT& >::type +operator<< (StreamT& strm, T* value) +{ + typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type; + static_cast< formatting_ostream_type& >(strm) << value; + return strm; +} + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template< typename StreamT, typename T > @@ -420,6 +431,15 @@ operator<< (StreamT&& strm, T& value) return strm; } +template< typename StreamT, typename T > +inline typename boost::log::aux::enable_record_ostream_pointer_operator< StreamT, T, StreamT& >::type +operator<< (StreamT&& strm, T* value) +{ + typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type; + static_cast< formatting_ostream_type& >(strm) << value; + return strm; +} + #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) namespace aux { diff --git a/include/boost/log/utility/formatting_ostream.hpp b/include/boost/log/utility/formatting_ostream.hpp index 18de3a7a2d..ae2fe77296 100644 --- a/include/boost/log/utility/formatting_ostream.hpp +++ b/include/boost/log/utility/formatting_ostream.hpp @@ -48,18 +48,28 @@ namespace aux { template< typename T, typename R > struct enable_if_streamable_char_type {}; +template< typename T, typename R > +struct disable_if_streamable_char_type { typedef R type; }; template< typename R > struct enable_if_streamable_char_type< char, R > { typedef R type; }; template< typename R > +struct disable_if_streamable_char_type< char, R > {}; +template< typename R > struct enable_if_streamable_char_type< wchar_t, R > { typedef R type; }; +template< typename R > +struct disable_if_streamable_char_type< wchar_t, R > {}; #if !defined(BOOST_LOG_NO_CXX11_CODECVT_FACETS) #if !defined(BOOST_NO_CXX11_CHAR16_T) template< typename R > struct enable_if_streamable_char_type< char16_t, R > { typedef R type; }; +template< typename R > +struct disable_if_streamable_char_type< char16_t, R > {}; #endif #if !defined(BOOST_NO_CXX11_CHAR32_T) template< typename R > struct enable_if_streamable_char_type< char32_t, R > { typedef R type; }; +template< typename R > +struct disable_if_streamable_char_type< char32_t, R > {}; #endif #endif @@ -76,6 +86,14 @@ struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< Cha { }; +template< typename StreamT, typename T, typename R > +struct enable_formatting_ostream_pointer_operator {}; +template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R > +struct enable_formatting_ostream_pointer_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, R > : + public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R > +{ +}; + } // namespace aux /*! @@ -531,12 +549,6 @@ class basic_formatting_ostream return *this; } - basic_formatting_ostream& operator<< (const void* value) - { - m_stream << value; - return *this; - } - basic_formatting_ostream& operator<< (std::basic_streambuf< char_type, traits_type >* buf) { m_stream << buf; @@ -918,6 +930,14 @@ operator<< (StreamT& strm, T& value) return strm; } +template< typename StreamT, typename T > +inline typename boost::log::aux::enable_formatting_ostream_pointer_operator< StreamT, T, StreamT& >::type +operator<< (StreamT& strm, T* value) +{ + strm.stream() << value; + return strm; +} + #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template< typename StreamT, typename T > @@ -944,6 +964,14 @@ operator<< (StreamT&& strm, T& value) return strm; } +template< typename StreamT, typename T > +inline typename boost::log::aux::enable_formatting_ostream_pointer_operator< StreamT, T, StreamT& >::type +operator<< (StreamT&& strm, T* value) +{ + strm.stream() << value; + return strm; +} + #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) BOOST_LOG_CLOSE_NAMESPACE // namespace log diff --git a/test/run/src_record_ostream.cpp b/test/run/src_record_ostream.cpp index 2200e119c7..dd321f922c 100644 --- a/test/run/src_record_ostream.cpp +++ b/test/run/src_record_ostream.cpp @@ -321,6 +321,20 @@ inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< Cha return strm; } +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*) +{ + strm << "B*"; + return strm; +} + +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*) +{ + strm << "const B*"; + return strm; +} + class C {}; template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&) @@ -355,11 +369,12 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types) my_namespace::B b; // lvalue strm_fmt << a << b << my_namespace::C(); // rvalue strm_fmt << my_namespace::eee; + strm_fmt << &b << (my_namespace::B const*)&b; strm_fmt.flush(); string_type rec_message = logging::extract_or_throw< string_type >(expr::message.get_name(), rec); ostream_type strm_correct; - strm_correct << a << b << my_namespace::C() << my_namespace::eee; + strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b; BOOST_CHECK(equal_strings(rec_message, strm_correct.str())); } diff --git a/test/run/util_formatting_ostream.cpp b/test/run/util_formatting_ostream.cpp index 9585f4f032..cd73bcd5f0 100644 --- a/test/run/util_formatting_ostream.cpp +++ b/test/run/util_formatting_ostream.cpp @@ -269,6 +269,20 @@ inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< Cha return strm; } +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, B*) +{ + strm << "B*"; + return strm; +} + +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, const B*) +{ + strm << "const B*"; + return strm; +} + class C {}; template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, C const&) @@ -302,10 +316,11 @@ BOOST_AUTO_TEST_CASE_TEMPLATE(operator_forwarding, CharT, char_types) my_namespace::B b; // lvalue strm_fmt << a << b << my_namespace::C(); // rvalue strm_fmt << my_namespace::eee; + strm_fmt << &b << (my_namespace::B const*)&b; strm_fmt.flush(); ostream_type strm_correct; - strm_correct << a << b << my_namespace::C() << my_namespace::eee; + strm_correct << a << b << my_namespace::C() << my_namespace::eee << &b << (my_namespace::B const*)&b; BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); } From 4c7b3ede6e1d0071cd8b9b72e45ddcfb52f8173b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 26 May 2019 17:47:24 +0300 Subject: [PATCH 030/309] Simplified support for forwarding pointer types in formatting ostreams. --- include/boost/log/sources/record_ostream.hpp | 24 +++---------------- .../boost/log/utility/formatting_ostream.hpp | 22 +++-------------- 2 files changed, 6 insertions(+), 40 deletions(-) diff --git a/include/boost/log/sources/record_ostream.hpp b/include/boost/log/sources/record_ostream.hpp index d8eb899566..776315ae1f 100644 --- a/include/boost/log/sources/record_ostream.hpp +++ b/include/boost/log/sources/record_ostream.hpp @@ -51,21 +51,21 @@ namespace aux { template< typename StreamT, typename T, bool ByValueV, typename R > struct enable_record_ostream_generic_operator {}; + template< typename CharT, typename T, typename R > struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T, false, R > : public boost::disable_if_c< boost::is_scalar< typename boost::remove_cv< T >::type >::value, R > { }; + template< typename CharT, typename T, typename R > struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T, true, R > : public boost::enable_if_c< boost::is_enum< typename boost::remove_cv< T >::type >::value, R > { }; -template< typename StreamT, typename T, typename R > -struct enable_record_ostream_pointer_operator {}; template< typename CharT, typename T, typename R > -struct enable_record_ostream_pointer_operator< basic_record_ostream< CharT >, T, R > : +struct enable_record_ostream_generic_operator< basic_record_ostream< CharT >, T*, true, R > : public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R > { }; @@ -393,15 +393,6 @@ operator<< (StreamT& strm, T& value) return strm; } -template< typename StreamT, typename T > -inline typename boost::log::aux::enable_record_ostream_pointer_operator< StreamT, T, StreamT& >::type -operator<< (StreamT& strm, T* value) -{ - typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type; - static_cast< formatting_ostream_type& >(strm) << value; - return strm; -} - #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template< typename StreamT, typename T > @@ -431,15 +422,6 @@ operator<< (StreamT&& strm, T& value) return strm; } -template< typename StreamT, typename T > -inline typename boost::log::aux::enable_record_ostream_pointer_operator< StreamT, T, StreamT& >::type -operator<< (StreamT&& strm, T* value) -{ - typedef basic_formatting_ostream< typename StreamT::char_type > formatting_ostream_type; - static_cast< formatting_ostream_type& >(strm) << value; - return strm; -} - #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) namespace aux { diff --git a/include/boost/log/utility/formatting_ostream.hpp b/include/boost/log/utility/formatting_ostream.hpp index ae2fe77296..e2f83aab0c 100644 --- a/include/boost/log/utility/formatting_ostream.hpp +++ b/include/boost/log/utility/formatting_ostream.hpp @@ -75,21 +75,21 @@ struct disable_if_streamable_char_type< char32_t, R > {}; template< typename StreamT, typename T, bool ByValueV, typename R > struct enable_formatting_ostream_generic_operator {}; + template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R > struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, false, R > : public boost::disable_if_c< boost::is_scalar< typename boost::remove_cv< T >::type >::value, R > { }; + template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R > struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, true, R > : public boost::enable_if_c< boost::is_enum< typename boost::remove_cv< T >::type >::value, R > { }; -template< typename StreamT, typename T, typename R > -struct enable_formatting_ostream_pointer_operator {}; template< typename CharT, typename TraitsT, typename AllocatorT, typename T, typename R > -struct enable_formatting_ostream_pointer_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T, R > : +struct enable_formatting_ostream_generic_operator< basic_formatting_ostream< CharT, TraitsT, AllocatorT >, T*, true, R > : public disable_if_streamable_char_type< typename boost::remove_cv< T >::type, R > { }; @@ -930,14 +930,6 @@ operator<< (StreamT& strm, T& value) return strm; } -template< typename StreamT, typename T > -inline typename boost::log::aux::enable_formatting_ostream_pointer_operator< StreamT, T, StreamT& >::type -operator<< (StreamT& strm, T* value) -{ - strm.stream() << value; - return strm; -} - #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) template< typename StreamT, typename T > @@ -964,14 +956,6 @@ operator<< (StreamT&& strm, T& value) return strm; } -template< typename StreamT, typename T > -inline typename boost::log::aux::enable_formatting_ostream_pointer_operator< StreamT, T, StreamT& >::type -operator<< (StreamT&& strm, T* value) -{ - strm.stream() << value; - return strm; -} - #endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) BOOST_LOG_CLOSE_NAMESPACE // namespace log From 894acde57ef9121d90e9aa2b7646d7dbd7923fe1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 23 Jun 2019 21:02:51 +0300 Subject: [PATCH 031/309] Added support for controling trailing newline insertion in the text sinks. Text ostream, file and multifile sink backends now support controlling trailing newline insertion after every log records. The supported modes are described by the auto_newline_mode enum. The behavior can be controlled via the same-named named parameter, a set_auto_newline_mode call or the AutoNewline parameter in the settings. The default behavior has changed from the previous releases. From now on the trailing newline will only be added if there isn't one in the formatted log message already. --- doc/changelog.qbk | 5 ++ doc/sink_backends.qbk | 2 +- doc/utilities.qbk | 6 +++ include/boost/log/sinks/text_file_backend.hpp | 14 +++++ .../log/sinks/text_multifile_backend.hpp | 36 ++++++++++++- .../boost/log/sinks/text_ostream_backend.hpp | 53 +++++++++++++++++-- include/boost/log/utility/setup/console.hpp | 22 ++++++-- include/boost/log/utility/setup/file.hpp | 4 ++ src/setup/init_from_settings.cpp | 34 ++++++++++++ src/setup/parser_utils.hpp | 10 ++++ src/text_file_backend.cpp | 26 +++++++-- src/text_multifile_backend.cpp | 34 +++++++++--- src/text_ostream_backend.cpp | 36 +++++++++++-- 13 files changed, 256 insertions(+), 26 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 31ef9042fe..1e174db502 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,11 @@ [*New features:] * Improved support for C++17 `std::string_view` in [class_log_basic_formatting_ostream]. The string view can now participate in character code conversion on output. +* In the [link log.detailed.sink_backends.text_ostream output stream], [link log.detailed.sink_backends.text_file text file] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends added support for configuring behavior with regard to appending a trailing newline to every formatted log record. The user can specify a value of the [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`] enum either in the `auto_newline_mode` named parameter of the backend constructor or by calling the `set_auto_newline_mode` methof on the backend post-construction. The `auto_newline_mode` named parameter is also supported in the [link log.detailed.utilities.setup.convenience convenience] functions for initializing sinks. When initializing from [link log.detailed.utilities.setup.settings settings] or a config file, the behavior is controlled by the new "AutoNewline" parameter of the sink. + +[note The default behavior with regard to trailing newlines has changed slightly compared to the previous Boost.Log releases. The backends will now only add a trailing newline if there isn't one in the formatted log message string already. In previous releases a newline was added unconditionally. In general, users are advised to configure their formatters so that the trailing newline is added there, if needed, and disable the automatic trailing newline insertion in the sink backends. This feature mostly exists for backward compatibility and can be considered deprecated.] + +* [link log.detailed.sink_backends.text_ostream Output stream] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends can now be constructed with named parameters. [*Bug fixes:] diff --git a/doc/sink_backends.qbk b/doc/sink_backends.qbk index 1f580a344b..ebad4aec4c 100644 --- a/doc/sink_backends.qbk +++ b/doc/sink_backends.qbk @@ -15,7 +15,7 @@ The text output stream sink backend is the most generic backend provided by the library out of the box. The backend is implemented in the [class_sinks_basic_text_ostream_backend] class template (`text_ostream_backend` and `wtext_ostream_backend` convenience typedefs provided for narrow and wide character support). It supports formatting log records into strings and putting into one or several streams. Each attached stream gets the same result of formatting, so if you need to format log records differently for different streams, you will need to create several sinks - each with its own formatter. -The backend also provides a feature that may come useful when debugging your application. With the `auto_flush` method one can tell the sink to automatically flush the buffers of all attached streams after each log record is written. This will, of course, degrade logging performance, but in case of an application crash there is a good chance that last log records will not be lost. +The backend also provides a feature that may come useful when debugging your application. With the `auto_flush` method one can tell the sink to automatically flush the buffers of all attached streams after each log record is written. This will, of course, degrade logging performance, but in case of an application crash there is a good chance that last log records are not lost. [example_sinks_ostream] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index d51c4416bf..a99ff8b1b3 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -549,6 +549,9 @@ Besides the common settings that all sinks support, some sink backends also acce [[Format] [Format string as described [link log.detailed.utilities.setup.filter_formatter here]] [Log record formatter to be used by the sink. If not specified, the default formatter is used.] ] +[[AutoNewline] ["Disabled", "AlwaysInsert" or "InsertIfMissing"] + [Controls whether the backend should automatically insert a trailing newline after every log record, see [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`]. If not specified, the default value is "InsertIfMissing".] +] [[AutoFlush] ["true" or "false"] [Enables or disables the auto-flush feature of the backend. If not specified, the default value `false` is assumed.] ] @@ -565,6 +568,9 @@ Besides the common settings that all sinks support, some sink backends also acce [[Format] [Format string as described [link log.detailed.utilities.setup.filter_formatter here]] [Log record formatter to be used by the sink. If not specified, the default formatter is used.] ] +[[AutoNewline] ["Disabled", "AlwaysInsert" or "InsertIfMissing"] + [Controls whether the backend should automatically insert a trailing newline after every log record, see [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`]. If not specified, the default value is "InsertIfMissing".] +] [[AutoFlush] ["true" or "false"] [Enables or disables the auto-flush feature of the backend. If not specified, the default value `false` is assumed.] ] diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 486e55a9d7..d72e4cfb53 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -37,9 +37,11 @@ #include #include #include +#include #include #include #include +#include #include #include #include @@ -397,6 +399,8 @@ class text_file_backend : * sink backend destruction. By default, is \c true. * \li \c auto_flush - Specifies a flag, whether or not to automatically flush the file after each * written log record. By default, is \c false. + * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of + * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. * * \note Read the caution note regarding file name pattern in the sinks::file::collector::scan_for_files * documentation. @@ -512,6 +516,14 @@ class text_file_backend : */ BOOST_LOG_API void auto_flush(bool enable = true); + /*! + * Selects whether a trailing newline should be automatically inserted after every log record. See + * \c auto_newline_mode description for the possible modes of operation. + * + * \param mode The trailing newline insertion mode. + */ + BOOST_LOG_API void set_auto_newline_mode(auto_newline_mode mode); + /*! * \return The name of the currently open log file. If no file is open, returns an empty path. */ @@ -566,6 +578,7 @@ class text_file_backend : args[keywords::open_mode | (std::ios_base::trunc | std::ios_base::out)], args[keywords::rotation_size | (std::numeric_limits< uintmax_t >::max)()], args[keywords::time_based_rotation | time_based_rotation_predicate()], + args[keywords::auto_newline_mode | insert_if_missing], args[keywords::auto_flush | false], args[keywords::enable_final_rotation | true]); } @@ -576,6 +589,7 @@ class text_file_backend : std::ios_base::openmode mode, uintmax_t rotation_size, time_based_rotation_predicate const& time_based_rotation, + auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation); diff --git a/include/boost/log/sinks/text_multifile_backend.hpp b/include/boost/log/sinks/text_multifile_backend.hpp index 8e707b990c..2db672b366 100644 --- a/include/boost/log/sinks/text_multifile_backend.hpp +++ b/include/boost/log/sinks/text_multifile_backend.hpp @@ -25,7 +25,10 @@ #include #include #include +#include #include +#include +#include #include #include #include @@ -161,10 +164,24 @@ class text_multifile_backend : public: /*! * Default constructor. The constructed sink backend has no file name composer and - * thus will not write any files. + * thus will not write any files. All other parameters are set to their defaults. */ BOOST_LOG_API text_multifile_backend(); + /*! + * Constructor. Creates a sink backend with the specified named parameters. + * The following named parameters are supported: + * + * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of + * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS + BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(text_multifile_backend, construct) +#else + template< typename... ArgsT > + explicit text_multifile_backend(ArgsT... const& args); +#endif + /*! * Destructor */ @@ -181,6 +198,14 @@ class text_multifile_backend : set_file_name_composer_internal(composer); } + /*! + * Selects whether a trailing newline should be automatically inserted after every log record. See + * \c auto_newline_mode description for the possible modes of operation. + * + * \param mode The trailing newline insertion mode. + */ + BOOST_LOG_API void set_auto_newline_mode(auto_newline_mode mode); + /*! * The method writes the message to the sink */ @@ -188,6 +213,15 @@ class text_multifile_backend : private: #ifndef BOOST_LOG_DOXYGEN_PASS + //! Constructor implementation + template< typename ArgsT > + void construct(ArgsT const& args) + { + construct(args[keywords::auto_newline_mode | insert_if_missing]); + } + //! Constructor implementation + BOOST_LOG_API void construct(auto_newline_mode auto_newline); + //! The method sets the file name composer BOOST_LOG_API void set_file_name_composer_internal(file_name_composer_type const& composer); #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/text_ostream_backend.hpp b/include/boost/log/sinks/text_ostream_backend.hpp index 9d8ad0d6cd..487c8f8178 100644 --- a/include/boost/log/sinks/text_ostream_backend.hpp +++ b/include/boost/log/sinks/text_ostream_backend.hpp @@ -18,6 +18,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include @@ -71,6 +75,23 @@ class basic_text_ostream_backend : * Constructor. No streams attached to the constructed backend, auto flush feature disabled. */ BOOST_LOG_API basic_text_ostream_backend(); + + /*! + * Constructor. Creates a sink backend with the specified named parameters. + * The following named parameters are supported: + * + * \li \c auto_flush - Specifies a flag, whether or not to automatically flush the attached streams after each + * written log record. By default, is \c false. + * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of + * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. + */ +#ifndef BOOST_LOG_DOXYGEN_PASS + BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_CALL(basic_text_ostream_backend, construct) +#else + template< typename... ArgsT > + explicit basic_text_ostream_backend(ArgsT... const& args); +#endif + /*! * Destructor */ @@ -91,19 +112,43 @@ class basic_text_ostream_backend : BOOST_LOG_API void remove_stream(shared_ptr< stream_type > const& strm); /*! - * Sets the flag to automatically flush buffers of all attached streams after each log record + * Sets the flag to automatically flush buffers of all attached streams after each log record. + * + * \param enable The flag indicates whether the automatic buffer flush should be performed. */ - BOOST_LOG_API void auto_flush(bool f = true); + BOOST_LOG_API void auto_flush(bool enable = true); /*! - * The method writes the message to the sink + * Selects whether a trailing newline should be automatically inserted after every log record. See + * \c auto_newline_mode description for the possible modes of operation. + * + * \param mode The trailing newline insertion mode. + */ + BOOST_LOG_API void set_auto_newline_mode(auto_newline_mode mode); + + /*! + * The method writes the message to the sink. */ BOOST_LOG_API void consume(record_view const& rec, string_type const& formatted_message); /*! - * The method flushes the associated streams + * The method flushes all attached streams. */ BOOST_LOG_API void flush(); + +private: +#ifndef BOOST_LOG_DOXYGEN_PASS + //! Constructor implementation + template< typename ArgsT > + void construct(ArgsT const& args) + { + construct( + args[keywords::auto_newline_mode | insert_if_missing], + args[keywords::auto_flush | false]); + } + //! Constructor implementation + BOOST_LOG_API void construct(auto_newline_mode auto_newline, bool auto_flush); +#endif // BOOST_LOG_DOXYGEN_PASS }; #ifdef BOOST_LOG_USE_CHAR diff --git a/include/boost/log/utility/setup/console.hpp b/include/boost/log/utility/setup/console.hpp index 7212c7b74a..08bfd961f0 100644 --- a/include/boost/log/utility/setup/console.hpp +++ b/include/boost/log/utility/setup/console.hpp @@ -16,10 +16,12 @@ #define BOOST_LOG_UTILITY_SETUP_CONSOLE_HPP_INCLUDED_ #include +#include #include #include #include #include +#include #include #ifndef BOOST_LOG_NO_THREADS #include @@ -29,7 +31,6 @@ #include #include #include -#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -62,10 +63,9 @@ shared_ptr< shared_ptr< std::basic_ostream< CharT > > pStream(&strm, boost::null_deleter()); typedef sinks::basic_text_ostream_backend< CharT > backend_t; - shared_ptr< backend_t > pBackend = boost::make_shared< backend_t >(); + shared_ptr< backend_t > pBackend = boost::make_shared< backend_t >(args); pBackend->add_stream(pStream); - pBackend->auto_flush(args[keywords::auto_flush | false]); typedef BOOST_LOG_CONSOLE_SINK_FRONTEND_INTERNAL< backend_t > sink_t; shared_ptr< sink_t > pSink = boost::make_shared< sink_t >(pBackend); @@ -112,7 +112,7 @@ inline shared_ptr< > add_console_log() { return aux::add_console_log( - aux::default_console_stream< CharT >::get(), keywords::auto_flush = false); + aux::default_console_stream< CharT >::get(), log::aux::empty_arg_list()); } @@ -123,7 +123,7 @@ inline shared_ptr< > > add_console_log(std::basic_ostream< CharT >& strm) { - return aux::add_console_log(strm, keywords::auto_flush = false); + return aux::add_console_log(strm, log::aux::empty_arg_list()); } template< typename CharT, typename ArgT1 > @@ -156,6 +156,16 @@ inline shared_ptr< return aux::add_console_log(strm, (arg1, arg2, arg3)); } +template< typename CharT, typename ArgT1, typename ArgT2, typename ArgT3, typename ArgT4 > +inline shared_ptr< + BOOST_LOG_CONSOLE_SINK_FRONTEND_INTERNAL< + sinks::basic_text_ostream_backend< CharT > + > +> add_console_log(std::basic_ostream< CharT >& strm, ArgT1 const& arg1, ArgT2 const& arg2, ArgT3 const& arg3, ArgT3 const& arg4) +{ + return aux::add_console_log(strm, (arg1, arg2, arg3, arg4)); +} + #else // BOOST_LOG_DOXYGEN_PASS /*! @@ -170,6 +180,8 @@ inline shared_ptr< * or a formatter lambda expression (either streaming or Boost.Format-like notation). * \li \c auto_flush A boolean flag that shows whether the sink should automatically flush the stream * after each written record. + * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of + * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. * \return Pointer to the constructed sink. */ template< typename CharT, typename... ArgsT > diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index b66f06c2cc..03fef7f30b 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -36,6 +36,8 @@ #include #endif #include +#include +#include #include #include @@ -164,6 +166,8 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, BOOST_LOG_INIT_LOG_TO_F * \li \c time_based_rotation The predicate for time-based file rotations. See basic_text_file_backend. * \li \c auto_flush A boolean flag that shows whether the sink should automatically flush the file * after each written record. + * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of + * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. * \li \c target The target directory to store rotated files in. See sinks::file::make_collector. * \li \c max_size The maximum total size of rotated files in the target directory. See sinks::file::make_collector. * \li \c min_free_space Minimum free space in the target directory. See sinks::file::make_collector. diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index f49c9a2a3c..502f2c8d68 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include #include @@ -149,6 +150,27 @@ inline bool param_cast_to_bool(const char* param_name, std::basic_string< CharT } } +//! Extracts an \c auto_newline_mode value from parameter value +template< typename CharT > +inline sinks::auto_newline_mode param_cast_to_auto_newline_mode(const char* param_name, std::basic_string< CharT > const& value) +{ + typedef CharT char_type; + typedef boost::log::aux::char_constants< char_type > constants; + typedef boost::log::basic_string_literal< char_type > literal_type; + + if (value == constants::auto_newline_mode_disabled()) + return sinks::disabled_auto_newline; + else if (value == constants::auto_newline_mode_always_insert()) + return sinks::always_insert; + else if (value == constants::auto_newline_mode_insert_if_missing()) + return sinks::insert_if_missing; + else + { + BOOST_LOG_THROW_DESCR(invalid_value, + "Auto newline mode \"" + boost::log::aux::to_narrow(value) + "\" is not supported"); + } +} + #if !defined(BOOST_LOG_NO_ASIO) //! Extracts a network address from parameter value template< typename CharT > @@ -394,6 +416,12 @@ class default_console_sink_factory : shared_ptr< backend_t > backend = boost::make_shared< backend_t >(); backend->add_stream(shared_ptr< typename backend_t::stream_type >(&constants::get_console_log_stream(), boost::null_deleter())); + // Auto newline mode + if (optional< string_type > auto_newline_param = params["AutoNewline"]) + { + backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get())); + } + // Auto flush if (optional< string_type > auto_flush_param = params["AutoFlush"]) { @@ -469,6 +497,12 @@ class default_text_file_sink_factory : backend->enable_final_rotation(param_cast_to_bool("EnableFinalRotation", enable_final_rotation_param.get())); } + // Auto newline mode + if (optional< string_type > auto_newline_param = params["AutoNewline"]) + { + backend->set_auto_newline_mode(param_cast_to_auto_newline_mode("AutoNewline", auto_newline_param.get())); + } + // Auto flush if (optional< string_type > auto_flush_param = params["AutoFlush"]) { diff --git a/src/setup/parser_utils.hpp b/src/setup/parser_utils.hpp index 94f5ffb56c..bf0be4b873 100644 --- a/src/setup/parser_utils.hpp +++ b/src/setup/parser_utils.hpp @@ -97,6 +97,7 @@ struct char_constants< char > static const char_type* append_param_name() { return "Append"; } static const char_type* enable_final_rotation_param_name() { return "EnableFinalRotation"; } static const char_type* auto_flush_param_name() { return "AutoFlush"; } + static const char_type* auto_newline_mode_param_name() { return "AutoNewline"; } static const char_type* asynchronous_param_name() { return "Asynchronous"; } static const char_type* format_param_name() { return "Format"; } static const char_type* provider_id_param_name() { return "ProviderID"; } @@ -114,6 +115,10 @@ struct char_constants< char > static const char_type* scan_method_all() { return "All"; } static const char_type* scan_method_matching() { return "Matching"; } + static const char_type* auto_newline_mode_disabled() { return "Disabled"; } + static const char_type* auto_newline_mode_always_insert() { return "AlwaysInsert"; } + static const char_type* auto_newline_mode_insert_if_missing() { return "InsertIfMissing"; } + static const char_type* registration_never() { return "Never"; } static const char_type* registration_on_demand() { return "OnDemand"; } static const char_type* registration_forced() { return "Forced"; } @@ -228,6 +233,7 @@ struct char_constants< wchar_t > static const char_type* append_param_name() { return L"Append"; } static const char_type* enable_final_rotation_param_name() { return L"EnableFinalRotation"; } static const char_type* auto_flush_param_name() { return L"AutoFlush"; } + static const char_type* auto_newline_mode_param_name() { return L"AutoNewline"; } static const char_type* asynchronous_param_name() { return L"Asynchronous"; } static const char_type* format_param_name() { return L"Format"; } static const char_type* provider_id_param_name() { return L"ProviderID"; } @@ -245,6 +251,10 @@ struct char_constants< wchar_t > static const char_type* scan_method_all() { return L"All"; } static const char_type* scan_method_matching() { return L"Matching"; } + static const char_type* auto_newline_mode_disabled() { return L"Disabled"; } + static const char_type* auto_newline_mode_always_insert() { return L"AlwaysInsert"; } + static const char_type* auto_newline_mode_insert_if_missing() { return L"InsertIfMissing"; } + static const char_type* registration_never() { return L"Never"; } static const char_type* registration_on_demand() { return L"OnDemand"; } static const char_type* registration_forced() { return L"Forced"; } diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index dcb8fd678e..d01c4d4a22 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -53,6 +53,7 @@ #include #include #include +#include #include #include "unique_ptr.hpp" @@ -1242,16 +1243,19 @@ struct text_file_backend::implementation uintmax_t m_FileRotationSize; //! Time-based rotation predicate time_based_rotation_predicate m_TimeBasedRotation; + //! Indicates whether to append a trailing newline after every log record + auto_newline_mode m_AutoNewlineMode; //! The flag shows if every written record should be flushed bool m_AutoFlush; //! The flag indicates whether the final rotation should be performed bool m_FinalRotationEnabled; - implementation(uintmax_t rotation_size, bool auto_flush, bool enable_final_rotation) : + implementation(uintmax_t rotation_size, auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) : m_FileOpenMode(std::ios_base::trunc | std::ios_base::out), m_FileCounter(0), m_CharactersWritten(0), m_FileRotationSize(rotation_size), + m_AutoNewlineMode(auto_newline), m_AutoFlush(auto_flush), m_FinalRotationEnabled(enable_final_rotation) { @@ -1287,10 +1291,11 @@ BOOST_LOG_API void text_file_backend::construct( std::ios_base::openmode mode, uintmax_t rotation_size, time_based_rotation_predicate const& time_based_rotation, + auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) { - m_pImpl = new implementation(rotation_size, auto_flush, enable_final_rotation); + m_pImpl = new implementation(rotation_size, auto_newline, auto_flush, enable_final_rotation); set_file_name_pattern_internal(pattern); set_target_file_name_pattern_internal(target_file_name); set_time_based_rotation(time_based_rotation); @@ -1321,6 +1326,12 @@ BOOST_LOG_API void text_file_backend::auto_flush(bool enable) m_pImpl->m_AutoFlush = enable; } +//! Selects whether a trailing newline should be automatically inserted after every log record. +BOOST_LOG_API void text_file_backend::set_auto_newline_mode(auto_newline_mode mode) +{ + m_pImpl->m_AutoNewlineMode = mode; +} + //! The method writes the message to the sink BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_type const& formatted_message) { @@ -1389,9 +1400,16 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ } m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size())); - m_pImpl->m_File.put(traits_t::newline); + m_pImpl->m_CharactersWritten += formatted_message.size(); - m_pImpl->m_CharactersWritten += formatted_message.size() + 1; + if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline) + { + if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || formatted_message.back() != traits_t::newline) + { + m_pImpl->m_File.put(traits_t::newline); + ++m_pImpl->m_CharactersWritten; + } + } if (m_pImpl->m_AutoFlush) m_pImpl->m_File.flush(); diff --git a/src/text_multifile_backend.cpp b/src/text_multifile_backend.cpp index 58669deb66..c1e2d6492d 100644 --- a/src/text_multifile_backend.cpp +++ b/src/text_multifile_backend.cpp @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -36,9 +38,12 @@ struct text_multifile_backend::implementation const filesystem::path m_BasePath; //! File stream filesystem::ofstream m_File; + //! Indicates whether to append a trailing newline after every log record + auto_newline_mode m_AutoNewlineMode; - implementation() : - m_BasePath(filesystem::current_path()) + explicit implementation(auto_newline_mode auto_newline) : + m_BasePath(filesystem::current_path()), + m_AutoNewlineMode(auto_newline) { } @@ -50,8 +55,15 @@ struct text_multifile_backend::implementation }; //! Default constructor -BOOST_LOG_API text_multifile_backend::text_multifile_backend() : m_pImpl(new implementation()) +BOOST_LOG_API text_multifile_backend::text_multifile_backend() { + construct(log::aux::empty_arg_list()); +} + +//! Constructor implementation +BOOST_LOG_API void text_multifile_backend::construct(auto_newline_mode auto_newline) +{ + m_pImpl = new implementation(auto_newline); } //! Destructor @@ -66,18 +78,28 @@ BOOST_LOG_API void text_multifile_backend::set_file_name_composer_internal(file_ m_pImpl->m_FileNameComposer = composer; } +//! Selects whether a trailing newline should be automatically inserted after every log record. +BOOST_LOG_API void text_multifile_backend::set_auto_newline_mode(auto_newline_mode mode) +{ + m_pImpl->m_AutoNewlineMode = mode; +} + //! The method writes the message to the sink BOOST_LOG_API void text_multifile_backend::consume(record_view const& rec, string_type const& formatted_message) { - if (!m_pImpl->m_FileNameComposer.empty()) + if (BOOST_LIKELY(!m_pImpl->m_FileNameComposer.empty())) { filesystem::path file_name = m_pImpl->make_absolute(m_pImpl->m_FileNameComposer(rec)); filesystem::create_directories(file_name.parent_path()); m_pImpl->m_File.open(file_name, std::ios_base::out | std::ios_base::app); - if (m_pImpl->m_File.is_open()) + if (BOOST_LIKELY(m_pImpl->m_File.is_open())) { m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size())); - m_pImpl->m_File.put(static_cast< string_type::value_type >('\n')); + if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline) + { + if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || formatted_message.back() != static_cast< string_type::value_type >('\n')) + m_pImpl->m_File.put(static_cast< string_type::value_type >('\n')); + } m_pImpl->m_File.close(); } } diff --git a/src/text_ostream_backend.cpp b/src/text_ostream_backend.cpp index d803d0dba4..047b0c00ff 100644 --- a/src/text_ostream_backend.cpp +++ b/src/text_ostream_backend.cpp @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -34,10 +36,14 @@ struct basic_text_ostream_backend< CharT >::implementation //! Output stream list ostream_sequence m_Streams; + //! Indicates whether to append a trailing newline after every log record + auto_newline_mode m_AutoNewlineMode; //! Auto-flush flag bool m_fAutoFlush; - implementation() : m_fAutoFlush(false) + implementation(auto_newline_mode auto_newline, bool auto_flush) : + m_AutoNewlineMode(auto_newline), + m_fAutoFlush(auto_flush) { } }; @@ -45,8 +51,16 @@ struct basic_text_ostream_backend< CharT >::implementation //! Constructor template< typename CharT > -BOOST_LOG_API basic_text_ostream_backend< CharT >::basic_text_ostream_backend() : m_pImpl(new implementation()) +BOOST_LOG_API basic_text_ostream_backend< CharT >::basic_text_ostream_backend() { + construct(log::aux::empty_arg_list()); +} + +//! Constructor implementation +template< typename CharT > +BOOST_LOG_API void basic_text_ostream_backend< CharT >::construct(auto_newline_mode auto_newline, bool auto_flush) +{ + m_pImpl = new implementation(auto_newline, auto_flush); } //! Destructor (just to make it link from the shared library) @@ -56,6 +70,13 @@ BOOST_LOG_API basic_text_ostream_backend< CharT >::~basic_text_ostream_backend() delete m_pImpl; } +//! Selects whether a trailing newline should be automatically inserted after every log record. +template< typename CharT > +BOOST_LOG_API void basic_text_ostream_backend< CharT >::set_auto_newline_mode(auto_newline_mode mode) +{ + m_pImpl->m_AutoNewlineMode = mode; +} + //! The method adds a new stream to the sink template< typename CharT > BOOST_LOG_API void basic_text_ostream_backend< CharT >::add_stream(shared_ptr< stream_type > const& strm) @@ -93,13 +114,18 @@ BOOST_LOG_API void basic_text_ostream_backend< CharT >::consume(record_view cons typename string_type::size_type const s = message.size(); typename implementation::ostream_sequence::const_iterator it = m_pImpl->m_Streams.begin(), end = m_pImpl->m_Streams.end(); + bool need_trailing_newline = false; + if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline) + need_trailing_newline = (m_pImpl->m_AutoNewlineMode == always_insert || s == 0u || p[s - 1u] != static_cast< char_type >('\n')); + for (; it != end; ++it) { stream_type* const strm = it->get(); - if (strm->good()) + if (BOOST_LIKELY(strm->good())) { strm->write(p, static_cast< std::streamsize >(s)); - strm->put(static_cast< char_type >('\n')); + if (need_trailing_newline) + strm->put(static_cast< char_type >('\n')); if (m_pImpl->m_fAutoFlush) strm->flush(); @@ -116,7 +142,7 @@ BOOST_LOG_API void basic_text_ostream_backend< CharT >::flush() for (; it != end; ++it) { stream_type* const strm = it->get(); - if (strm->good()) + if (BOOST_LIKELY(strm->good())) strm->flush(); } } From 2fbd7ae0f2aba27b44fcd8814699daaaf4ee0458 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 23 Jun 2019 22:12:51 +0300 Subject: [PATCH 032/309] Added missing files. --- .../boost/log/keywords/auto_newline_mode.hpp | 40 ++++++++++++++++ include/boost/log/sinks/auto_newline_mode.hpp | 47 +++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 include/boost/log/keywords/auto_newline_mode.hpp create mode 100644 include/boost/log/sinks/auto_newline_mode.hpp diff --git a/include/boost/log/keywords/auto_newline_mode.hpp b/include/boost/log/keywords/auto_newline_mode.hpp new file mode 100644 index 0000000000..6b9a04110c --- /dev/null +++ b/include/boost/log/keywords/auto_newline_mode.hpp @@ -0,0 +1,40 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file keywords/auto_newline_mode.hpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * The header contains the \c auto_newline_mode keyword declaration. + */ + +#ifndef BOOST_LOG_KEYWORDS_AUTO_NEWLINE_MODE_HPP_INCLUDED_ +#define BOOST_LOG_KEYWORDS_AUTO_NEWLINE_MODE_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace keywords { + +//! The keyword for passing automatic trailing newline insertion mode to a sink backend initialization +BOOST_PARAMETER_KEYWORD(tag, auto_newline_mode) + +} // namespace keywords + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#endif // BOOST_LOG_KEYWORDS_AUTO_NEWLINE_MODE_HPP_INCLUDED_ diff --git a/include/boost/log/sinks/auto_newline_mode.hpp b/include/boost/log/sinks/auto_newline_mode.hpp new file mode 100644 index 0000000000..012b81b180 --- /dev/null +++ b/include/boost/log/sinks/auto_newline_mode.hpp @@ -0,0 +1,47 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file sinks/auto_newline_mode.hpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * The header contains definition of auto-newline modes. + */ + +#ifndef BOOST_LOG_SINKS_AUTO_NEWLINE_MODE_HPP_INCLUDED_HPP_ +#define BOOST_LOG_SINKS_AUTO_NEWLINE_MODE_HPP_INCLUDED_HPP_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace sinks { + +//! The enum lists automatic trailing newline modes +enum auto_newline_mode +{ + disabled_auto_newline, //!< Do not insert automatic trailing newline characters + always_insert, //!< Always insert automatic trailing newline characters + insert_if_missing //!< Insert automatic trailing newline characters, if not present already +}; + +} // namespace sinks + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_SINKS_AUTO_NEWLINE_MODE_HPP_INCLUDED_HPP_ From 326d97a9d1ea7f37b7be12dae525842374965d72 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 00:27:16 +0300 Subject: [PATCH 033/309] Added auto_newline stream manipulator and formatter. The manipulator and formatter can be used to ensure a certain piece of output ends with a newline without introducing duplicate newline characters if the previous output ended with a newline already. --- doc/changelog.qbk | 5 +- doc/expressions.qbk | 18 +++- doc/utilities.qbk | 12 +++ include/boost/log/expressions/formatters.hpp | 1 + .../expressions/formatters/auto_newline.hpp | 46 +++++++++ include/boost/log/utility/manipulators.hpp | 1 + .../log/utility/manipulators/auto_newline.hpp | 66 +++++++++++++ .../boost/log/utility/manipulators/dump.hpp | 4 +- test/run/form_auto_newline.cpp | 94 +++++++++++++++++++ test/run/util_manip_auto_newline.cpp | 83 ++++++++++++++++ 10 files changed, 325 insertions(+), 5 deletions(-) create mode 100644 include/boost/log/expressions/formatters/auto_newline.hpp create mode 100644 include/boost/log/utility/manipulators/auto_newline.hpp create mode 100644 test/run/form_auto_newline.cpp create mode 100644 test/run/util_manip_auto_newline.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 1e174db502..35f2be5b98 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,9 +14,10 @@ [*New features:] * Improved support for C++17 `std::string_view` in [class_log_basic_formatting_ostream]. The string view can now participate in character code conversion on output. -* In the [link log.detailed.sink_backends.text_ostream output stream], [link log.detailed.sink_backends.text_file text file] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends added support for configuring behavior with regard to appending a trailing newline to every formatted log record. The user can specify a value of the [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`] enum either in the `auto_newline_mode` named parameter of the backend constructor or by calling the `set_auto_newline_mode` methof on the backend post-construction. The `auto_newline_mode` named parameter is also supported in the [link log.detailed.utilities.setup.convenience convenience] functions for initializing sinks. When initializing from [link log.detailed.utilities.setup.settings settings] or a config file, the behavior is controlled by the new "AutoNewline" parameter of the sink. +* Added `auto_newline` [link log.detailed.expressions.formatters.auto_newline formatter] and [link log.detailed.utilities.manipulators.auto_newline stream manipulator]. It can be used to ensure that formatted output always ends with a newline while avoiding duplicate newlines. +* In the [link log.detailed.sink_backends.text_ostream output stream], [link log.detailed.sink_backends.text_file text file] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends added support for configuring behavior with regard to appending a trailing newline to every formatted log record. The user can specify a value of the [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`] enum either in the `auto_newline_mode` named parameter of the backend constructor or by calling the `set_auto_newline_mode` method on the backend post-construction. The `auto_newline_mode` named parameter is also supported in the [link log.detailed.utilities.setup.convenience convenience] functions for initializing sinks. When initializing from [link log.detailed.utilities.setup.settings settings] or a config file, the behavior is controlled by the new "AutoNewline" parameter of the sink. -[note The default behavior with regard to trailing newlines has changed slightly compared to the previous Boost.Log releases. The backends will now only add a trailing newline if there isn't one in the formatted log message string already. In previous releases a newline was added unconditionally. In general, users are advised to configure their formatters so that the trailing newline is added there, if needed, and disable the automatic trailing newline insertion in the sink backends. This feature mostly exists for backward compatibility and can be considered deprecated.] +[note The default behavior with regard to trailing newlines has changed slightly compared to the previous Boost.Log releases. The backends will now only add a trailing newline if there isn't one in the formatted log message string already. In previous releases a newline was added unconditionally. In general, users are advised to configure their formatters so that the trailing newline is added there, if needed (e.g. by using [link log.detailed.expressions.formatters.auto_newline `auto_newline`] formatter), and disable the automatic trailing newline insertion in the sink backends. This feature mostly exists for backward compatibility and can be considered deprecated.] * [link log.detailed.sink_backends.text_ostream Output stream] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends can now be constructed with named parameters. diff --git a/doc/expressions.qbk b/doc/expressions.qbk index 412ffbc16f..eaaa9c5ff8 100644 --- a/doc/expressions.qbk +++ b/doc/expressions.qbk @@ -146,7 +146,7 @@ The `message` keyword has to dispatch between different string types, so it is s [section:predicates Predicate expressions] -This section describes several expressions that can be used as predicates in the filtering expressions. +This section describes several expressions that can be used as predicates in filtering expressions. [section:has_attr Attribute presence filter] @@ -474,6 +474,22 @@ Those familiar with __boost_phoenix__ lambda expressions will find this syntax q [endsect] +[section:auto_newline Automatic newline insertion] + + #include <``[boost_log_expressions_formatters_auto_newline_hpp]``> + +This is an adaptation of the [link log.detailed.utilities.manipulators.auto_newline `auto_newline` manipulator] for formatter expressions. The `auto_newline` formatter can be useful, for example, if log messages generated by one source are terminated with a newline character (and that behavior cannot be changed easily), and other messages are not. The formatter will ensure that all messages are reliably terminated with a newline and there are no duplicate newline characters. Like the manipulator, it will insert a newline unless the last character inserted into the stream before it was a newline. For example: + + sink->set_formatter + ( + expr::stream + // Ensure that the sink outputs one message per line, + // regardless whether the message itself ends with a newline or not + << expr::message << expr::auto_newline + ); + +[endsect] + [section:decorators Character decorators] There are times when one would like to additionally post-process the composed string before passing it to the sink backend. For example, in order to store log into an XML file the formatted log record should be checked for special characters that have a special meaning in XML documents. This is where decorators step in. diff --git a/doc/utilities.qbk b/doc/utilities.qbk index a99ff8b1b3..c80bee5471 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -250,6 +250,18 @@ There is another manipulator called [funcref boost::log::dump_elements `dump_ele [endsect] +[section:auto_newline Automatic newline insertion] + + #include <``[boost_log_utility_manipulators_auto_newline_hpp]``> + +Sometimes it can be useful to be able to insert a newline character in the output stream, but only if it hasn't been inserted as part of the previous output. For example, if a string may or may not end with a newline, and we cannot easily tell which one it is each time. The `auto_newline` manipulator can be used to ensure that all such strings are reliably terminated with a newline and there are no duplicate newline characters. The manipulator will insert a newline unless the last character inserted into the stream before it was a newline. Its use is similar to standard stream manipulators: + + BOOST_LOG(lg) << "Parameter: " << param.name << ", value: " << param.value << logging::auto_newline; + +[note This manipulator inspects previous output to the stream, and therefore can only be used with Boost.Log streams based on [class_log_basic_formatting_ostream].] + +[endsect] + [endsect] [section:ipc Interprocess communication tools] diff --git a/include/boost/log/expressions/formatters.hpp b/include/boost/log/expressions/formatters.hpp index f85cb7903b..e61857e1ea 100644 --- a/include/boost/log/expressions/formatters.hpp +++ b/include/boost/log/expressions/formatters.hpp @@ -31,6 +31,7 @@ #include #include +#include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once diff --git a/include/boost/log/expressions/formatters/auto_newline.hpp b/include/boost/log/expressions/formatters/auto_newline.hpp new file mode 100644 index 0000000000..5677314484 --- /dev/null +++ b/include/boost/log/expressions/formatters/auto_newline.hpp @@ -0,0 +1,46 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file expressions/formatters/auto_newline.hpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * The header contains implementation of formatter for inserting a newline, unless there is already one inserted. + */ + +#ifndef BOOST_LOG_EXPRESSIONS_FORMATTERS_AUTO_NEWLINE_HPP_INCLUDED_ +#define BOOST_LOG_EXPRESSIONS_FORMATTERS_AUTO_NEWLINE_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace expressions { + +/*! + * Formatter for inserting a newline character, unless the last character + * inserted into the stream is already a newline. + */ +using boost::log::auto_newline; + +} // namespace expressions + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_EXPRESSIONS_FORMATTERS_AUTO_NEWLINE_HPP_INCLUDED_ diff --git a/include/boost/log/utility/manipulators.hpp b/include/boost/log/utility/manipulators.hpp index cb39fd2416..75ea8fc91c 100644 --- a/include/boost/log/utility/manipulators.hpp +++ b/include/boost/log/utility/manipulators.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #ifdef BOOST_HAS_PRAGMA_ONCE #pragma once diff --git a/include/boost/log/utility/manipulators/auto_newline.hpp b/include/boost/log/utility/manipulators/auto_newline.hpp new file mode 100644 index 0000000000..06aa16f9ac --- /dev/null +++ b/include/boost/log/utility/manipulators/auto_newline.hpp @@ -0,0 +1,66 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/manipulators/auto_newline.hpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * The header contains implementation of a stream manipulator for inserting a newline, unless there is already one inserted. + */ + +#ifndef BOOST_LOG_UTILITY_MANIPULATORS_AUTO_NEWLINE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_MANIPULATORS_AUTO_NEWLINE_HPP_INCLUDED_ + +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * Stream manipulator for inserting a newline character, unless the last character + * inserted into the stream is already a newline. + */ +struct auto_newline_manip {} +const auto_newline = {}; + +/*! + * Stream output operator for the \c auto_newline manipulator + */ +template< typename CharT, typename TraitsT, typename AllocatorT > +inline basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (basic_formatting_ostream< CharT, TraitsT, AllocatorT >& strm, auto_newline_manip) +{ + typedef basic_formatting_ostream< CharT, TraitsT, AllocatorT > stream_type; + typedef typename stream_type::char_type char_type; + typedef typename stream_type::string_type string_type; + if (BOOST_LIKELY(strm.good())) + { + string_type* str = strm.rdbuf()->storage(); + if (BOOST_LIKELY(!!str)) + { + strm.rdbuf()->pubsync(); + if (str->empty() || str->back() != static_cast< char_type >('\n')) + strm.rdbuf()->push_back(static_cast< char_type >('\n')); + } + } + + return strm; +} + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_MANIPULATORS_AUTO_NEWLINE_HPP_INCLUDED_ diff --git a/include/boost/log/utility/manipulators/dump.hpp b/include/boost/log/utility/manipulators/dump.hpp index 3341376f39..2c55e5c004 100644 --- a/include/boost/log/utility/manipulators/dump.hpp +++ b/include/boost/log/utility/manipulators/dump.hpp @@ -128,7 +128,7 @@ class dump_manip template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, dump_manip const& manip) { - if (strm.good()) + if (BOOST_LIKELY(strm.good())) aux::dump_data(manip.get_data(), manip.get_size(), strm); return strm; @@ -155,7 +155,7 @@ class bounded_dump_manip : template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, bounded_dump_manip const& manip) { - if (strm.good()) + if (BOOST_LIKELY(strm.good())) { const std::size_t size = manip.get_size(), max_size = manip.get_max_size(); if (max_size >= size) diff --git a/test/run/form_auto_newline.cpp b/test/run/form_auto_newline.cpp new file mode 100644 index 0000000000..0ce38e67a6 --- /dev/null +++ b/test/run/form_auto_newline.cpp @@ -0,0 +1,94 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file form_auto_newline.cpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * \brief This header contains tests for the auto_newline formatter. + */ + +#define BOOST_TEST_MODULE form_auto_newline + +#include +#include +#include +#include +#include "char_definitions.hpp" +#include "make_record.hpp" + +namespace logging = boost::log; +namespace expr = logging::expressions; + +// Test appending a newline to a non-empty string +BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + typedef logging::record_view record_view; + typedef logging::basic_formatter< char_type > formatter; + + record_view rec = make_record_view(); + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + formatter f = expr::stream << "Hello" << expr::auto_newline; + f(rec, strm_fmt); + + ostream_type strm_correct; + strm_correct << "Hello\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} + +// Test appending a newline to an empty string +BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + typedef logging::record_view record_view; + typedef logging::basic_formatter< char_type > formatter; + + record_view rec = make_record_view(); + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + formatter f = expr::stream << expr::auto_newline; + f(rec, strm_fmt); + + ostream_type strm_correct; + strm_correct << "\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} + +// Test not appending a newline to a non-empty string which already ends with a newline +BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + typedef logging::record_view record_view; + typedef logging::basic_formatter< char_type > formatter; + + record_view rec = make_record_view(); + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + formatter f = expr::stream << "Hello\n" << expr::auto_newline; + f(rec, strm_fmt); + + ostream_type strm_correct; + strm_correct << "Hello\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} diff --git a/test/run/util_manip_auto_newline.cpp b/test/run/util_manip_auto_newline.cpp new file mode 100644 index 0000000000..91f1d07b5e --- /dev/null +++ b/test/run/util_manip_auto_newline.cpp @@ -0,0 +1,83 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_manip_auto_newline.cpp + * \author Andrey Semashev + * \date 23.06.2019 + * + * \brief This header contains tests for the auto_newline manipulator. + */ + +#define BOOST_TEST_MODULE util_manip_auto_newline + +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; + +// Test appending a newline to a non-empty string +BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_non_empty_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + strm_fmt << "Hello" << logging::auto_newline; + strm_fmt.flush(); + + ostream_type strm_correct; + strm_correct << "Hello\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} + +// Test appending a newline to an empty string +BOOST_AUTO_TEST_CASE_TEMPLATE(append_to_empty_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + strm_fmt << logging::auto_newline; + strm_fmt.flush(); + + ostream_type strm_correct; + strm_correct << "\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} + +// Test not appending a newline to a non-empty string which already ends with a newline +BOOST_AUTO_TEST_CASE_TEMPLATE(not_append_if_ends_with_a_newline, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef logging::basic_formatting_ostream< char_type > formatting_ostream_type; + typedef typename formatting_ostream_type::string_type string_type; + + string_type str_fmt; + formatting_ostream_type strm_fmt(str_fmt); + + strm_fmt << "Hello\n" << logging::auto_newline; + strm_fmt.flush(); + + ostream_type strm_correct; + strm_correct << "Hello\n"; + + BOOST_CHECK(equal_strings(strm_fmt.str(), strm_correct.str())); +} From ed5af033527e737a7c45a7f2b99dd0d3445b33e9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 00:33:03 +0300 Subject: [PATCH 034/309] Corrected a typo. --- doc/changelog.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 35f2be5b98..0f19364a4e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -23,7 +23,7 @@ [*Bug fixes:] -* Fixed incorrect parsing of components of the rotated file names while scanning for files in the [link log.detailed.sink_backends.text_file text file sink backend]. If the file name pattern ended with a placeholder (for example, a file counter), the `scan_for_files` method would not find files matching that patter in the target storage, leaving them unmanaged. In particular, such files would not be deleted to free target storage. ([github_issue 78]) +* Fixed incorrect parsing of components of the rotated file names while scanning for files in the [link log.detailed.sink_backends.text_file text file sink backend]. If the file name pattern ended with a placeholder (for example, a file counter), the `scan_for_files` method would not find files matching that pattern in the target storage, leaving them unmanaged. In particular, such files would not be deleted to free target storage. ([github_issue 78]) * Updated [class_log_basic_formatting_ostream] and [class_log_basic_record_ostream] to make it possible to overload stream output operators for pointers to user-defined types. User-defined `operator<<` overloads taking `std::basic_ostream` and a pointer argument should now be picked up by the compiler when the pointer is being written to one of Boost.Log streams. ([github_issue 84]) [heading 2.16, Boost 1.70] From e4f91a2431142f89dbec9aa4358afe2b0dedbb99 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 04:04:09 +0300 Subject: [PATCH 035/309] Added support for arbitrary functions in filter and format named parameters. This allows to specify directly custom function objects, including C++11 lambda functions, in the filter and format named parameters in the sink initialization calls. Closes https://github.com/boostorg/log/issues/63. --- doc/changelog.qbk | 3 +- doc/tutorial.qbk | 10 ++- .../boost/log/detail/sink_init_helpers.hpp | 63 ++++++++++++++++--- 3 files changed, 65 insertions(+), 11 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 0f19364a4e..7e9721befc 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,11 +15,12 @@ * Improved support for C++17 `std::string_view` in [class_log_basic_formatting_ostream]. The string view can now participate in character code conversion on output. * Added `auto_newline` [link log.detailed.expressions.formatters.auto_newline formatter] and [link log.detailed.utilities.manipulators.auto_newline stream manipulator]. It can be used to ensure that formatted output always ends with a newline while avoiding duplicate newlines. -* In the [link log.detailed.sink_backends.text_ostream output stream], [link log.detailed.sink_backends.text_file text file] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends added support for configuring behavior with regard to appending a trailing newline to every formatted log record. The user can specify a value of the [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`] enum either in the `auto_newline_mode` named parameter of the backend constructor or by calling the `set_auto_newline_mode` method on the backend post-construction. The `auto_newline_mode` named parameter is also supported in the [link log.detailed.utilities.setup.convenience convenience] functions for initializing sinks. When initializing from [link log.detailed.utilities.setup.settings settings] or a config file, the behavior is controlled by the new "AutoNewline" parameter of the sink. +* In the [link log.detailed.sink_backends.text_ostream output stream], [link log.detailed.sink_backends.text_file text file] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends added support for configuring behavior with regard to appending a trailing newline to every formatted log record. The user can specify a value of the [enumref boost::log::sinks::auto_newline_mode `auto_newline_mode`] enum either in the `auto_newline_mode` named parameter of the backend constructor or by calling the `set_auto_newline_mode` method on the backend post-construction. The `auto_newline_mode` named parameter is also supported in the [link log.detailed.utilities.setup.convenience convenience functions] for initializing sinks. When initializing from [link log.detailed.utilities.setup.settings settings] or a config file, the behavior is controlled by the new "AutoNewline" parameter of the sink. [note The default behavior with regard to trailing newlines has changed slightly compared to the previous Boost.Log releases. The backends will now only add a trailing newline if there isn't one in the formatted log message string already. In previous releases a newline was added unconditionally. In general, users are advised to configure their formatters so that the trailing newline is added there, if needed (e.g. by using [link log.detailed.expressions.formatters.auto_newline `auto_newline`] formatter), and disable the automatic trailing newline insertion in the sink backends. This feature mostly exists for backward compatibility and can be considered deprecated.] * [link log.detailed.sink_backends.text_ostream Output stream] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends can now be constructed with named parameters. +* Added support for passing arbitrary function objects (as opposed to only __boost_phoenix__ function objects, which were supported before) in the `filter` and `format` named parameters to sink constructors and [link log.detailed.utilities.setup.convenience convenience functions] for initializing sinks. For example, it is now possible to specify C++11 lambda functions directly in these parameters. ([github_issue 63]) [*Bug fixes:] diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index bf81b443a1..edb5cb21df 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -336,11 +336,17 @@ Notably, the formatter itself contains a filter here. As you can see, the format Further goes the initialization of the two sinks. The first sink does not have any filter, which means it will save every log record to the file. We call `set_filter` on the second sink to only save log records with severity no less than `warning` or having a "Tag" attribute with value "IMPORTANT_MESSAGE". As you can see, the filter syntax resembles usual C++ very much, especially when attribute keywords are used. -Like with formatters, it is also possible to use custom functions as filters. __boost_phoenix__ can be very helpful in this case as its `bind` implementation is compatible with attribute placeholders. The previous example can be modified in the following way: +Like with formatters, it is also possible to use custom functions as filters. Fundamentally, a filter function must support the following signature: + + bool (logging::attribute_value_set const& attrs); + +When the filter is called, `attrs` will contain a complete set of attribute values, which can be used to decide whether the log record should be passed or suppressed. If the filter returns `true`, the log record will be constructed and further processed by sinks. Otherwise, the record will be discarded. + +__boost_phoenix__ can be very helpful in constructing filters. It allows to automate extraction of attribute values from the `attrs` set as its `bind` implementation is compatible with attribute placeholders. The previous example can be modified in the following way: [example_tutorial_filtering_bind] -As you can see, the custom filter receives attribute values wrapped into the [link log.detailed.utilities.value_ref `value_ref`] template. This wrapper contains an optional reference to the attribute value of the specified type; the reference is valid if the log record contains the attribute value of the required type. The relational operators used in `my_filter` can be applied unconditionally because they will automatically return `false` if the reference is not valid. The rest is done with the `bind` expression which will recognize the `severity` and `tag_attr` keywords and extract the corresponding values before passing them to `my_filter`. +As you can see, the custom filter receives attribute values as separate arguments, wrapped into the [link log.detailed.utilities.value_ref `value_ref`] template. This wrapper contains an optional reference to the attribute value of the specified type; the reference is valid if the log record contains the attribute value of the required type. The relational operators used in `my_filter` can be applied unconditionally because they will automatically return `false` if the reference is not valid. The rest is done with the `bind` expression which will recognize the `severity` and `tag_attr` keywords and extract the corresponding values before passing them to `my_filter`. [note Because of limitations related to the integration with __boost_phoenix__ (see [ticket 7996]), it is required to explicitly specify the fallback policy in case if the attribute value is missing, when attribute keywords are used with `phoenix::bind` or `phoenix::function`. In the example above, this is done by calling `or_none`, which results in an empty [link log.detailed.utilities.value_ref `value_ref`] if the value is not found. In other contexts this policy is the default. There are [link log.detailed.expressions.attr.fallback_policies other policies] that can be used instead.] diff --git a/include/boost/log/detail/sink_init_helpers.hpp b/include/boost/log/detail/sink_init_helpers.hpp index a3bbe0e8a1..4f0bed850c 100644 --- a/include/boost/log/detail/sink_init_helpers.hpp +++ b/include/boost/log/detail/sink_init_helpers.hpp @@ -20,9 +20,13 @@ #include #include #include +#include #include -#include +#include #include +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +#include +#endif #include #include #include @@ -30,6 +34,7 @@ #include #include #include +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -44,18 +49,39 @@ namespace aux { // The function creates a filter functional object from the provided argument template< typename CharT > -inline filter acquire_filter(const CharT* filter) +inline typename boost::enable_if_c< + log::aux::is_character_type< CharT >::value, + filter +>::type acquire_filter(const CharT* filter) { return boost::log::parse_filter(filter); } + template< typename CharT, typename TraitsT, typename AllocatorT > inline filter acquire_filter(std::basic_string< CharT, TraitsT, AllocatorT > const& filter) { return boost::log::parse_filter(filter); } + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +template< typename CharT, typename TraitsT > +inline filter acquire_filter(std::basic_string_view< CharT, TraitsT > const& filter) +{ + const CharT* p = filter.data(); + return boost::log::parse_filter(p, p + filter.size()); +} +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename CharT, typename TraitsT > +inline filter acquire_filter(boost::basic_string_view< CharT, TraitsT > const& filter) +{ + const CharT* p = filter.data(); + return boost::log::parse_filter(p, p + filter.size()); +} + template< typename FilterT > -inline typename boost::enable_if_c< - phoenix::is_actor< FilterT >::value, +inline typename boost::disable_if_c< + boost::is_array< FilterT >::value, FilterT const& >::type acquire_filter(FilterT const& filter) { @@ -75,20 +101,41 @@ inline void setup_filter(SinkT& s, ArgsT const& args, mpl::false_) } -// The function creates a filter functional object from the provided argument +// The function creates a formatter functional object from the provided argument template< typename CharT > -inline basic_formatter< CharT > acquire_formatter(const CharT* formatter) +inline typename boost::enable_if_c< + log::aux::is_character_type< CharT >::value, + basic_formatter< CharT > +>::type acquire_formatter(const CharT* formatter) { return boost::log::parse_formatter(formatter); } + template< typename CharT, typename TraitsT, typename AllocatorT > inline basic_formatter< CharT > acquire_formatter(std::basic_string< CharT, TraitsT, AllocatorT > const& formatter) { return boost::log::parse_formatter(formatter); } + +#if !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) +template< typename CharT, typename TraitsT > +inline basic_formatter< CharT > acquire_formatter(std::basic_string_view< CharT, TraitsT > const& formatter) +{ + const CharT* p = formatter.data(); + return boost::log::parse_formatter(p, p + formatter.size()); +} +#endif // !defined(BOOST_NO_CXX17_HDR_STRING_VIEW) + +template< typename CharT, typename TraitsT > +inline basic_formatter< CharT > acquire_formatter(boost::basic_string_view< CharT, TraitsT > const& formatter) +{ + const CharT* p = formatter.data(); + return boost::log::parse_formatter(p, p + formatter.size()); +} + template< typename FormatterT > -inline typename boost::enable_if_c< - phoenix::is_actor< FormatterT >::value, +inline typename boost::disable_if_c< + boost::is_array< FormatterT >::value, FormatterT const& >::type acquire_formatter(FormatterT const& formatter) { From e903d3aef7be37adb877655b9ac39d4a954ca943 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 04:34:44 +0300 Subject: [PATCH 036/309] Fixed compilation in C++03. --- include/boost/log/utility/manipulators/auto_newline.hpp | 2 +- src/text_file_backend.cpp | 2 +- src/text_multifile_backend.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/log/utility/manipulators/auto_newline.hpp b/include/boost/log/utility/manipulators/auto_newline.hpp index 06aa16f9ac..933a670de5 100644 --- a/include/boost/log/utility/manipulators/auto_newline.hpp +++ b/include/boost/log/utility/manipulators/auto_newline.hpp @@ -49,7 +49,7 @@ inline basic_formatting_ostream< CharT, TraitsT, AllocatorT >& operator<< (basic if (BOOST_LIKELY(!!str)) { strm.rdbuf()->pubsync(); - if (str->empty() || str->back() != static_cast< char_type >('\n')) + if (str->empty() || *str->rbegin() != static_cast< char_type >('\n')) strm.rdbuf()->push_back(static_cast< char_type >('\n')); } } diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index d01c4d4a22..50cef3b034 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1404,7 +1404,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline) { - if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || formatted_message.back() != traits_t::newline) + if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || *formatted_message.rbegin() != traits_t::newline) { m_pImpl->m_File.put(traits_t::newline); ++m_pImpl->m_CharactersWritten; diff --git a/src/text_multifile_backend.cpp b/src/text_multifile_backend.cpp index c1e2d6492d..550dd57f69 100644 --- a/src/text_multifile_backend.cpp +++ b/src/text_multifile_backend.cpp @@ -97,7 +97,7 @@ BOOST_LOG_API void text_multifile_backend::consume(record_view const& rec, strin m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size())); if (m_pImpl->m_AutoNewlineMode != disabled_auto_newline) { - if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || formatted_message.back() != static_cast< string_type::value_type >('\n')) + if (m_pImpl->m_AutoNewlineMode == always_insert || formatted_message.empty() || *formatted_message.rbegin() != static_cast< string_type::value_type >('\n')) m_pImpl->m_File.put(static_cast< string_type::value_type >('\n')); } m_pImpl->m_File.close(); From dad1c0518d0deb2b3ab3c989180cf38e30a6f717 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 13:32:00 +0300 Subject: [PATCH 037/309] Upgraded Travis CI images, added gcc-9 and clang-8. Workaround clang CI failures. --- .travis.yml | 119 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 91 insertions(+), 28 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5b182eb228..93fedc0d7f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,8 @@ os: - linux - osx +dist: xenial + branches: only: - master @@ -29,9 +31,12 @@ matrix: include: # gcc, Linux - os: linux + compiler: gcc env: TOOLSET=gcc COMPILER=g++ CXXSTD=03,11 EXTRA_TESTS=1 - os: linux + dist: trusty + compiler: gcc-4.7 env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=03,11 addons: apt: @@ -43,6 +48,8 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: trusty + compiler: gcc-4.8 env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=03,11 addons: apt: @@ -54,6 +61,8 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: trusty + compiler: gcc-4.9 env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=03,11 addons: apt: @@ -65,6 +74,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + compiler: gcc-5 env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14 addons: apt: @@ -76,6 +86,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + compiler: gcc-6 env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z addons: apt: @@ -87,6 +98,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + compiler: gcc-7 env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,17 addons: apt: @@ -98,6 +110,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + compiler: gcc-8 env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 addons: apt: @@ -109,20 +122,31 @@ matrix: - ubuntu-toolchain-r-test - os: linux - compiler: g++-8 - env: UBSAN=1 TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + compiler: gcc-9 + env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 addons: apt: packages: - - g++-8 + - g++-9 + - g++-9-multilib + - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test -# clang, Linux - os: linux - env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 + compiler: gcc-UBSAN + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + addons: + apt: + packages: + - g++-9 + sources: + - ubuntu-toolchain-r-test +# clang, Linux - os: linux + dist: trusty + compiler: clang-3.5 env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11 addons: apt: @@ -132,9 +156,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 + - llvm-toolchain-trusty-3.5 - os: linux + dist: trusty + compiler: clang-3.6 env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11 addons: apt: @@ -144,9 +170,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 + - llvm-toolchain-trusty-3.6 - os: linux + dist: trusty + compiler: clang-3.7 env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11 addons: apt: @@ -156,107 +184,142 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 + - llvm-toolchain-trusty-3.7 - os: linux + dist: trusty + compiler: clang-3.8 env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z addons: apt: packages: - clang-3.8 - - g++-5-multilib + - g++-6-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 + - llvm-toolchain-trusty-3.8 - os: linux + dist: trusty + compiler: clang-3.9 env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=03,11,14,1z addons: apt: packages: - clang-3.9 - - g++-5-multilib + - g++-6-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - llvm-toolchain-trusty-3.9 - os: linux + compiler: clang-4 env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z addons: apt: packages: - clang-4.0 - - g++-5-multilib + - g++-6-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-4.0 + - llvm-toolchain-xenial-4.0 - os: linux + compiler: clang-5 env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z addons: apt: packages: - clang-5.0 - - g++-5-multilib + - g++-7-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 + - llvm-toolchain-xenial-5.0 - os: linux + compiler: clang-6 env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17 addons: apt: packages: - clang-6.0 - - g++-5-multilib + - g++-8-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 + - llvm-toolchain-xenial-6.0 - os: linux + compiler: clang-7 env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 addons: apt: packages: - clang-7 - - g++-5-multilib + - g++-8-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-7 + - llvm-toolchain-xenial-7 - os: linux - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 + compiler: clang-8 + env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 addons: apt: packages: - - clang-7 - - g++-5-multilib + - clang-8 + - g++-8-multilib - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-7 + - llvm-toolchain-xenial-8 - os: linux - compiler: clang++-libc++ - env: TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=03,11,14,1z + compiler: clang-UBSAN + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: + - clang-8 + - g++-8-multilib + - linux-libc-dev:i386 + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-8 + +# Note: libc++ currently causes linking errors about missing operator new/delete with std::align_val_t arguments in C++17 + - os: linux + compiler: clang-libc++ + env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++ -fno-aligned-new" LINKFLAGS="-stdlib=libc++" + addons: + apt: + packages: + - clang-8 + - g++-8-multilib + - linux-libc-dev:i386 - libc++-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-8 - os: linux - compiler: clang++-libc++ - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-libc++ CXXSTD=03,11,14,1z UBSAN_OPTIONS=print_stacktrace=1 + compiler: clang-libc++-UBSAN + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++ -fno-aligned-new" LINKFLAGS="-stdlib=libc++" addons: apt: packages: + - clang-8 + - g++-8-multilib + - linux-libc-dev:i386 - libc++-dev + sources: + - ubuntu-toolchain-r-test + - llvm-toolchain-xenial-8 # clang, OS X # OS X jobs time out for some reason @@ -291,7 +354,7 @@ script: echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam - BUILD_JOBS=`(nproc || sysctl -n hw.ncpu) 2> /dev/null` - if [ -z "$EXTRA_TESTS" ]; then export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1; export BOOST_LOG_TEST_WITHOUT_EXAMPLES=1; fi - - ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET cxxstd=$CXXSTD ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on visibility=global} ${LINKFLAGS:+linkflags=$LINKFLAGS} + - ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET cxxstd=$CXXSTD ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on visibility=global} ${CXXFLAGS:+cxxflags="$CXXFLAGS"} ${LINKFLAGS:+linkflags="$LINKFLAGS"} notifications: email: From 9ce37914afb154539117f62c80c956fcb237e520 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 15:10:37 +0300 Subject: [PATCH 038/309] Changed older clang jobs to Precise images because their apt sources are not registered for Trusty and Xenial in Travis CI. --- .travis.yml | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 93fedc0d7f..741e2aa4e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -145,7 +145,7 @@ matrix: # clang, Linux - os: linux - dist: trusty + dist: precise compiler: clang-3.5 env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11 addons: @@ -156,10 +156,10 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.5 + - llvm-toolchain-precise-3.5 - os: linux - dist: trusty + dist: precise compiler: clang-3.6 env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11 addons: @@ -170,10 +170,10 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.6 + - llvm-toolchain-precise-3.6 - os: linux - dist: trusty + dist: precise compiler: clang-3.7 env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11 addons: @@ -184,10 +184,10 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.7 + - llvm-toolchain-precise-3.7 - os: linux - dist: trusty + dist: precise compiler: clang-3.8 env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z addons: @@ -198,7 +198,7 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.8 + - llvm-toolchain-precise-3.8 - os: linux dist: trusty @@ -215,6 +215,7 @@ matrix: - llvm-toolchain-trusty-3.9 - os: linux + dist: trusty compiler: clang-4 env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z addons: @@ -225,9 +226,10 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-4.0 + - llvm-toolchain-trusty-4.0 - os: linux + dist: trusty compiler: clang-5 env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z addons: @@ -238,7 +240,7 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-5.0 + - llvm-toolchain-trusty-5.0 - os: linux compiler: clang-6 @@ -292,10 +294,9 @@ matrix: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-8 -# Note: libc++ currently causes linking errors about missing operator new/delete with std::align_val_t arguments in C++17 - os: linux compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++ -fno-aligned-new" LINKFLAGS="-stdlib=libc++" + env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: @@ -303,13 +304,14 @@ matrix: - g++-8-multilib - linux-libc-dev:i386 - libc++-dev + - libc++abi-dev sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-8 - os: linux compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++ -fno-aligned-new" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: @@ -317,6 +319,7 @@ matrix: - g++-8-multilib - linux-libc-dev:i386 - libc++-dev + - libc++abi-dev sources: - ubuntu-toolchain-r-test - llvm-toolchain-xenial-8 From 5bc02d4c4cf7aec26a34133da06a2235e093c539 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Jun 2019 19:00:16 +0300 Subject: [PATCH 039/309] Removed Precise images as they have outdated git. Switched to manual specification of Debian sources for clang. Switched to Bionic images where possible. --- .travis.yml | 79 +++++++++++++++++++++++++++++++++++------------------ 1 file changed, 52 insertions(+), 27 deletions(-) diff --git a/.travis.yml b/.travis.yml index 741e2aa4e8..4d1790192a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ os: - linux - osx -dist: xenial +dist: bionic branches: only: @@ -48,7 +48,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: trusty + dist: xenial compiler: gcc-4.8 env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=03,11 addons: @@ -61,7 +61,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: trusty + dist: xenial compiler: gcc-4.9 env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=03,11 addons: @@ -74,6 +74,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-5 env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14 addons: @@ -86,6 +87,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-6 env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z addons: @@ -98,6 +100,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-7 env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,17 addons: @@ -110,6 +113,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-8 env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 addons: @@ -122,6 +126,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-9 env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 addons: @@ -134,6 +139,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux + dist: bionic compiler: gcc-UBSAN env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: @@ -145,7 +151,7 @@ matrix: # clang, Linux - os: linux - dist: precise + dist: trusty compiler: clang-3.5 env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11 addons: @@ -156,10 +162,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.5 + - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.5 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: precise + dist: trusty compiler: clang-3.6 env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11 addons: @@ -170,10 +177,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.6 + - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.6 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: precise + dist: trusty compiler: clang-3.7 env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11 addons: @@ -184,10 +192,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.7 + - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: precise + dist: xenial compiler: clang-3.8 env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z addons: @@ -198,10 +207,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-precise-3.8 + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.8 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: trusty + dist: xenial compiler: clang-3.9 env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=03,11,14,1z addons: @@ -212,10 +222,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-3.9 + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: trusty + dist: xenial compiler: clang-4 env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z addons: @@ -226,10 +237,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-4.0 + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: trusty + dist: bionic compiler: clang-5 env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z addons: @@ -240,9 +252,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-5.0 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-5.0 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-6 env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17 addons: @@ -253,9 +267,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-6.0 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-6.0 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-7 env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 addons: @@ -266,9 +282,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-7 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-8 env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 addons: @@ -279,9 +297,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: @@ -292,9 +312,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-libc++ env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -303,13 +325,15 @@ matrix: - clang-8 - g++-8-multilib - linux-libc-dev:i386 - - libc++-dev - - libc++abi-dev + - libc++-8-dev + - libc++abi-8-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux + dist: bionic compiler: clang-libc++-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -318,11 +342,12 @@ matrix: - clang-8 - g++-8-multilib - linux-libc-dev:i386 - - libc++-dev - - libc++abi-dev + - libc++-8-dev + - libc++abi-8-dev sources: - ubuntu-toolchain-r-test - - llvm-toolchain-xenial-8 + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X # OS X jobs time out for some reason From 61c96c519ce77b0d27cb4dd10ffd3aa158a609f3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 25 Jun 2019 12:00:56 +0300 Subject: [PATCH 040/309] Converted Bionic images back to Xenial as apt plugin doesn't work on Bionic. --- .travis.yml | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4d1790192a..d5c7acf359 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ os: - linux - osx -dist: bionic +dist: xenial branches: only: @@ -74,7 +74,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-5 env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14 addons: @@ -87,7 +87,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-6 env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z addons: @@ -100,7 +100,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-7 env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,17 addons: @@ -113,7 +113,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-8 env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 addons: @@ -126,7 +126,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-9 env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 addons: @@ -139,7 +139,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: bionic + dist: xenial compiler: gcc-UBSAN env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: @@ -241,7 +241,7 @@ matrix: key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-5 env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z addons: @@ -252,11 +252,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-5.0 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-6 env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17 addons: @@ -267,11 +267,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-6.0 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-7 env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 addons: @@ -282,11 +282,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-7 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-8 env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 addons: @@ -297,11 +297,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: @@ -312,11 +312,11 @@ matrix: - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-libc++ env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -329,11 +329,11 @@ matrix: - libc++abi-8-dev sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: bionic + dist: xenial compiler: clang-libc++-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -346,7 +346,7 @@ matrix: - libc++abi-8-dev sources: - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-8 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X From 08bd1fb8090a9cff80b408ab102cc1a16ce7f1eb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 25 Jun 2019 18:54:55 +0300 Subject: [PATCH 041/309] Added support for trivial::severity_level to filter/formatter parsers. The default filter/formatter factories will now be able to extract severity level values of type boost::log::trivial::severity_level. For filters, this is only supported for attributes with the "Severity" name. --- doc/changelog.qbk | 1 + example/settings_file/main.cpp | 30 +++-------- example/settings_file/settings.txt | 8 +-- include/boost/log/trivial.hpp | 18 +++++-- src/setup/default_filter_factory.cpp | 49 +++++++++++++++-- src/setup/default_formatter_factory.cpp | 6 ++- src/trivial.cpp | 71 +++++++++++++++++++------ 7 files changed, 133 insertions(+), 50 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 7e9721befc..422e503b1c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -21,6 +21,7 @@ * [link log.detailed.sink_backends.text_ostream Output stream] and [link log.detailed.sink_backends.text_multifile text multi-file] sink backends can now be constructed with named parameters. * Added support for passing arbitrary function objects (as opposed to only __boost_phoenix__ function objects, which were supported before) in the `filter` and `format` named parameters to sink constructors and [link log.detailed.utilities.setup.convenience convenience functions] for initializing sinks. For example, it is now possible to specify C++11 lambda functions directly in these parameters. ([github_issue 63]) +* In the default filter and formatter factories used in [link log.detailed.utilities.setup.filter_formatter filter and formatter parsers], added support for severity level attribute values of type [enumref boost::log::trivial::severity_level `boost::log::trivial::severity_level`]. For filters, the support is limited to attributes with "Severity" name. This relieves the user from having to register filter and formatter factories in order to use `boost::log::trivial::severity_level` with filters and formatters parsed from strings or [link log.detailed.utilities.setup.settings settings]. Note that any other custom severity level enums must still be [link log.extension.settings registered], as before. [*Bug fixes:] diff --git a/example/settings_file/main.cpp b/example/settings_file/main.cpp index 436a572663..eb4a13f921 100644 --- a/example/settings_file/main.cpp +++ b/example/settings_file/main.cpp @@ -18,41 +18,25 @@ // #define BOOST_ALL_DYN_LINK 1 #include -#include #include #include +#include #include #include #include namespace logging = boost::log; namespace attrs = boost::log::attributes; -namespace src = boost::log::sources; - -using boost::shared_ptr; - -// Here we define our application severity levels. -enum severity_level -{ - normal, - notification, - warning, - error, - critical -}; - -// Global logger declaration -BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::severity_logger< >) void try_logging() { - src::severity_logger< >& lg = test_lg::get(); - BOOST_LOG_SEV(lg, normal) << "This is a normal severity record"; - BOOST_LOG_SEV(lg, notification) << "This is a notification severity record"; - BOOST_LOG_SEV(lg, warning) << "This is a warning severity record"; - BOOST_LOG_SEV(lg, error) << "This is a error severity record"; - BOOST_LOG_SEV(lg, critical) << "This is a critical severity record"; + BOOST_LOG_TRIVIAL(trace) << "This is a trace severity record"; + BOOST_LOG_TRIVIAL(debug) << "This is a debug severity record"; + BOOST_LOG_TRIVIAL(info) << "This is an info severity record"; + BOOST_LOG_TRIVIAL(warning) << "This is a warning severity record"; + BOOST_LOG_TRIVIAL(error) << "This is an error severity record"; + BOOST_LOG_TRIVIAL(fatal) << "This is a fatal severity record"; } int main(int argc, char* argv[]) diff --git a/example/settings_file/settings.txt b/example/settings_file/settings.txt index e7f159a538..c9fdb9db3e 100644 --- a/example/settings_file/settings.txt +++ b/example/settings_file/settings.txt @@ -7,14 +7,14 @@ [Core] -Filter="%Severity% >= 2" +Filter="%Severity% >= debug" [Sinks.1] Destination=Console -Format="%TimeStamp% *** %Message%" -Filter="%Tag% | %Severity% > 3" +Format="%TimeStamp% [%Severity%] *** %Message%" +Filter="%Tag% | %Severity% > info" [Sinks.2] @@ -22,4 +22,4 @@ Filter="%Tag% | %Severity% > 3" Destination=TextFile FileName=test.log AutoFlush=true -Format="[%TimeStamp%] %Tag% %Message%" +Format="[%TimeStamp%] [%Severity%] [%Tag%] %Message%" diff --git a/include/boost/log/trivial.hpp b/include/boost/log/trivial.hpp index ece0c900e6..7fb896ac36 100644 --- a/include/boost/log/trivial.hpp +++ b/include/boost/log/trivial.hpp @@ -15,6 +15,7 @@ #ifndef BOOST_LOG_TRIVIAL_HPP_INCLUDED_ #define BOOST_LOG_TRIVIAL_HPP_INCLUDED_ +#include #include #include #include @@ -49,15 +50,26 @@ enum severity_level }; //! Returns stringized enumeration value or \c NULL, if the value is not valid -BOOST_LOG_API const char* to_string(severity_level lvl); +template< typename CharT > +BOOST_LOG_API const CharT* to_string(severity_level lvl); + +//! Returns stringized enumeration value or \c NULL, if the value is not valid +inline const char* to_string(severity_level lvl) +{ + return boost::log::trivial::to_string< char >(lvl); +} + +//! Parses enumeration value from string and returns \c true on success and \c false otherwise +template< typename CharT > +BOOST_LOG_API bool from_string(const CharT* str, std::size_t len, severity_level& lvl); //! Outputs stringized representation of the severity level to the stream template< typename CharT, typename TraitsT > inline std::basic_ostream< CharT, TraitsT >& operator<< ( std::basic_ostream< CharT, TraitsT >& strm, severity_level lvl) { - const char* str = boost::log::trivial::to_string(lvl); - if (str) + const CharT* str = boost::log::trivial::to_string< CharT >(lvl); + if (BOOST_LIKELY(!!str)) strm << str; else strm << static_cast< int >(lvl); diff --git a/src/setup/default_filter_factory.cpp b/src/setup/default_filter_factory.cpp index 225e5d4f48..ff9106efc8 100644 --- a/src/setup/default_filter_factory.cpp +++ b/src/setup/default_filter_factory.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,7 @@ #include #include #include +#include #if defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T) #include #include @@ -140,6 +142,37 @@ class string_predicate : #endif // defined(BOOST_LOG_USE_CHAR) && defined(BOOST_LOG_USE_WCHAR_T) +//! A special filtering predicate that adopts the severity level or string operand to the attribute value character type +template< typename RelationT > +class severity_or_string_predicate : + public string_predicate< RelationT > +{ +private: + typedef string_predicate< RelationT > base_type; + +public: + typedef typename base_type::relation_type relation_type; + typedef typename base_type::result_type result_type; + +public: + template< typename StringT > + severity_or_string_predicate(relation_type const& rel, StringT const& string_operand, boost::log::trivial::severity_level severity_operand) : + base_type(rel, string_operand), + m_severity_operand(severity_operand) + { + } + + using base_type::operator(); + + result_type operator() (boost::log::trivial::severity_level val) const + { + return relation_type::operator() (val, m_severity_operand); + } + +private: + const boost::log::trivial::severity_level m_severity_operand; +}; + //! A filtering predicate for numeric relations template< typename NumericT, typename RelationT > class numeric_predicate : @@ -283,13 +316,23 @@ filter default_filter_factory< CharT >::parse_argument(attribute_name const& nam if (qi::parse(begin, end, qi::long_, int_val) && begin == end) { typedef numeric_predicate< long, RelationT > predicate; - typedef default_attribute_types value_types; + typedef default_attribute_value_types value_types; return predicate_wrapper< value_types, predicate >(name, predicate(RelationT(), arg, int_val)); } else { - typedef string_predicate< RelationT > predicate; - return predicate_wrapper< log::string_types, predicate >(name, predicate(RelationT(), arg)); + boost::log::trivial::severity_level lvl; + if (name == boost::log::aux::default_attribute_names::severity() && boost::log::trivial::from_string(arg.data(), arg.size(), lvl)) + { + typedef severity_or_string_predicate< RelationT > predicate; + typedef mpl::vector< boost::log::trivial::severity_level, BOOST_PP_SEQ_ENUM(BOOST_LOG_STANDARD_STRING_TYPES()) > value_types; + return predicate_wrapper< value_types, predicate >(name, predicate(RelationT(), arg, lvl)); + } + else + { + typedef string_predicate< RelationT > predicate; + return predicate_wrapper< log::string_types, predicate >(name, predicate(RelationT(), arg)); + } } } } diff --git a/src/setup/default_formatter_factory.cpp b/src/setup/default_formatter_factory.cpp index 1f4cda1484..15a0b8384f 100644 --- a/src/setup/default_formatter_factory.cpp +++ b/src/setup/default_formatter_factory.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -56,7 +57,10 @@ namespace aux { #endif #define BOOST_LOG_AUX_LOG_ATTRIBUTE_VALUE_TYPES()\ - (boost::log::attributes::named_scope_list)(boost::log::aux::process::id)BOOST_LOG_AUX_THREAD_ID_TYPE() + (boost::log::trivial::severity_level)\ + (boost::log::attributes::named_scope_list)\ + (boost::log::aux::process::id)\ + BOOST_LOG_AUX_THREAD_ID_TYPE() // The list of the attribute value types supported by the default formatter. Note that we have to exclude std::time_t // as it is an integral type, as well as double from the native time duration types - these are part of arithmetic types already. diff --git a/src/trivial.cpp b/src/trivial.cpp index b2fd280edf..133a1462eb 100644 --- a/src/trivial.cpp +++ b/src/trivial.cpp @@ -43,7 +43,7 @@ BOOST_LOG_API logger::logger_type& logger::get() BOOST_LOG_ANONYMOUS_NAMESPACE { -const unsigned int names_count = 6; +BOOST_CONSTEXPR_OR_CONST unsigned int names_count = 6; template< typename CharT > struct severity_level_names @@ -64,43 +64,82 @@ const CharT severity_level_names< CharT >::names[names_count][8] = } // namespace -BOOST_LOG_API const char* to_string(severity_level lvl) +template< typename CharT > +BOOST_LOG_API const CharT* to_string(severity_level lvl) { - typedef severity_level_names< char > level_names; - if (static_cast< unsigned int >(lvl) < names_count) + typedef severity_level_names< CharT > level_names; + if (BOOST_LIKELY(static_cast< unsigned int >(lvl) < names_count)) return level_names::names[static_cast< unsigned int >(lvl)]; - else - return NULL; + return NULL; +} + +//! Parses enumeration value from string and returns \c true on success and \c false otherwise +template< typename CharT > +BOOST_LOG_API bool from_string(const CharT* str, std::size_t len, severity_level& lvl) +{ + typedef severity_level_names< CharT > level_names; + typedef std::char_traits< CharT > char_traits; + + if (len == 5u) + { + if (char_traits::compare(str, level_names::names[0], len) == 0) + lvl = static_cast< severity_level >(0); + else if (char_traits::compare(str, level_names::names[1], len) == 0) + lvl = static_cast< severity_level >(1); + else if (char_traits::compare(str, level_names::names[4], len) == 0) + lvl = static_cast< severity_level >(4); + else if (char_traits::compare(str, level_names::names[5], len) == 0) + lvl = static_cast< severity_level >(5); + else + goto no_match; + return true; + } + else if (len == 4u) + { + if (char_traits::compare(str, level_names::names[2], len) == 0) + lvl = static_cast< severity_level >(2); + else + goto no_match; + return true; + } + else if (len == 7u) + { + if (char_traits::compare(str, level_names::names[3], len) == 0) + lvl = static_cast< severity_level >(3); + else + goto no_match; + return true; + } + +no_match: + return false; } template< typename CharT, typename TraitsT > BOOST_LOG_API std::basic_istream< CharT, TraitsT >& operator>> ( std::basic_istream< CharT, TraitsT >& strm, severity_level& lvl) { - if (strm.good()) + if (BOOST_LIKELY(strm.good())) { typedef severity_level_names< CharT > level_names; typedef std::basic_string< CharT, TraitsT > string_type; string_type str; strm >> str; - for (unsigned int i = 0; i < names_count; ++i) - { - if (str == level_names::names[i]) - { - lvl = static_cast< severity_level >(i); - return strm; - } - } - strm.setstate(std::ios_base::failbit); + if (BOOST_UNLIKELY(!boost::log::trivial::from_string(str.data(), str.size(), lvl))) + strm.setstate(std::ios_base::failbit); } return strm; } +template BOOST_LOG_API const char* to_string< char >(severity_level lvl); +template BOOST_LOG_API bool from_string< char >(const char* begin, std::size_t len, severity_level& lvl); template BOOST_LOG_API std::basic_istream< char, std::char_traits< char > >& operator>> < char, std::char_traits< char > > ( std::basic_istream< char, std::char_traits< char > >& strm, severity_level& lvl); #ifdef BOOST_LOG_USE_WCHAR_T +template BOOST_LOG_API const wchar_t* to_string< wchar_t >(severity_level lvl); +template BOOST_LOG_API bool from_string< wchar_t >(const wchar_t* begin, std::size_t len, severity_level& lvl); template BOOST_LOG_API std::basic_istream< wchar_t, std::char_traits< wchar_t > >& operator>> < wchar_t, std::char_traits< wchar_t > > ( std::basic_istream< wchar_t, std::char_traits< wchar_t > >& strm, severity_level& lvl); From a71dc018a8dd35b40e53dd01e3313c5546d8d3a2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 25 Jun 2019 19:25:45 +0300 Subject: [PATCH 042/309] Renamed settings_file_formatter_factory to settings_file_custom_factories. Also, updated the example to register filter/formatter factories for the custom severity level. --- example/Jamfile.v2 | 2 +- .../Jamfile.v2 | 3 +- .../main.cpp | 68 +++++++++++++++++-- .../settings.txt | 1 + 4 files changed, 67 insertions(+), 7 deletions(-) rename example/{settings_file_formatter_factory => settings_file_custom_factories}/Jamfile.v2 (98%) rename example/{settings_file_formatter_factory => settings_file_custom_factories}/main.cpp (66%) rename example/{settings_file_formatter_factory => settings_file_custom_factories}/settings.txt (92%) diff --git a/example/Jamfile.v2 b/example/Jamfile.v2 index 6813a2343e..07ad6ccf5a 100644 --- a/example/Jamfile.v2 +++ b/example/Jamfile.v2 @@ -14,7 +14,7 @@ build-project ./multiple_files ; build-project ./multiple_threads ; build-project ./rotating_file ; build-project ./settings_file ; -build-project ./settings_file_formatter_factory ; +build-project ./settings_file_custom_factories ; build-project ./syslog ; build-project ./native_syslog ; build-project ./wide_char ; diff --git a/example/settings_file_formatter_factory/Jamfile.v2 b/example/settings_file_custom_factories/Jamfile.v2 similarity index 98% rename from example/settings_file_formatter_factory/Jamfile.v2 rename to example/settings_file_custom_factories/Jamfile.v2 index 540d97ceaa..8032af9b6e 100644 --- a/example/settings_file_formatter_factory/Jamfile.v2 +++ b/example/settings_file_custom_factories/Jamfile.v2 @@ -53,7 +53,6 @@ project multi:/boost/thread//boost_thread ; -exe settings_file_formatter_factory +exe settings_file_custom_factories : main.cpp ; - diff --git a/example/settings_file_formatter_factory/main.cpp b/example/settings_file_custom_factories/main.cpp similarity index 66% rename from example/settings_file_formatter_factory/main.cpp rename to example/settings_file_custom_factories/main.cpp index 3352a54fba..3d59444bb5 100644 --- a/example/settings_file_formatter_factory/main.cpp +++ b/example/settings_file_custom_factories/main.cpp @@ -10,7 +10,7 @@ * \date 12.05.2010 * * \brief An example of initializing the library from a settings file, - * with a custom formatter for an attribute. + * with custom filter and formatter factories for attributes. */ // #define BOOST_ALL_DYN_LINK 1 @@ -29,12 +29,14 @@ #include #include #include +#include #include namespace logging = boost::log; namespace attrs = boost::log::attributes; namespace src = boost::log::sources; +//! Enum for our custom severity levels enum severity_level { normal, @@ -44,7 +46,57 @@ enum severity_level critical }; -BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::severity_logger< >) +//! Formatting operator for severity levels +inline std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + switch (level) + { + case normal: + strm << "normal"; + break; + case notification: + strm << "notification"; + break; + case warning: + strm << "warning"; + break; + case error: + strm << "error"; + break; + case critical: + strm << "critical"; + break; + default: + strm << static_cast< int >(level); + break; + } + + return strm; +} + +//! Parsing operator for severity levels +inline std::istream& operator>> (std::istream& strm, severity_level& level) +{ + if (strm.good()) + { + std::string str; + strm >> str; + if (str == "normal") + level = normal; + else if (str == "notification") + level = notification; + else if (str == "warning") + level = warning; + else if (str == "error") + level = error; + else if (str == "critical") + level = critical; + else + strm.setstate(std::ios_base::failbit); + } + + return strm; +} //! Our custom formatter for the scope list struct scope_list_formatter @@ -103,24 +155,32 @@ void init_logging() // First thing - register the custom formatter for MyScopes logging::register_formatter_factory("MyScopes", boost::make_shared< my_scopes_formatter_factory >()); + // Also register filter and formatter factories for our custom severity level enum. Since our operator<< and operator>> implement + // all required behavior, simple factories provided by Boost.Log will do. + logging::register_simple_filter_factory< severity_level >("Severity"); + logging::register_simple_formatter_factory< severity_level, char >("Severity"); + // Then load the settings from the file std::ifstream settings("settings.txt"); if (!settings.is_open()) throw std::runtime_error("Could not open settings.txt file"); logging::init_from_stream(settings); - // Add some attributes + // Add some attributes. Note that severity level will be provided by the logger, so we don't need to add it here. logging::add_common_attributes(); logging::core::get()->add_global_attribute("MyScopes", attrs::named_scope()); } +//! Global logger, which we will use to write log messages +BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::severity_logger< severity_level >) + //! The function tests logging void try_logging() { BOOST_LOG_FUNCTION(); - src::severity_logger< >& lg = test_lg::get(); + src::severity_logger< severity_level >& lg = test_lg::get(); BOOST_LOG_SEV(lg, critical) << "This is a critical severity record"; diff --git a/example/settings_file_formatter_factory/settings.txt b/example/settings_file_custom_factories/settings.txt similarity index 92% rename from example/settings_file_formatter_factory/settings.txt rename to example/settings_file_custom_factories/settings.txt index e4848a005e..98d8d7fd6d 100644 --- a/example/settings_file_formatter_factory/settings.txt +++ b/example/settings_file_custom_factories/settings.txt @@ -9,5 +9,6 @@ Destination=TextFile FileName=test.log AutoFlush=true +Filter="%Severity% > normal" Format="[%TimeStamp%] [%Severity%]\n%MyScopes%\n\t:: %Message%" Asynchronous=false From 1ce3c06ac635d847fef8a446691959e1845b654e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 25 Jun 2019 20:10:50 +0300 Subject: [PATCH 043/309] Added a compilable example for initialization from a settings container. The new example demostrates working with the settings container directly and provides a more complete view on the library initialization. Closes https://github.com/boostorg/log/issues/87. --- doc/log.qbk | 1 + doc/utilities.qbk | 25 ++---- example/doc/util_setup_settings.cpp | 118 ++++++++++++++++++++++++++++ 3 files changed, 124 insertions(+), 20 deletions(-) create mode 100644 example/doc/util_setup_settings.cpp diff --git a/doc/log.qbk b/doc/log.qbk index 43e8ddac5c..e740587cf5 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -110,6 +110,7 @@ [import ../example/doc/util_dynamic_type_disp.cpp] [import ../example/doc/util_manip_to_log.cpp] [import ../example/doc/util_ipc_reliable_mq_writer.cpp] +[import ../example/doc/util_setup_settings.cpp] [import ../example/doc/extension_stat_collector.cpp] [import ../example/doc/extension_app_launcher.cpp] [import ../example/doc/extension_record_tagger.cpp] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index c80bee5471..aec780922b 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -659,28 +659,13 @@ The RotationTimePoint parameter should have one of the following formats, accord The user is free to fill the settings container from whatever settings source he needs. The usage example is below: - void init_logging() - { - logging::settings setts; - - setts["Core"]["Filter"] = "%Severity% >= warning"; - setts["Core"]["DisableLogging"] = false; +[example_util_setup_settings] - // Subsections can be referred to with a single path - setts["Sinks.Console"]["Destination"] = "Console"; - setts["Sinks.Console"]["Filter"] = "%Severity% >= fatal"; - setts["Sinks.Console"]["AutoFlush"] = true; +[@boost:/libs/log/example/doc/util_setup_settings.cpp See the complete code]. - // ...as well as the individual parameters - setts["Sinks.File.Destination"] = "TextFile"; - setts["Sinks.File.FileName"] = "MyApp_%3N.log"; - setts["Sinks.File.AutoFlush"] = true; - setts["Sinks.File.RotationSize"] = 10 * 1024 * 1024; // 10 MiB - - logging::init_from_settings(setts); - } +[note Initialization from settings does not automatically create any attributes or loggers, the application developer is still responsible for creating those. It can be said that loggers and attributes define the data that is exported by the application and the settings only describe how that data is going to be presented to the application user.] -The settings reader also allows to be extended to support custom sink types. See the [link log.extension.settings Extending the library] section for more information. +The settings reader also can be extended to support custom sink types. See the [link log.extension.settings Extending the library] section for more information. [endsect] @@ -688,7 +673,7 @@ The settings reader also allows to be extended to support custom sink types. See #include <``[boost_log_utility_setup_from_stream_hpp]``> -Support for configuration files is a frequently requested feature of the library. And despite the fact there is no ultimately convenient and flexible format of the library settings, the library provides preliminary support for this feature. The functionality is implemented with a simple function [funcref boost::log::init_from_stream `init_from_stream`], which accepts an STL input stream and reads the library settings from it. The function then passes on the read settings to the [funcref boost::log::init_from_settings `init_from_settings`] function, described [link log.detailed.utilities.setup.settings above]. Therefore the parameter names and their meaning is the same as for the [funcref boost::log::init_from_settings `init_from_settings`] function. +Support for configuration files is a frequently requested feature of the library. And despite the fact there is no ultimately convenient and flexible format of the library settings, the library provides preliminary support for this feature. The functionality is implemented with a simple function [funcref boost::log::init_from_stream `init_from_stream`], which accepts a `std::istream` and reads the library settings from it. The function then passes on the read settings to the [funcref boost::log::init_from_settings `init_from_settings`] function, described [link log.detailed.utilities.setup.settings above]. Therefore the parameter names and their meaning is the same as for the [funcref boost::log::init_from_settings `init_from_settings`] function. The settings format is quite simple and widely used. Below is the description of syntax and parameters. diff --git a/example/doc/util_setup_settings.cpp b/example/doc/util_setup_settings.cpp new file mode 100644 index 0000000000..875df30cb1 --- /dev/null +++ b/example/doc/util_setup_settings.cpp @@ -0,0 +1,118 @@ +/* + * Copyright Andrey Semashev 2019. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace logging = boost::log; +namespace src = boost::log::sources; + +// Let's define our own severity levels +enum severity_level +{ + normal, + notification, + warning, + error, + critical +}; + +const char* const severity_strings[] = +{ + "normal", + "notification", + "warning", + "error", + "critical" +}; + +// The operator puts a human-friendly representation of the severity level to the stream +std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + if (static_cast< std::size_t >(level) < sizeof(severity_strings) / sizeof(*severity_strings)) + strm << severity_strings[level]; + else + strm << static_cast< int >(level); + + return strm; +} + +// The operator parses the severity level from the stream +std::istream& operator>> (std::istream& strm, severity_level& level) +{ + if (strm.good()) + { + std::string str; + strm >> str; + + for (unsigned int i = 0; i < sizeof(severity_strings) / sizeof(*severity_strings); ++i) + { + if (str == severity_strings[i]) + { + level = static_cast< severity_level >(i); + return strm; + } + } + + strm.setstate(std::ios_base::failbit); + } + + return strm; +} + +void init_logging() +{ + // Before initializing the library from settings, we need to register any custom filter and formatter factories + logging::register_simple_filter_factory< severity_level >("Severity"); + logging::register_simple_formatter_factory< severity_level, char >("Severity"); + +//[ example_util_setup_settings + logging::settings setts; + + setts["Core"]["Filter"] = "%Severity% >= warning"; + setts["Core"]["DisableLogging"] = false; + + // Subsections can be referred to with a single path + setts["Sinks.Console"]["Destination"] = "Console"; + setts["Sinks.Console"]["Filter"] = "%Severity% >= critical"; + setts["Sinks.Console"]["Format"] = "%TimeStamp% [%Severity%] %Message%"; + setts["Sinks.Console"]["AutoFlush"] = true; + + // ...as well as the individual parameters + setts["Sinks.File.Destination"] = "TextFile"; + setts["Sinks.File.FileName"] = "MyApp_%3N.log"; + setts["Sinks.File.AutoFlush"] = true; + setts["Sinks.File.RotationSize"] = 10 * 1024 * 1024; // 10 MiB + setts["Sinks.File.Format"] = "%TimeStamp% [%Severity%] %Message%"; + + logging::init_from_settings(setts); +//] + + // Add attributes + logging::add_common_attributes(); +} + +int main(int, char*[]) +{ + init_logging(); + + src::severity_logger< severity_level > lg; + + BOOST_LOG_SEV(lg, normal) << "A regular message"; + BOOST_LOG_SEV(lg, warning) << "Something bad is going on but I can handle it"; + BOOST_LOG_SEV(lg, critical) << "Everything crumbles, shoot me now!"; + + return 0; +} From ca227bc2f30d65f14719a674247728647caa2b2f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 25 Jun 2019 20:21:27 +0300 Subject: [PATCH 044/309] Added a link to a more complete example for reading settings from file. --- doc/utilities.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/utilities.qbk b/doc/utilities.qbk index aec780922b..0f92aa35dc 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -718,6 +718,8 @@ Here's the usage example: return 0; } +See a [@boost:/libs/log/example/settings_file/main.cpp more complete example]. + [endsect] [endsect] From 77f6eba408ab88630a997d41324e5ddf369f8aa8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 14 Oct 2019 00:03:40 +0300 Subject: [PATCH 045/309] Added compiler barrier definition for clang-win to silence deprecated warnings. --- include/boost/log/detail/adaptive_mutex.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index 70efd92e7c..a142a6a406 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -44,6 +44,8 @@ #if defined(__INTEL_COMPILER) || defined(_MSC_VER) # if defined(__INTEL_COMPILER) # define BOOST_LOG_COMPILER_BARRIER __memory_barrier() +# elif defined(__clang__) // clang-win also defines _MSC_VER +# define BOOST_LOG_COMPILER_BARRIER __atomic_signal_fence(__ATOMIC_SEQ_CST) # else extern "C" void _ReadWriteBarrier(void); # if defined(BOOST_MSVC) From 81bc040eb58fda461dfdce7e0b545ff00f2dd4de Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 14 Oct 2019 00:17:44 +0300 Subject: [PATCH 046/309] Added more compilers to CI. --- .travis.yml | 63 ++++++++++++++++++++++++++++++++-------------------- appveyor.yml | 12 +++++++++- 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/.travis.yml b/.travis.yml index d5c7acf359..7f1860f3bc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ os: - linux - osx -dist: xenial +dist: bionic branches: only: @@ -126,7 +126,7 @@ matrix: - ubuntu-toolchain-r-test - os: linux - dist: xenial + dist: bionic compiler: gcc-9 env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 addons: @@ -136,10 +136,10 @@ matrix: - g++-9-multilib - linux-libc-dev:i386 sources: - - ubuntu-toolchain-r-test + - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux - dist: xenial + dist: bionic compiler: gcc-UBSAN env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: @@ -147,7 +147,7 @@ matrix: packages: - g++-9 sources: - - ubuntu-toolchain-r-test + - sourceline: "ppa:ubuntu-toolchain-r/test" # clang, Linux - os: linux @@ -300,53 +300,68 @@ matrix: - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" + - os: linux + dist: xenial + compiler: clang-9 + env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 + addons: + apt: + packages: + - clang-9 + - g++-9-multilib + - linux-libc-dev:i386 + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" + - os: linux dist: xenial compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - - clang-8 - - g++-8-multilib + - clang-9 + - g++-9-multilib - linux-libc-dev:i386 sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" + - sourceline: "ppa:ubuntu-toolchain-r/test" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-8 - - g++-8-multilib + - clang-9 + - g++-9-multilib - linux-libc-dev:i386 - - libc++-8-dev - - libc++abi-8-dev + - libc++-9-dev + - libc++abi-9-dev sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" + - sourceline: "ppa:ubuntu-toolchain-r/test" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-8 - - g++-8-multilib + - clang-9 + - g++-9-multilib - linux-libc-dev:i386 - - libc++-8-dev - - libc++abi-8-dev + - libc++-9-dev + - libc++abi-9-dev sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" + - sourceline: "ppa:ubuntu-toolchain-r/test" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X diff --git a/appveyor.yml b/appveyor.yml index 6c2fa23727..c13d4ca3d1 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -31,8 +31,13 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.1 ADDRESS_MODEL: 64 - EXTRA_TESTS: 1 + CXXSTD: 14,17 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - TOOLSET: msvc-14.2 + ADDRESS_MODEL: 64 + CXXSTD: 14,17 + EXTRA_TESTS: 1 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: gcc ADDRESS_MODEL: 64 CXXSTD: 03,11 @@ -68,7 +73,12 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.1 ADDRESS_MODEL: 32 + CXXSTD: 14,17 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + - TOOLSET: msvc-14.2 + ADDRESS_MODEL: 32 + CXXSTD: 14,17 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: gcc ADDRESS_MODEL: 32 CXXSTD: 03,11 From 710bd95d36640586698fd3fe5aea863a226fbed2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 14 Oct 2019 23:13:22 +0300 Subject: [PATCH 047/309] Moved extra tests to msvc-14.0 job to avoid job timeouts. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c13d4ca3d1..ee69f21b13 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -28,6 +28,7 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.0 ADDRESS_MODEL: 64 + EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.1 ADDRESS_MODEL: 64 @@ -36,7 +37,6 @@ environment: - TOOLSET: msvc-14.2 ADDRESS_MODEL: 64 CXXSTD: 14,17 - EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: gcc ADDRESS_MODEL: 64 From 84b753da83711838f66d833d22dbb753d0e68b15 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 22 Oct 2019 01:09:48 +0300 Subject: [PATCH 048/309] Removed unnecessary packages from CI jobs, added C++20 testing. --- .travis.yml | 76 ++++++++++++++++------------------------------------- 1 file changed, 22 insertions(+), 54 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f1860f3bc..7a8b2369df 100644 --- a/.travis.yml +++ b/.travis.yml @@ -42,8 +42,6 @@ matrix: apt: packages: - g++-4.7 - - g++-4.7-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test @@ -55,8 +53,6 @@ matrix: apt: packages: - g++-4.8 - - g++-4.8-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test @@ -68,8 +64,6 @@ matrix: apt: packages: - g++-4.9 - - g++-4.9-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test @@ -81,8 +75,6 @@ matrix: apt: packages: - g++-5 - - g++-5-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test @@ -94,8 +86,6 @@ matrix: apt: packages: - g++-6 - - g++-6-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test @@ -107,41 +97,35 @@ matrix: apt: packages: - g++-7 - - g++-7-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - os: linux dist: xenial compiler: gcc-8 - env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17 + env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17,2a addons: apt: packages: - g++-8 - - g++-8-multilib - - linux-libc-dev:i386 sources: - ubuntu-toolchain-r-test - os: linux dist: bionic compiler: gcc-9 - env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 + env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17,2a addons: apt: packages: - g++-9 - - g++-9-multilib - - linux-libc-dev:i386 sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux dist: bionic compiler: gcc-UBSAN - env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: apt: packages: @@ -158,8 +142,7 @@ matrix: apt: packages: - clang-3.5 - - g++-4.9-multilib - - linux-libc-dev:i386 + - libstdc++-4.9-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.5 main" @@ -173,8 +156,7 @@ matrix: apt: packages: - clang-3.6 - - g++-5-multilib - - linux-libc-dev:i386 + - libstdc++-5-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.6 main" @@ -188,8 +170,7 @@ matrix: apt: packages: - clang-3.7 - - g++-5-multilib - - linux-libc-dev:i386 + - libstdc++-5-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main" @@ -203,8 +184,7 @@ matrix: apt: packages: - clang-3.8 - - g++-6-multilib - - linux-libc-dev:i386 + - libstdc++-6-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.8 main" @@ -218,8 +198,7 @@ matrix: apt: packages: - clang-3.9 - - g++-6-multilib - - linux-libc-dev:i386 + - libstdc++-6-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main" @@ -233,8 +212,7 @@ matrix: apt: packages: - clang-4.0 - - g++-6-multilib - - linux-libc-dev:i386 + - libstdc++-6-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main" @@ -248,8 +226,7 @@ matrix: apt: packages: - clang-5.0 - - g++-7-multilib - - linux-libc-dev:i386 + - libstdc++-7-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main" @@ -258,13 +235,12 @@ matrix: - os: linux dist: xenial compiler: clang-6 - env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17 + env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17,2a addons: apt: packages: - clang-6.0 - - g++-8-multilib - - linux-libc-dev:i386 + - libstdc++-8-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" @@ -273,13 +249,12 @@ matrix: - os: linux dist: xenial compiler: clang-7 - env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17 + env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17,2a addons: apt: packages: - clang-7 - - g++-8-multilib - - linux-libc-dev:i386 + - libstdc++-8-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" @@ -288,13 +263,12 @@ matrix: - os: linux dist: xenial compiler: clang-8 - env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17 + env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17,2a addons: apt: packages: - clang-8 - - g++-8-multilib - - linux-libc-dev:i386 + - libstdc++-8-dev sources: - ubuntu-toolchain-r-test - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" @@ -303,13 +277,12 @@ matrix: - os: linux dist: xenial compiler: clang-9 - env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 + env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a addons: apt: packages: - clang-9 - - g++-9-multilib - - linux-libc-dev:i386 + - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" @@ -318,13 +291,12 @@ matrix: - os: linux dist: xenial compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - clang-9 - - g++-9-multilib - - linux-libc-dev:i386 + - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" @@ -333,13 +305,11 @@ matrix: - os: linux dist: xenial compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - clang-9 - - g++-9-multilib - - linux-libc-dev:i386 - libc++-9-dev - libc++abi-9-dev sources: @@ -350,13 +320,11 @@ matrix: - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - clang-9 - - g++-9-multilib - - linux-libc-dev:i386 - libc++-9-dev - libc++abi-9-dev sources: From e80dce7fec7015149f839bc4759985b807c081aa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 22 Oct 2019 20:06:26 +0300 Subject: [PATCH 049/309] Removed unused local typedefs. --- src/setup/init_from_settings.cpp | 1 - src/trivial.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 502f2c8d68..d8da54cdd9 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -156,7 +156,6 @@ inline sinks::auto_newline_mode param_cast_to_auto_newline_mode(const char* para { typedef CharT char_type; typedef boost::log::aux::char_constants< char_type > constants; - typedef boost::log::basic_string_literal< char_type > literal_type; if (value == constants::auto_newline_mode_disabled()) return sinks::disabled_auto_newline; diff --git a/src/trivial.cpp b/src/trivial.cpp index 133a1462eb..1461ad71b3 100644 --- a/src/trivial.cpp +++ b/src/trivial.cpp @@ -121,7 +121,6 @@ BOOST_LOG_API std::basic_istream< CharT, TraitsT >& operator>> ( { if (BOOST_LIKELY(strm.good())) { - typedef severity_level_names< CharT > level_names; typedef std::basic_string< CharT, TraitsT > string_type; string_type str; strm >> str; From 959a97c38b436ddfe6afe2906d255a6b32458fc9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 23 Oct 2019 13:29:50 +0300 Subject: [PATCH 050/309] Avoid using deprecated Boost.Test headers. --- test/run/attr_attribute_value_impl.cpp | 4 ++-- test/run/attr_attribute_value_set.cpp | 2 +- test/run/attr_value_visitation.cpp | 2 +- test/run/util_dynamic_type_disp.cpp | 2 +- test/run/util_static_type_disp.cpp | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/test/run/attr_attribute_value_impl.cpp b/test/run/attr_attribute_value_impl.cpp index 156277a100..682b2e486e 100644 --- a/test/run/attr_attribute_value_impl.cpp +++ b/test/run/attr_attribute_value_impl.cpp @@ -15,10 +15,10 @@ #define BOOST_TEST_MODULE attr_attribute_value_impl #include -#include +#include #include -#include #include +#include #include #include #include diff --git a/test/run/attr_attribute_value_set.cpp b/test/run/attr_attribute_value_set.cpp index 15fdeece9b..1b80673872 100644 --- a/test/run/attr_attribute_value_set.cpp +++ b/test/run/attr_attribute_value_set.cpp @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include #include #include #include diff --git a/test/run/attr_value_visitation.cpp b/test/run/attr_value_visitation.cpp index 11730d8cc7..f057fb17b6 100644 --- a/test/run/attr_value_visitation.cpp +++ b/test/run/attr_value_visitation.cpp @@ -17,7 +17,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/test/run/util_dynamic_type_disp.cpp b/test/run/util_dynamic_type_disp.cpp index 485569d255..e64abb1d6c 100644 --- a/test/run/util_dynamic_type_disp.cpp +++ b/test/run/util_dynamic_type_disp.cpp @@ -16,8 +16,8 @@ #include #include -#include #include +#include #include namespace logging = boost::log; diff --git a/test/run/util_static_type_disp.cpp b/test/run/util_static_type_disp.cpp index e318fc5a53..3f30ad5d51 100644 --- a/test/run/util_static_type_disp.cpp +++ b/test/run/util_static_type_disp.cpp @@ -17,8 +17,8 @@ #include #include #include -#include #include +#include #include namespace logging = boost::log; From a519226b38ed7b922d72a2f83b1f2b18248bbe35 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Tue, 26 Nov 2019 17:28:12 +0200 Subject: [PATCH 051/309] Use throw_exception overload taking source_location --- include/boost/log/detail/adaptive_mutex.hpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index a142a6a406..a073f8bd0b 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -214,11 +214,7 @@ class adaptive_mutex template< typename ExceptionT > static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_exception(int err, const char* descr, const char* func, const char* file, int line) { -#if !defined(BOOST_EXCEPTION_DISABLE) - boost::exception_detail::throw_exception_(ExceptionT(err, descr), func, file, line); -#else - boost::throw_exception(ExceptionT(err, descr)); -#endif + boost::throw_exception(ExceptionT(err, descr), boost::source_location(file, line, func)); } }; From ac17f4adcfa7547a24fe776939171d7f0fbdf142 Mon Sep 17 00:00:00 2001 From: Peter Dimov Date: Wed, 27 Nov 2019 18:47:10 +0200 Subject: [PATCH 052/309] Add source_location #include --- include/boost/log/detail/adaptive_mutex.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index a073f8bd0b..acfc5f3cf0 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -26,6 +26,7 @@ #include #include +#include #if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD From b395be29c24791d40cfd16662d8966895626c150 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 12 Dec 2019 11:53:26 +0300 Subject: [PATCH 053/309] Removed spaces before ticket/issue/PR links in docs, updated copyright years. --- doc/log.qbk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/log.qbk b/doc/log.qbk index e740587cf5..a4083b801f 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -2,7 +2,7 @@ [quickbook 1.5] [version v2] [authors [Semashev, Andrey]] - [copyright 2007 - 2016 Andrey Semashev] + [copyright 2007 - 2019 Andrey Semashev] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -51,9 +51,9 @@ [def __boost_utility__ [@http://www.boost.org/doc/libs/release/libs/utility/utility.htm Boost.Utility]] [def __boost_quickbook__ [@http://www.boost.org/doc/libs/release/doc/html/quickbook.html Boost.Quickbook]] -[template ticket[key] '''#'''[key]''''''] -[template github_issue[key] '''GH#'''[key]''''''] -[template pull_request[key] '''PR#'''[key]''''''] +[template ticket[key]'''#'''[key]''''''] +[template github_issue[key]'''GH#'''[key]''''''] +[template pull_request[key]'''PR#'''[key]''''''] [/ Auto-generated macros that refer to Reference sections /] [include tmp/top_level_reference.qbk] From 10a63204b38bea26765e694d6342aaf3af7c9ec2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 22 Jan 2020 21:37:56 +0300 Subject: [PATCH 054/309] Added a workaround for openlog not saving ident string. Some syslog implementations (e.g. glibc) do not save the ident string in openlog and instead only save a pointer to the user-provided string. This requires the caller to preserve the passed string for the whole duration of logging. Fixes https://github.com/boostorg/log/issues/97. --- doc/changelog.qbk | 8 +++++++- src/syslog_backend.cpp | 22 ++++++++++++++++++++-- 2 files changed, 27 insertions(+), 3 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 422e503b1c..607ea8cad9 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2019. + Copyright Andrey Semashev 2007 - 2020. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.18, Boost 1.73] + +[*Bug fixes:] + +* Added a workaround for some syslog API implementations (e.g. glibc), which do not save the application identification string in `openlog` call. Such implementations could access already freed memory on each `syslog` call, resulting in undefined behavior. ([github_issue 97]) + [heading 2.17, Boost 1.71] [*New features:] diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 1c359454b8..19731880b4 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -134,10 +134,25 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder; #endif + private: + /*! + * \brief Application identification string + * + * \note We have to keep it as an immutable member because some syslog implementations (e.g. glibc) + * do not deep-copy the ident string to internal storage when \c openlog is called + * and instead save a pointer to the user-provided string. This means the user-provided + * string needs to remain accessible for the whole duration of logging. + * + * https://github.com/boostorg/log/issues/97 + * https://sourceware.org/bugzilla/show_bug.cgi?id=25442 + */ + const std::string m_Ident; + public: - native_syslog_initializer(std::string const& ident, int facility) + native_syslog_initializer(std::string const& ident, int facility) : + m_Ident(ident) { - ::openlog((ident.empty() ? static_cast< const char* >(NULL) : ident.c_str()), 0, facility); + ::openlog((m_Ident.empty() ? static_cast< const char* >(NULL) : m_Ident.c_str()), 0, facility); } ~native_syslog_initializer() { @@ -158,6 +173,9 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } return p; } + + BOOST_DELETED_FUNCTION(native_syslog_initializer(native_syslog_initializer const&)) + BOOST_DELETED_FUNCTION(native_syslog_initializer& operator= (native_syslog_initializer const&)) }; } // namespace From 42b4463ad26b19a8e2fc767101614ad5836037c4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 5 Feb 2020 17:30:55 +0300 Subject: [PATCH 055/309] Fixed day kind representation in rotation_at_time_point. Since day_kind is enum, it may be represented by a signed integer type. Some compilers (e.g. MSVC) use sign extension when loading the day kind field from the bit field, which corrupts the monthday value (which is 2) and makes the rotation never happen. Fix this by using an unsigned type to store the day kind and then cast the value to the enum. Also, rearranged the bitfields for slightly better codegen. Fixes https://github.com/boostorg/log/issues/98. --- doc/changelog.qbk | 1 + include/boost/log/sinks/text_file_backend.hpp | 2 +- src/text_file_backend.cpp | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 607ea8cad9..7588e00cfd 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Added a workaround for some syslog API implementations (e.g. glibc), which do not save the application identification string in `openlog` call. Such implementations could access already freed memory on each `syslog` call, resulting in undefined behavior. ([github_issue 97]) +* Fixed that log file rotation on a specific day of month (e.g. `rotation_at_time_point(boost::gregorian::greg_day(1))`) could be silently ignored and not happen. ([github_issue 98]) [heading 2.17, Boost 1.71] diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index d72e4cfb53..719acc958b 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -236,8 +236,8 @@ class rotation_at_time_point monthday }; - day_kind m_DayKind : 2; unsigned char m_Day : 6; + unsigned char m_DayKind : 2; // contains day_kind values unsigned char m_Hour, m_Minute, m_Second; mutable posix_time::ptime m_Previous; diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 50cef3b034..5f664a8241 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1122,7 +1122,7 @@ BOOST_LOG_API bool rotation_at_time_point::operator()() const } const bool time_of_day_passed = rotation_time.total_seconds() <= m_Previous.time_of_day().total_seconds(); - switch (m_DayKind) + switch (static_cast< day_kind >(m_DayKind)) { case not_specified: { From 8a7cc8efd6291b29a9762a49d5b50eb40f43668f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 17 Feb 2020 15:00:14 +0300 Subject: [PATCH 056/309] Move log file status check before renaming to the target file name. If the log file has not been created (e.g. when there are no log records written yet), rotate_file could throw as it attempted to rename the file to the target file name before rotation. The check for file presence that was intended to protect from this was made later on, before the file collector is invoked. This commit moves the check before renaming. --- doc/changelog.qbk | 1 + doc/gen_references.xsl | 2 +- src/text_file_backend.cpp | 30 +++++++++++++++--------------- 3 files changed, 17 insertions(+), 16 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 7588e00cfd..5ca7648e39 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,6 +15,7 @@ * Added a workaround for some syslog API implementations (e.g. glibc), which do not save the application identification string in `openlog` call. Such implementations could access already freed memory on each `syslog` call, resulting in undefined behavior. ([github_issue 97]) * Fixed that log file rotation on a specific day of month (e.g. `rotation_at_time_point(boost::gregorian::greg_day(1))`) could be silently ignored and not happen. ([github_issue 98]) +* Fixed that [link log.detailed.sink_backends.text_file `text_file_backend`]`::rotate_file` could throw if there were no log records written yet and target file name pattern was set. The method would attempt to rename a missing file, which would result in an exception. Note that `rotate_file` may still throw because of a missing log file, if the file being rotated is removed by a third party. [heading 2.17, Boost 1.71] diff --git a/doc/gen_references.xsl b/doc/gen_references.xsl index 9b195eb81f..f95ac1dbcb 100644 --- a/doc/gen_references.xsl +++ b/doc/gen_references.xsl @@ -13,7 +13,7 @@ [/ - Copyright Andrey Semashev 2007 - 2017. + Copyright Andrey Semashev 2007 - 2020. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 5f664a8241..8624b43336 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1482,26 +1482,26 @@ BOOST_LOG_API void text_file_backend::rotate_file() filesystem::path prev_file_name = m_pImpl->m_FileName; close_file(); - if (!!m_pImpl->m_TargetFileNameGenerator) + // Check if the file has been created in the first place + system::error_code ec; + filesystem::file_status status = filesystem::status(prev_file_name, ec); + if (status.type() == filesystem::regular_file) { - filesystem::path new_file_name; - new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); - - if (new_file_name != prev_file_name) + if (!!m_pImpl->m_TargetFileNameGenerator) { - filesystem::create_directories(new_file_name.parent_path()); - move_file(prev_file_name, new_file_name); + filesystem::path new_file_name; + new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); - prev_file_name.swap(new_file_name); + if (new_file_name != prev_file_name) + { + filesystem::create_directories(new_file_name.parent_path()); + move_file(prev_file_name, new_file_name); + + prev_file_name.swap(new_file_name); + } } - } - if (!!m_pImpl->m_pFileCollector) - { - // Check if the file has not been deleted by another process - system::error_code ec; - filesystem::file_status status = filesystem::status(prev_file_name, ec); - if (status.type() == filesystem::regular_file) + if (!!m_pImpl->m_pFileCollector) m_pImpl->m_pFileCollector->store_file(prev_file_name); } } From c721453aeb2c42e10b9d91cd06302731d0a8234b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 17 Feb 2020 15:49:58 +0300 Subject: [PATCH 057/309] Ported named_scope_list and pool_allocator to allocator_traits. This fixes compilation problems with C++20 std::allocator, which removed deprecated typedefs and member functions. Closes https://github.com/boostorg/log/pull/100. --- doc/changelog.qbk | 1 + include/boost/log/attributes/named_scope.hpp | 15 ++++----- src/attribute_set_impl.hpp | 33 +++++++++++--------- src/named_scope.cpp | 9 +++--- 4 files changed, 33 insertions(+), 25 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 5ca7648e39..2047817593 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -16,6 +16,7 @@ * Added a workaround for some syslog API implementations (e.g. glibc), which do not save the application identification string in `openlog` call. Such implementations could access already freed memory on each `syslog` call, resulting in undefined behavior. ([github_issue 97]) * Fixed that log file rotation on a specific day of month (e.g. `rotation_at_time_point(boost::gregorian::greg_day(1))`) could be silently ignored and not happen. ([github_issue 98]) * Fixed that [link log.detailed.sink_backends.text_file `text_file_backend`]`::rotate_file` could throw if there were no log records written yet and target file name pattern was set. The method would attempt to rename a missing file, which would result in an exception. Note that `rotate_file` may still throw because of a missing log file, if the file being rotated is removed by a third party. +* Ported various components of the library to `std::allocator_traits` to improve compatibility with C++20 allocators. [heading 2.17, Boost 1.71] diff --git a/include/boost/log/attributes/named_scope.hpp b/include/boost/log/attributes/named_scope.hpp index 5b33518ddb..2caead3609 100644 --- a/include/boost/log/attributes/named_scope.hpp +++ b/include/boost/log/attributes/named_scope.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -124,13 +125,13 @@ class named_scope_list typedef std::allocator< named_scope_entry > allocator_type; // Standard types - typedef allocator_type::value_type value_type; - typedef allocator_type::reference reference; - typedef allocator_type::const_reference const_reference; - typedef allocator_type::pointer pointer; - typedef allocator_type::const_pointer const_pointer; - typedef allocator_type::size_type size_type; - typedef allocator_type::difference_type difference_type; + typedef log::aux::allocator_traits< allocator_type >::value_type value_type; + typedef log::aux::allocator_traits< allocator_type >::size_type size_type; + typedef log::aux::allocator_traits< allocator_type >::difference_type difference_type; + typedef log::aux::allocator_traits< allocator_type >::pointer pointer; + typedef log::aux::allocator_traits< allocator_type >::const_pointer const_pointer; + typedef value_type& reference; + typedef value_type const& const_reference; #ifndef BOOST_LOG_DOXYGEN_PASS diff --git a/src/attribute_set_impl.hpp b/src/attribute_set_impl.hpp index e9de28ec80..044a8e764f 100644 --- a/src/attribute_set_impl.hpp +++ b/src/attribute_set_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2020. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -30,6 +30,7 @@ #include #include #include +#include #include #ifndef BOOST_LOG_HASH_TABLE_SIZE_LOG @@ -62,13 +63,13 @@ class pool_allocator : #if BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > 0 - typedef typename base_type::value_type value_type; - typedef typename base_type::size_type size_type; - typedef typename base_type::difference_type difference_type; - typedef typename base_type::pointer pointer; - typedef typename base_type::const_pointer const_pointer; - typedef typename base_type::reference reference; - typedef typename base_type::const_reference const_reference; + typedef typename log::aux::allocator_traits< base_type >::value_type value_type; + typedef typename log::aux::allocator_traits< base_type >::size_type size_type; + typedef typename log::aux::allocator_traits< base_type >::difference_type difference_type; + typedef typename log::aux::allocator_traits< base_type >::pointer pointer; + typedef typename log::aux::allocator_traits< base_type >::const_pointer const_pointer; + typedef value_type& reference; + typedef value_type const& const_reference; private: array< pointer, BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > m_Pool; @@ -96,7 +97,7 @@ class pool_allocator : { for (size_type i = 0; i < m_PooledCount; ++i) { - base_type::deallocate(m_Pool[i], 1); + log::aux::allocator_traits< base_type >::deallocate(*static_cast< base_type* >(this), m_Pool[i], 1); } } @@ -116,24 +117,28 @@ class pool_allocator : pointer allocate(size_type n, const void* hint = NULL) { - if (m_PooledCount > 0) + if (BOOST_LIKELY(m_PooledCount > 0)) { --m_PooledCount; return m_Pool[m_PooledCount]; } else - return base_type::allocate(n, hint); + { + return log::aux::allocator_traits< base_type >::allocate(*static_cast< base_type* >(this), n, hint); + } } void deallocate(pointer p, size_type n) { - if (m_PooledCount < m_Pool.size()) + if (BOOST_LIKELY(m_PooledCount < m_Pool.size())) { m_Pool[m_PooledCount] = p; ++m_PooledCount; } else - base_type::deallocate(p, n); + { + log::aux::allocator_traits< base_type >::deallocate(*static_cast< base_type* >(this), p, n); + } } #else @@ -195,7 +200,7 @@ struct attribute_set::implementation }; //! A list of buckets - typedef boost::array< bucket, 1U << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets; + typedef boost::array< bucket, 1u << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets; //! Cleanup function object used to erase elements from the container struct disposer diff --git a/src/named_scope.cpp b/src/named_scope.cpp index 5fa634a380..fff80a1d4a 100644 --- a/src/named_scope.cpp +++ b/src/named_scope.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #if !defined(BOOST_LOG_NO_THREADS) #include @@ -210,11 +211,11 @@ BOOST_LOG_API named_scope_list::named_scope_list(named_scope_list const& that) : if (m_Size > 0) { // Copy the container contents - pointer p = allocator_type::allocate(that.size()); + pointer p = log::aux::allocator_traits< allocator_type >::allocate(*static_cast< allocator_type* >(this), that.size()); aux::named_scope_list_node* prev = &m_RootNode; for (const_iterator src = that.begin(), end = that.end(); src != end; ++src, ++p) { - allocator_type::construct(p, *src); // won't throw + log::aux::allocator_traits< allocator_type >::construct(*static_cast< allocator_type* >(this), p, *src); // won't throw p->_m_pPrev = prev; prev->_m_pNext = p; prev = p; @@ -232,8 +233,8 @@ BOOST_LOG_API named_scope_list::~named_scope_list() iterator it(m_RootNode._m_pNext); iterator end(&m_RootNode); while (it != end) - allocator_type::destroy(&*(it++)); - allocator_type::deallocate(static_cast< pointer >(m_RootNode._m_pNext), m_Size); + log::aux::allocator_traits< allocator_type >::destroy(*static_cast< allocator_type* >(this), &*(it++)); + log::aux::allocator_traits< allocator_type >::deallocate(*static_cast< allocator_type* >(this), static_cast< pointer >(m_RootNode._m_pNext), m_Size); } } From 34d9e64815894ef549d30b84d29aa34dce03c58f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 17 Feb 2020 15:54:45 +0300 Subject: [PATCH 058/309] Reordered day and day kind initializers to match declaration order. Silences compiler warnings. --- src/text_file_backend.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 8624b43336..9cca651e9d 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1061,8 +1061,8 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( unsigned char minute, unsigned char second ) : - m_DayKind(not_specified), m_Day(0), + m_DayKind(not_specified), m_Hour(hour), m_Minute(minute), m_Second(second), @@ -1078,8 +1078,8 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( unsigned char minute, unsigned char second ) : - m_DayKind(weekday), m_Day(static_cast< unsigned char >(wday)), + m_DayKind(weekday), m_Hour(hour), m_Minute(minute), m_Second(second), @@ -1095,8 +1095,8 @@ BOOST_LOG_API rotation_at_time_point::rotation_at_time_point( unsigned char minute, unsigned char second ) : - m_DayKind(monthday), m_Day(static_cast< unsigned char >(mday.as_number())), + m_DayKind(monthday), m_Hour(hour), m_Minute(minute), m_Second(second), From e7bcb0ac4b9bb34257ca60ae210cbdc2a1d2dea9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 17 Feb 2020 18:28:39 +0300 Subject: [PATCH 059/309] Converted some uses of Boost.MPL to Boost.TypeTraits. --- .../boost/log/attributes/attribute_set.hpp | 6 +-- .../boost/log/attributes/mutable_constant.hpp | 6 +-- include/boost/log/attributes/named_scope.hpp | 6 +-- .../boost/log/utility/functional/in_range.hpp | 8 ++-- .../boost/log/utility/functional/logical.hpp | 45 +++++++++---------- .../log/utility/manipulators/add_value.hpp | 10 ++--- include/boost/log/utility/setup/settings.hpp | 4 +- 7 files changed, 43 insertions(+), 42 deletions(-) diff --git a/include/boost/log/attributes/attribute_set.hpp b/include/boost/log/attributes/attribute_set.hpp index 05fa3aaa96..2d2a987a98 100644 --- a/include/boost/log/attributes/attribute_set.hpp +++ b/include/boost/log/attributes/attribute_set.hpp @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -157,12 +157,12 @@ class attribute_set // Standard typedefs typedef attribute_set::difference_type difference_type; typedef attribute_set::value_type value_type; - typedef typename mpl::if_c< + typedef typename boost::conditional< fConstV, attribute_set::const_reference, attribute_set::reference >::type reference; - typedef typename mpl::if_c< + typedef typename boost::conditional< fConstV, attribute_set::const_pointer, attribute_set::pointer diff --git a/include/boost/log/attributes/mutable_constant.hpp b/include/boost/log/attributes/mutable_constant.hpp index 6ff76ddc2c..9357dafa02 100644 --- a/include/boost/log/attributes/mutable_constant.hpp +++ b/include/boost/log/attributes/mutable_constant.hpp @@ -17,10 +17,10 @@ #include #include -#include #include #include #include +#include #include #include #include @@ -60,7 +60,7 @@ template< typename MutexT = void, typename ScopedWriteLockT = #ifndef BOOST_LOG_NO_THREADS - typename mpl::if_c< + typename boost::conditional< boost::log::aux::is_exclusively_lockable< MutexT >::value, boost::log::aux::exclusive_lock_guard< MutexT >, void @@ -70,7 +70,7 @@ template< #endif // BOOST_LOG_NO_THREADS typename ScopedReadLockT = #ifndef BOOST_LOG_NO_THREADS - typename mpl::if_c< + typename boost::conditional< boost::log::aux::is_shared_lockable< MutexT >::value, boost::log::aux::shared_lock_guard< MutexT >, ScopedWriteLockT diff --git a/include/boost/log/attributes/named_scope.hpp b/include/boost/log/attributes/named_scope.hpp index 2caead3609..ed338c6726 100644 --- a/include/boost/log/attributes/named_scope.hpp +++ b/include/boost/log/attributes/named_scope.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include #include #include @@ -150,12 +150,12 @@ class named_scope_list // Standard typedefs typedef named_scope_list::difference_type difference_type; typedef named_scope_list::value_type value_type; - typedef typename mpl::if_c< + typedef typename boost::conditional< fConstV, named_scope_list::const_reference, named_scope_list::reference >::type reference; - typedef typename mpl::if_c< + typedef typename boost::conditional< fConstV, named_scope_list::const_pointer, named_scope_list::pointer diff --git a/include/boost/log/utility/functional/in_range.hpp b/include/boost/log/utility/functional/in_range.hpp index b87160ef03..90d3b3344d 100644 --- a/include/boost/log/utility/functional/in_range.hpp +++ b/include/boost/log/utility/functional/in_range.hpp @@ -16,6 +16,8 @@ #define BOOST_LOG_UTILITY_FUNCTIONAL_IN_RANGE_HPP_INCLUDED_ #include +#include +#include #include #include // make_common_integral_type #include @@ -36,17 +38,17 @@ struct in_range_fun template< typename T, typename U > bool operator() (T const& value, std::pair< U, U > const& rng) const { - return op(value, rng, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(value, rng, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& value, std::pair< U, U > const& rng, mpl::false_ const&) + static bool op(T const& value, std::pair< U, U > const& rng, false_type) { return (value >= rng.first && value < rng.second); } template< typename T, typename U > - static bool op(T const& value, std::pair< U, U > const& rng, mpl::true_ const&) + static bool op(T const& value, std::pair< U, U > const& rng, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return (static_cast< common_integral_type >(value) >= static_cast< common_integral_type >(rng.first)) diff --git a/include/boost/log/utility/functional/logical.hpp b/include/boost/log/utility/functional/logical.hpp index bdba8b8f8d..9481e473a3 100644 --- a/include/boost/log/utility/functional/logical.hpp +++ b/include/boost/log/utility/functional/logical.hpp @@ -21,11 +21,10 @@ #ifndef BOOST_LOG_UTILITY_FUNCTIONAL_LOGICAL_HPP_INCLUDED_ #define BOOST_LOG_UTILITY_FUNCTIONAL_LOGICAL_HPP_INCLUDED_ -#include -#include -#include #include #include +#include +#include #include #include @@ -56,8 +55,8 @@ struct make_common_integral_type< T, U, TSizeV, USizeV, true > //! Specialization for the case when both types have the same size template< typename T, typename U, unsigned int SizeV > struct make_common_integral_type< T, U, SizeV, SizeV, false > : - public mpl::if_< - is_unsigned< T >, + public boost::conditional< + is_unsigned< T >::value, T, U > @@ -74,17 +73,17 @@ struct equal_to template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left == right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) == static_cast< common_integral_type >(right); @@ -99,17 +98,17 @@ struct not_equal_to template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left != right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) != static_cast< common_integral_type >(right); @@ -124,17 +123,17 @@ struct less template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left < right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) < static_cast< common_integral_type >(right); @@ -149,17 +148,17 @@ struct greater template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left > right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) > static_cast< common_integral_type >(right); @@ -174,17 +173,17 @@ struct less_equal template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left <= right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) <= static_cast< common_integral_type >(right); @@ -199,17 +198,17 @@ struct greater_equal template< typename T, typename U > bool operator() (T const& left, U const& right) const { - return op(left, right, typename mpl::and_< is_integral< T >, is_integral< U > >::type()); + return op(left, right, integral_constant< bool, is_integral< T >::value && is_integral< U >::value >()); } private: template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::false_ const&) + static bool op(T const& left, U const& right, false_type) { return (left >= right); } template< typename T, typename U > - static bool op(T const& left, U const& right, mpl::true_ const&) + static bool op(T const& left, U const& right, true_type) { typedef typename aux::make_common_integral_type< T, U >::type common_integral_type; return static_cast< common_integral_type >(left) >= static_cast< common_integral_type >(right); diff --git a/include/boost/log/utility/manipulators/add_value.hpp b/include/boost/log/utility/manipulators/add_value.hpp index 270cedf65e..6daf3b4588 100644 --- a/include/boost/log/utility/manipulators/add_value.hpp +++ b/include/boost/log/utility/manipulators/add_value.hpp @@ -15,10 +15,10 @@ #ifndef BOOST_LOG_UTILITY_MANIPULATORS_ADD_VALUE_HPP_INCLUDED_ #define BOOST_LOG_UTILITY_MANIPULATORS_ADD_VALUE_HPP_INCLUDED_ -#include #include #include #include +#include #include #include #include @@ -61,14 +61,14 @@ class add_value_manip // To work around this problem we save the value inside the manipulator in this case. typedef typename remove_reference< reference_type >::type& lvalue_reference_type; - typedef typename mpl::if_< - is_scalar< value_type >, + typedef typename conditional< + is_scalar< value_type >::value, value_type, lvalue_reference_type >::type stored_type; - typedef typename mpl::if_< - is_scalar< value_type >, + typedef typename conditional< + is_scalar< value_type >::value, value_type, reference_type >::type get_value_result_type; diff --git a/include/boost/log/utility/setup/settings.hpp b/include/boost/log/utility/setup/settings.hpp index f35bf8506c..e7525c4ff4 100644 --- a/include/boost/log/utility/setup/settings.hpp +++ b/include/boost/log/utility/setup/settings.hpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -115,7 +115,7 @@ class basic_settings_section class ref { private: - typedef typename mpl::if_c< + typedef typename boost::conditional< IsConstV, basic_settings_section< char_type > const, basic_settings_section< char_type > From 2f15b44dc109c241d45cd54240aeaa1ed6477fa7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 17 Feb 2020 18:41:29 +0300 Subject: [PATCH 060/309] Converted some uses of Boost.MPL to Boost.TypeTraits. --- src/setup/init_from_settings.cpp | 11 ++++++----- src/thread_specific.cpp | 6 +++--- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index d8da54cdd9..534e091997 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -44,8 +44,9 @@ #include #include #include -#include +#include #include +#include #include #include #include @@ -95,8 +96,8 @@ template< typename IntT, typename CharT > inline IntT param_cast_to_int(const char* param_name, std::basic_string< CharT > const& value) { IntT res = 0; - typedef typename mpl::if_< - is_unsigned< IntT >, + typedef typename conditional< + is_unsigned< IntT >::value, qi::extract_uint< IntT, 10, 1, -1 >, qi::extract_int< IntT, 10, 1, -1 > >::type extract; @@ -368,7 +369,7 @@ class basic_default_sink_factory : private: //! The function initializes formatter for the sinks that support formatting template< typename SinkT > - static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, mpl::true_) + static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, true_type) { // Formatter if (optional< string_type > format_param = params["Format"]) @@ -381,7 +382,7 @@ class basic_default_sink_factory : return sink; } template< typename SinkT > - static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, mpl::false_) + static shared_ptr< SinkT > init_formatter(shared_ptr< SinkT > const& sink, settings_section const& params, false_type) { return sink; } diff --git a/src/thread_specific.cpp b/src/thread_specific.cpp index d8255738a9..851d4c166f 100644 --- a/src/thread_specific.cpp +++ b/src/thread_specific.cpp @@ -69,7 +69,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include #include #include -#include +#include #include #include #include @@ -128,13 +128,13 @@ struct pthread_key_traits< KeyT, true, true > typedef KeyT pthread_key_type; #if defined(BOOST_HAS_INTPTR_T) - typedef typename mpl::if_c< + typedef typename boost::conditional< boost::is_signed< pthread_key_type >::value, intptr_t, uintptr_t >::type intptr_type; #else - typedef typename mpl::if_c< + typedef typename boost::conditional< boost::is_signed< pthread_key_type >::value, std::ptrdiff_t, std::size_t From 4d9ce5cdba817c3e4f662c30100c65ae940c3656 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 21 Feb 2020 18:44:48 +0300 Subject: [PATCH 061/309] Check for feature test macros after including config.hpp. This avoids possible inconsistency when the BOOST_LOG_WITHOUT_DEBUG_OUTPUT and BOOST_LOG_WITHOUT_EVENT_LOG macros are defined in config.hpp but not in command line. Related to https://github.com/boostorg/log/issues/102. --- src/windows/debug_output_backend.cpp | 3 ++- src/windows/event_log_backend.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/windows/debug_output_backend.cpp b/src/windows/debug_output_backend.cpp index 105dd68f4c..2e59da1c39 100644 --- a/src/windows/debug_output_backend.cpp +++ b/src/windows/debug_output_backend.cpp @@ -12,9 +12,10 @@ * \brief A logging sink backend that uses debugger output */ +#include + #ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT -#include #include #include #include diff --git a/src/windows/event_log_backend.cpp b/src/windows/event_log_backend.cpp index a3382c8c51..7515f8bc56 100644 --- a/src/windows/event_log_backend.cpp +++ b/src/windows/event_log_backend.cpp @@ -13,9 +13,10 @@ * for signalling application events. */ +#include + #ifndef BOOST_LOG_WITHOUT_EVENT_LOG -#include #include #include #include From 009adf94c08bcae24bc03e3dbfa2e4be21ea4df1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 23 Feb 2020 15:24:15 +0300 Subject: [PATCH 062/309] Added a release note about fixing compilation in MSYS2 Cygwin. --- doc/changelog.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 2047817593..9a9ccd65ae 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -17,6 +17,7 @@ * Fixed that log file rotation on a specific day of month (e.g. `rotation_at_time_point(boost::gregorian::greg_day(1))`) could be silently ignored and not happen. ([github_issue 98]) * Fixed that [link log.detailed.sink_backends.text_file `text_file_backend`]`::rotate_file` could throw if there were no log records written yet and target file name pattern was set. The method would attempt to rename a missing file, which would result in an exception. Note that `rotate_file` may still throw because of a missing log file, if the file being rotated is removed by a third party. * Ported various components of the library to `std::allocator_traits` to improve compatibility with C++20 allocators. +* Fixed compilation errors when building in MSYS2 Cygwin environment. ([github_issue 102]) [heading 2.17, Boost 1.71] From e5f305a8a5d5c9062a7a7a85c63f4001e49068d0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 29 Feb 2020 15:27:56 +0300 Subject: [PATCH 063/309] Make core::flush call flush on the default sink. When trivial logging is used and no sinks are registered, allow users to manually flush the default sink. Related to https://github.com/boostorg/log/issues/103. --- doc/changelog.qbk | 4 ++++ src/core.cpp | 28 +++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 9a9ccd65ae..d942254b5a 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -11,6 +11,10 @@ [heading 2.18, Boost 1.73] +[*New Features:] + +* `core::flush` now performs a flush on the default sink used for trivial logging, when no sinks are registered. + [*Bug fixes:] * Added a workaround for some syslog API implementations (e.g. glibc), which do not save the application identification string in `openlog` call. Such implementations could access already freed memory on each `syslog` call, resulting in undefined behavior. ([github_issue 97]) diff --git a/src/core.cpp b/src/core.cpp index 07f719962c..07d51036dd 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -617,12 +617,34 @@ BOOST_LOG_API void core::flush() { // Acquire exclusive lock to prevent any logging attempts while flushing BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);) - implementation::sink_list::iterator it = m_impl->m_sinks.begin(), end = m_impl->m_sinks.end(); - for (; it != end; ++it) + if (BOOST_LIKELY(!m_impl->m_sinks.empty())) + { + implementation::sink_list::iterator it = m_impl->m_sinks.begin(), end = m_impl->m_sinks.end(); + for (; it != end; ++it) + { + try + { + it->get()->flush(); + } +#if !defined(BOOST_LOG_NO_THREADS) + catch (thread_interrupted&) + { + throw; + } +#endif // !defined(BOOST_LOG_NO_THREADS) + catch (...) + { + if (m_impl->m_exception_handler.empty()) + throw; + m_impl->m_exception_handler(); + } + } + } + else { try { - it->get()->flush(); + m_impl->m_default_sink->flush(); } #if !defined(BOOST_LOG_NO_THREADS) catch (thread_interrupted&) From 9474c572645d8835adb08c661298dbd24f59d6fe Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 29 Feb 2020 15:31:03 +0300 Subject: [PATCH 064/309] Perform automatic flush in default sink. Closes https://github.com/boostorg/log/issues/103. --- doc/changelog.qbk | 1 + src/default_sink.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index d942254b5a..3ec53932e9 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -13,6 +13,7 @@ [*New Features:] +* Default sink used in trivial logging, when no sinks are registered in the logging core, now automatically flushes output after each log record. ([github_issue 103]) * `core::flush` now performs a flush on the default sink used for trivial logging, when no sinks are registered. [*Bug fixes:] diff --git a/src/default_sink.cpp b/src/default_sink.cpp index 9258754658..00188f35fb 100644 --- a/src/default_sink.cpp +++ b/src/default_sink.cpp @@ -209,6 +209,7 @@ void default_sink::consume(record_view const& rec) { BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);) m_message_visitor(m_message_name, rec.attribute_values(), message_printer(m_severity_extractor(m_severity_name, rec).get())); + std::fflush(stdout); } void default_sink::flush() From a7b4a140d97b725f03adfd123c7e097c0838a5fa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 29 Feb 2020 16:01:00 +0300 Subject: [PATCH 065/309] Use atomic to implement logging_enabled flag. --- src/core.cpp | 34 ++++++++++++++++++++++++++-------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/src/core.cpp b/src/core.cpp index 07d51036dd..4fe27c7eea 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -37,6 +37,8 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) +#include +#include #include #include #include @@ -284,7 +286,11 @@ struct core::implementation : #endif //! The global state of logging - volatile bool m_enabled; +#if !defined(BOOST_LOG_NO_THREADS) + boost::atomic< bool > m_enabled; +#else + bool m_enabled; +#endif //! Global filter filter m_filter; @@ -307,14 +313,21 @@ struct core::implementation : bool invoke_exception_handler = true; // Try a quick win first - if (m_enabled) try +#if !defined(BOOST_LOG_NO_THREADS) + if (BOOST_LIKELY(m_enabled.load(boost::memory_order_relaxed))) +#else + if (BOOST_LIKELY(m_enabled)) +#endif + try { thread_data* tsd = get_thread_data(); +#if !defined(BOOST_LOG_NO_THREADS) // Lock the core to be safe against any attribute or sink set modifications - BOOST_LOG_EXPR_IF_MT(scoped_read_lock lock(m_mutex);) + scoped_read_lock lock(m_mutex); - if (m_enabled) + if (BOOST_LIKELY(m_enabled.load(boost::memory_order_relaxed))) +#endif { // Compose a view of attribute values (unfrozen, yet) attribute_value_set attr_values(boost::forward< SourceAttributesT >(source_attributes), tsd->m_thread_attributes, m_global_attributes); @@ -397,7 +410,7 @@ struct core::implementation : #else thread_data* p = m_thread_data.get(); #endif - if (!p) + if (BOOST_UNLIKELY(!p)) { init_thread_data(); #if defined(BOOST_LOG_USE_COMPILER_TLS) @@ -492,18 +505,23 @@ BOOST_LOG_API core_ptr core::get() //! The method enables or disables logging and returns the previous state of logging flag BOOST_LOG_API bool core::set_logging_enabled(bool enabled) { - BOOST_LOG_EXPR_IF_MT(implementation::scoped_write_lock lock(m_impl->m_mutex);) +#if !defined(BOOST_LOG_NO_THREADS) + return m_impl->m_enabled.exchange(enabled, boost::memory_order_relaxed); +#else const bool old_value = m_impl->m_enabled; m_impl->m_enabled = enabled; return old_value; +#endif } //! The method allows to detect if logging is enabled BOOST_LOG_API bool core::get_logging_enabled() const { - // Should have a read barrier here, but for performance reasons it is omitted. - // The function should be used as a quick check and doesn't need to be reliable. +#if !defined(BOOST_LOG_NO_THREADS) + return m_impl->m_enabled.load(boost::memory_order_relaxed); +#else return m_impl->m_enabled; +#endif } //! The method adds a new sink From 4c7d98843fe32c547efcd11603315e5715f9c8a9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 3 Mar 2020 23:09:41 +0300 Subject: [PATCH 066/309] Use make_attr_ordering with explicit attribute value type. Explicit specification of attribute value type is necessary when it cannot be inferred from the function object type. With C++20 removing argument type typedefs from standard function objects, like std::less, and compilers following suit (e.g. future MSVC versions), it is better to update the example so that it is compatible with future compilers. Related to https://github.com/boostorg/log/issues/105. --- example/async_log/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/example/async_log/main.cpp b/example/async_log/main.cpp index 26763a4bc1..7469688fc6 100644 --- a/example/async_log/main.cpp +++ b/example/async_log/main.cpp @@ -86,7 +86,7 @@ int main(int argc, char* argv[]) shared_ptr< sink_t > sink(new sink_t( boost::make_shared< backend_t >(), // We'll apply record ordering to ensure that records from different threads go sequentially in the file - keywords::order = logging::make_attr_ordering("RecordID", std::less< unsigned int >()))); + keywords::order = logging::make_attr_ordering< unsigned int >("RecordID", std::less< unsigned int >()))); sink->locked_backend()->add_stream(strm); From 60cf554ee9d739867f9b88d53eacc27f96e9f065 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 4 Mar 2020 00:32:52 +0300 Subject: [PATCH 067/309] Ported to use newer API of Boost.Atomic. --- src/event.cpp | 4 +- src/windows/ipc_sync_wrappers.cpp | 2 +- src/windows/ipc_sync_wrappers.hpp | 112 +----------------------------- 3 files changed, 5 insertions(+), 113 deletions(-) diff --git a/src/event.cpp b/src/event.cpp index ea9eee2fc0..5485154d72 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -95,7 +95,7 @@ BOOST_LOG_API void futex_based_event::wait() { while (true) { - if (::syscall(BOOST_LOG_SYS_FUTEX, &m_state.storage(), BOOST_LOG_FUTEX_WAIT, 0, NULL, NULL, 0) == 0) + if (::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAIT, 0, NULL, NULL, 0) == 0) { // Another thread has set the event while sleeping break; @@ -122,7 +122,7 @@ BOOST_LOG_API void futex_based_event::set_signalled() { if (m_state.exchange(1, boost::memory_order_release) == 0) { - if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.storage(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0)) + if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0)) { const int err = errno; BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake threads blocked on the futex", (err)); diff --git a/src/windows/ipc_sync_wrappers.cpp b/src/windows/ipc_sync_wrappers.cpp index bd8bfb215c..12d743aa60 100644 --- a/src/windows/ipc_sync_wrappers.cpp +++ b/src/windows/ipc_sync_wrappers.cpp @@ -332,7 +332,7 @@ inline void interprocess_mutex::clear_waiting_and_try_lock(uint32_t& old_state) { new_state = ((old_state & lock_flag_value) ? old_state : ((old_state - 1u) | lock_flag_value)) & ~event_set_flag_value; } - while (!m_shared_state->m_lock_state.compare_exchange_strong(old_state, new_state, boost::memory_order_acq_rel, boost::memory_order_relaxed)); + while (!m_shared_state->m_lock_state.compare_exchange_weak(old_state, new_state, boost::memory_order_acq_rel, boost::memory_order_relaxed)); } diff --git a/src/windows/ipc_sync_wrappers.hpp b/src/windows/ipc_sync_wrappers.hpp index 7d1272aa1f..8ecd9635cf 100644 --- a/src/windows/ipc_sync_wrappers.hpp +++ b/src/windows/ipc_sync_wrappers.hpp @@ -52,114 +52,6 @@ namespace ipc { namespace aux { -// TODO: Port to Boost.Atomic when it supports extended atomic ops -#if defined(BOOST_MSVC) && (_MSC_VER >= 1400) && !defined(UNDER_CE) - -#if _MSC_VER == 1400 -extern "C" unsigned char _interlockedbittestandset(long *a, long b); -extern "C" unsigned char _interlockedbittestandreset(long *a, long b); -#else -extern "C" unsigned char _interlockedbittestandset(volatile long *a, long b); -extern "C" unsigned char _interlockedbittestandreset(volatile long *a, long b); -#endif - -#pragma intrinsic(_interlockedbittestandset) -#pragma intrinsic(_interlockedbittestandreset) - -BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - return _interlockedbittestandset(reinterpret_cast< long* >(&x.storage()), static_cast< long >(bit)) != 0; -} - -BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - return _interlockedbittestandreset(reinterpret_cast< long* >(&x.storage()), static_cast< long >(bit)) != 0; -} - -#elif (defined(BOOST_MSVC) || defined(BOOST_INTEL_WIN)) && defined(_M_IX86) - -BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - boost::atomic< uint32_t >::storage_type* p = &x.storage(); - bool ret; - __asm - { - mov eax, bit - mov edx, p - lock bts [edx], eax - setc ret - }; - return ret; -} - -BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - boost::atomic< uint32_t >::storage_type* p = &x.storage(); - bool ret; - __asm - { - mov eax, bit - mov edx, p - lock btr [edx], eax - setc ret - }; - return ret; -} - -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) - -#if !defined(__CUDACC__) -#define BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "cc", -#else -#define BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA -#endif - -BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - bool res; - __asm__ __volatile__ - ( - "lock; bts %[bit_number], %[storage]\n\t" - "setc %[result]\n\t" - : [storage] "+m" (x.storage()), [result] "=q" (res) - : [bit_number] "Kq" (bit) - : BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "memory" - ); - return res; -} - -BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - bool res; - __asm__ __volatile__ - ( - "lock; btr %[bit_number], %[storage]\n\t" - "setc %[result]\n\t" - : [storage] "+m" (x.storage()), [result] "=q" (res) - : [bit_number] "Kq" (bit) - : BOOST_LOG_DETAIL_ASM_CLOBBER_CC_COMMA "memory" - ); - return res; -} - -#else - -BOOST_FORCEINLINE bool bit_test_and_set(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - const uint32_t mask = uint32_t(1u) << bit; - uint32_t old_val = x.fetch_or(mask, boost::memory_order_acq_rel); - return (old_val & mask) != 0u; -} - -BOOST_FORCEINLINE bool bit_test_and_reset(boost::atomic< uint32_t >& x, uint32_t bit) BOOST_NOEXCEPT -{ - const uint32_t mask = uint32_t(1u) << bit; - uint32_t old_val = x.fetch_and(~mask, boost::memory_order_acq_rel); - return (old_val & mask) != 0u; -} - -#endif - //! Interprocess event object class interprocess_event { @@ -403,7 +295,7 @@ class interprocess_mutex bool try_lock() { - return !bit_test_and_set(m_shared_state->m_lock_state, lock_flag_bit); + return !m_shared_state->m_lock_state.bit_test_and_set(lock_flag_bit, boost::memory_order_acquire); } void lock() @@ -424,7 +316,7 @@ class interprocess_mutex const uint32_t old_count = m_shared_state->m_lock_state.fetch_add(lock_flag_value, boost::memory_order_release); if ((old_count & event_set_flag_value) == 0u && (old_count > lock_flag_value)) { - if (!bit_test_and_set(m_shared_state->m_lock_state, event_set_flag_bit)) + if (!m_shared_state->m_lock_state.bit_test_and_set(event_set_flag_bit, boost::memory_order_relaxed)) { m_event.set_noexcept(); } From 68d38321b3d98f39de146cc2deb1a7f07bc05434 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 4 Mar 2020 00:44:23 +0300 Subject: [PATCH 068/309] Updated deprecated uses of boost::bind to silence warnings. --- example/async_log/main.cpp | 4 ++-- example/bounded_async_log/main.cpp | 4 ++-- example/multiple_threads/main.cpp | 4 ++-- example/settings_file_custom_factories/main.cpp | 6 +++--- include/boost/log/sinks/async_frontend.hpp | 2 +- src/setup/formatter_parser.cpp | 1 - src/setup/init_from_settings.cpp | 4 ++-- src/severity_level.cpp | 2 +- src/text_file_backend.cpp | 16 ++++++++-------- test/performance/record_emission.cpp | 4 ++-- test/run/util_dynamic_type_disp.cpp | 8 ++++---- test/run/util_once_block.cpp | 4 ++-- 12 files changed, 29 insertions(+), 30 deletions(-) diff --git a/example/async_log/main.cpp b/example/async_log/main.cpp index 7469688fc6..7f7a19509f 100644 --- a/example/async_log/main.cpp +++ b/example/async_log/main.cpp @@ -19,8 +19,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/example/bounded_async_log/main.cpp b/example/bounded_async_log/main.cpp index eefeb52af7..14dee2f5ee 100644 --- a/example/bounded_async_log/main.cpp +++ b/example/bounded_async_log/main.cpp @@ -19,8 +19,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/example/multiple_threads/main.cpp b/example/multiple_threads/main.cpp index a9b036fcc4..2b005237ff 100644 --- a/example/multiple_threads/main.cpp +++ b/example/multiple_threads/main.cpp @@ -21,8 +21,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include diff --git a/example/settings_file_custom_factories/main.cpp b/example/settings_file_custom_factories/main.cpp index 3d59444bb5..a82d813eb0 100644 --- a/example/settings_file_custom_factories/main.cpp +++ b/example/settings_file_custom_factories/main.cpp @@ -19,8 +19,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -115,7 +115,7 @@ struct scope_list_formatter ( name_, rec.attribute_values(), - boost::bind(&scope_list_formatter::format, _1, boost::ref(strm)) + boost::bind(&scope_list_formatter::format, boost::placeholders::_1, boost::ref(strm)) ); } diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index ec5371006e..d7bfd30aed 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -26,7 +26,7 @@ #error Boost.Log: Asynchronous sink frontend is only supported in multithreaded environment #endif -#include +#include #include #include #include diff --git a/src/setup/formatter_parser.cpp b/src/setup/formatter_parser.cpp index 09ab8ee618..597b6ca7b2 100644 --- a/src/setup/formatter_parser.cpp +++ b/src/setup/formatter_parser.cpp @@ -21,7 +21,6 @@ #include #include #include -#include #include #include #include diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 534e091997..7b5b6285a4 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -35,9 +35,9 @@ #include #include #include -#include #include #include +#include #include #include #include @@ -854,7 +854,7 @@ BOOST_LOG_SETUP_API void init_from_settings(basic_settings_section< CharT > cons } } - std::for_each(new_sinks.begin(), new_sinks.end(), boost::bind(&core::add_sink, core::get(), _1)); + std::for_each(new_sinks.begin(), new_sinks.end(), boost::bind(&core::add_sink, core::get(), boost::placeholders::_1)); } } diff --git a/src/severity_level.cpp b/src/severity_level.cpp index 25b7c7d548..03f8ebbd4c 100644 --- a/src/severity_level.cpp +++ b/src/severity_level.cpp @@ -18,7 +18,7 @@ #include #if !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS) -#include +#include #include #include // at_thread_exit #include diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 9cca651e9d..658aa28f62 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -29,8 +29,8 @@ #include #include #include -#include -#include +#include +#include #include #include #include @@ -570,18 +570,18 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { // Both counter and date/time placeholder in the pattern file_name_generator = boost::bind(date_and_time_formatter(), - boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1), _1); + boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1), boost::placeholders::_1); } else { // Only date/time placeholders in the pattern - file_name_generator = boost::bind(date_and_time_formatter(), name_pattern, _1); + file_name_generator = boost::bind(date_and_time_formatter(), name_pattern, boost::placeholders::_1); } } else if (counter_found) { // Only counter placeholder in the pattern - file_name_generator = boost::bind(file_counter_formatter(counter_pos, width), name_pattern, _1); + file_name_generator = boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1); } else { @@ -935,7 +935,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } }; if (std::find_if(m_Files.begin(), m_Files.end(), - boost::bind(&local::equivalent, boost::cref(info.m_Path), _1)) == m_Files.end()) + boost::bind(&local::equivalent, boost::cref(info.m_Path), boost::placeholders::_1)) == m_Files.end()) { // Check that the file name matches the pattern unsigned int file_number = 0; @@ -960,7 +960,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { // Sort files chronologically m_Files.splice(m_Files.end(), files); m_TotalSize += total_size; - m_Files.sort(boost::bind(&file_info::m_TimeStamp, _1) < boost::bind(&file_info::m_TimeStamp, _2)); + m_Files.sort(boost::bind(&file_info::m_TimeStamp, boost::placeholders::_1) < boost::bind(&file_info::m_TimeStamp, boost::placeholders::_2)); } } @@ -985,7 +985,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) file_collectors::iterator it = std::find_if(m_Collectors.begin(), m_Collectors.end(), - boost::bind(&file_collector::is_governed, _1, boost::cref(target_dir))); + boost::bind(&file_collector::is_governed, boost::placeholders::_1, boost::cref(target_dir))); shared_ptr< file_collector > p; if (it != m_Collectors.end()) try { diff --git a/test/performance/record_emission.cpp b/test/performance/record_emission.cpp index 8657091c7b..0dd388cb05 100644 --- a/test/performance/record_emission.cpp +++ b/test/performance/record_emission.cpp @@ -19,8 +19,8 @@ #include #include -#include -#include +#include +#include #include #include #include diff --git a/test/run/util_dynamic_type_disp.cpp b/test/run/util_dynamic_type_disp.cpp index e64abb1d6c..d1d6d9f49f 100644 --- a/test/run/util_dynamic_type_disp.cpp +++ b/test/run/util_dynamic_type_disp.cpp @@ -15,7 +15,7 @@ #define BOOST_TEST_MODULE util_dynamic_type_disp #include -#include +#include #include #include #include @@ -111,8 +111,8 @@ BOOST_AUTO_TEST_CASE(type_dispatch) logging::dynamic_type_dispatcher disp; // Register type visitors - disp.register_type< int >(boost::bind(&my_visitor::on_int, &vis, _1)); - disp.register_type< double >(boost::bind(&my_visitor::on_double, &vis, _1)); + disp.register_type< int >(boost::bind(&my_visitor::on_int, &vis, boost::placeholders::_1)); + disp.register_type< double >(boost::bind(&my_visitor::on_double, &vis, boost::placeholders::_1)); BOOST_CHECK(disp.registered_types_count() == 2); @@ -121,7 +121,7 @@ BOOST_AUTO_TEST_CASE(type_dispatch) BOOST_CHECK(!val1.dispatch(disp)); // And now they are - disp.register_type< std::string >(boost::bind(&my_visitor::on_string, &vis, _1)); + disp.register_type< std::string >(boost::bind(&my_visitor::on_string, &vis, boost::placeholders::_1)); BOOST_CHECK(disp.registered_types_count() == 3); vis.set_expected(val1.m_Value); diff --git a/test/run/util_once_block.cpp b/test/run/util_once_block.cpp index d952dad74b..4149c74284 100644 --- a/test/run/util_once_block.cpp +++ b/test/run/util_once_block.cpp @@ -21,8 +21,8 @@ #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include +#include #include #include #include From 5f48284bf9a3fee0bf0c96b47e666a35ad096a17 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 4 Mar 2020 13:38:45 +0300 Subject: [PATCH 069/309] Nonessential cleanup. --- src/text_file_backend.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 658aa28f62..e1569b1cb9 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1489,8 +1489,7 @@ BOOST_LOG_API void text_file_backend::rotate_file() { if (!!m_pImpl->m_TargetFileNameGenerator) { - filesystem::path new_file_name; - new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); + filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); if (new_file_name != prev_file_name) { From cd71e1c7f59418e60eb62e2685297f3f6377c926 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 10 Mar 2020 22:32:29 +0300 Subject: [PATCH 070/309] Updated README.md with better representation of build status. --- README.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a91f6cd89a..0da589b3e0 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,18 @@ Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/bo ### More information -* [Documentation](https://boost.org/libs/log) +* [Documentation](https://www.boost.org/libs/log) * [Ask questions](https://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-log) -* [Report bugs](https://svn.boost.org/trac/boost/newticket?component=log;version=Boost%20Release%20Branch). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. -* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). +* [Report bugs](https://github.com/boostorg/log/issues/new). Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well. +* Submit your patches as [pull requests](https://github.com/boostorg/log/compare) against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](https://www.boost.org/LICENSE_1_0.txt). * Discussions about the library are held on the [Boost developers mailing list](https://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](https://www.boost.org/community/policy.html) before posting and add the `[log]` tag at the beginning of the subject line. ### Build status -Master: [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) -Develop: [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) +Branch | Travis CI | AppVeyor | Test Matrix | Dependency Report | +:-------------: | --------- | -------- | ----------- | ----------------- | +[`master`](https://github.com/boostorg/log/tree/master) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) +[`develop`](https://github.com/boostorg/log/tree/develop) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) ### License From 2113f04d602b9579100a92936f36d81f228da1f3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 10 Mar 2020 22:34:34 +0300 Subject: [PATCH 071/309] Minor tweak for README.md. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0da589b3e0..b8827baf6c 100644 --- a/README.md +++ b/README.md @@ -22,8 +22,8 @@ Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/bo ### Build status -Branch | Travis CI | AppVeyor | Test Matrix | Dependency Report | -:-------------: | --------- | -------- | ----------- | ----------------- | +Branch | Travis CI | AppVeyor | Test Matrix | Dependencies | +:-------------: | --------- | -------- | ----------- | ------------ | [`master`](https://github.com/boostorg/log/tree/master) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) [`develop`](https://github.com/boostorg/log/tree/develop) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) From e6c6479d9118d45f10032fd2a1393b70f4c990fd Mon Sep 17 00:00:00 2001 From: Marian Klymov Date: Fri, 3 Apr 2020 18:55:34 +0300 Subject: [PATCH 072/309] Add missing filesystem includes. Fix compilation with BOOST_FILESYSTEM_NO_DEPRECATED --- src/text_file_backend.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index e1569b1cb9..f71f832d91 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include #include From 43b944da2e76ac9ca521cfe86060492532ca70f1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 8 Apr 2020 15:32:33 +0300 Subject: [PATCH 073/309] Added a workaround for MSVC 14.2 codegen bug in regex matching filters. The compiler generates incorrect code causing a crash if it inlines the `matches` generator functions, when a Boost.Regex regular expression is passed as an argument. https://developercommunity.visualstudio.com/content/problem/982738/bad-code-generated-in-boostlogboostregex-test-case.html As a workaround we prohibit inlining these functions on this compiler. Fixes AppVeyor CI test failures. --- .../boost/log/expressions/predicates/matches.hpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/include/boost/log/expressions/predicates/matches.hpp b/include/boost/log/expressions/predicates/matches.hpp index d9291396b3..1fe2d63595 100644 --- a/include/boost/log/expressions/predicates/matches.hpp +++ b/include/boost/log/expressions/predicates/matches.hpp @@ -69,12 +69,20 @@ class attribute_matches : } }; +#if defined(BOOST_MSVC) && BOOST_MSVC == 1925 +// MSVC 14.2 has a codegen bug that makes inlined `matches` functions below crash on copy constructing the phoenix::actor on return. +// https://developercommunity.visualstudio.com/content/problem/982738/bad-code-generated-in-boostlogboostregex-test-case.html +#define BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 inline BOOST_NOINLINE +#else +#define BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 BOOST_FORCEINLINE +#endif + /*! * The function generates a terminal node in a template expression. The node will check if the attribute value, * which is assumed to be a string, matches the specified regular expression. */ template< typename T, typename FallbackPolicyT, typename TagT, template< typename > class ActorT, typename RegexT > -BOOST_FORCEINLINE ActorT< aux::unary_function_terminal< attribute_matches< T, RegexT, FallbackPolicyT > > > +BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 ActorT< aux::unary_function_terminal< attribute_matches< T, RegexT, FallbackPolicyT > > > matches(attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& attr, RegexT const& rex) { typedef aux::unary_function_terminal< attribute_matches< T, RegexT, FallbackPolicyT > > terminal_type; @@ -87,7 +95,7 @@ matches(attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& attr, RegexT * which is assumed to be a string, matches the specified regular expression. */ template< typename DescriptorT, template< typename > class ActorT, typename RegexT > -BOOST_FORCEINLINE ActorT< aux::unary_function_terminal< attribute_matches< typename DescriptorT::value_type, RegexT > > > +BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 ActorT< aux::unary_function_terminal< attribute_matches< typename DescriptorT::value_type, RegexT > > > matches(attribute_keyword< DescriptorT, ActorT > const&, RegexT const& rex) { typedef aux::unary_function_terminal< attribute_matches< typename DescriptorT::value_type, RegexT > > terminal_type; @@ -100,7 +108,7 @@ matches(attribute_keyword< DescriptorT, ActorT > const&, RegexT const& rex) * which is assumed to be a string, matches the specified regular expression. */ template< typename T, typename RegexT > -BOOST_FORCEINLINE phoenix::actor< aux::unary_function_terminal< attribute_matches< T, RegexT > > > +BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 phoenix::actor< aux::unary_function_terminal< attribute_matches< T, RegexT > > > matches(attribute_name const& name, RegexT const& rex) { typedef aux::unary_function_terminal< attribute_matches< T, RegexT > > terminal_type; @@ -108,6 +116,8 @@ matches(attribute_name const& name, RegexT const& rex) return act; } +#undef BOOST_LOG_AUX_FORCEINLINE_MSVC_BUG982738 + } // namespace expressions BOOST_LOG_CLOSE_NAMESPACE // namespace log From c068c2a5aa94fcdcfe554414487e5d0d60e8a0e8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 14 Apr 2020 00:29:14 +0300 Subject: [PATCH 074/309] Add explicit markup of fallthrough between switch/case labels. Silences some compiler warnings. Closes https://github.com/boostorg/log/issues/115. --- src/code_conversion.cpp | 1 + src/named_scope_format_parser.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/code_conversion.cpp b/src/code_conversion.cpp index 2f253eda3d..d75d2a61ae 100644 --- a/src/code_conversion.cpp +++ b/src/code_conversion.cpp @@ -125,6 +125,7 @@ inline std::size_t code_convert(const SourceCharT* begin, const SourceCharT* end // Looks like the tail of the source buffer contains only part of the last character. // In this case we intentionally fall through to throw an exception. } + BOOST_FALLTHROUGH; default: // std::codecvt_base::error BOOST_LOG_THROW_DESCR(conversion_error, "Could not convert character encoding"); diff --git a/src/named_scope_format_parser.cpp b/src/named_scope_format_parser.cpp index b7a602a716..b393259472 100644 --- a/src/named_scope_format_parser.cpp +++ b/src/named_scope_format_parser.cpp @@ -124,12 +124,13 @@ bool detect_operator(const char* begin, const char* end, const char* operator_ke return true; } // Fall through to other cases involving '-' + BOOST_FALLTHROUGH; case '=': case '|': case '&': case '+': - // Handle operator=, operator==, operator+=, operator++, operator||, opeartor&&, etc. + // Handle operator=, operator==, operator+=, operator++, operator||, operator&&, etc. if (end - p >= 2 && (p[0] == p[1] || p[1] == '=')) operator_end = p + 2; else @@ -295,6 +296,7 @@ inline const char* find_opening_parenthesis(const char* begin, const char* end, } } // Fall through to process this character as other characters + BOOST_FALLTHROUGH; default: if (state != operator_detected) @@ -358,6 +360,7 @@ inline const char* find_closing_parenthesis(const char* begin, const char* end, } } // Fall through to process this character as other characters + BOOST_FALLTHROUGH; default: if (!found_first_meaningful_char && c != ' ') From 49af1c8fa0137047ec6e6e783581eb10e504c9db Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 20 Apr 2020 20:08:01 +0300 Subject: [PATCH 075/309] Use SFINAE to limit attribute set iterator comparison, copy and assignment. This makes the code more SFINAE-friendly. It also changes the converting constructor and assignment operator to only work as converting constructor and assignment and let the compiler generate the implicit copy constructor and assignment operator. This should silence bogus clang-10 warnings about deprecated generation of an implicit copy assignment operator in presence of a copy constructor. (The warning is bogus because there already is an explicitly defined assignment operator, which works as a copy assignment as well.) Closes https://github.com/boostorg/log/issues/118. --- .../boost/log/attributes/attribute_set.hpp | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/include/boost/log/attributes/attribute_set.hpp b/include/boost/log/attributes/attribute_set.hpp index 2d2a987a98..473a4f2622 100644 --- a/include/boost/log/attributes/attribute_set.hpp +++ b/include/boost/log/attributes/attribute_set.hpp @@ -19,8 +19,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -171,23 +173,32 @@ class attribute_set public: // Constructors - BOOST_CONSTEXPR iter() : m_pNode(NULL) {} + BOOST_CONSTEXPR iter() BOOST_NOEXCEPT : m_pNode(NULL) {} explicit iter(node_base* pNode) BOOST_NOEXCEPT : m_pNode(pNode) {} - iter(iter< false > const& that) BOOST_NOEXCEPT : m_pNode(that.m_pNode) {} +#if !defined(BOOST_NO_CXX11_FUNCTION_TEMPLATE_DEFAULT_ARGS) + template< bool fOtherConstV, typename = typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV >::type > + iter(iter< fOtherConstV > const& that) BOOST_NOEXCEPT : m_pNode(that.m_pNode) {} +#else + template< bool fOtherConstV > + iter(iter< fOtherConstV > const& that, typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) BOOST_NOEXCEPT : + m_pNode(that.m_pNode) + { + } +#endif //! Assignment - template< bool f > - iter& operator= (iter< f > const& that) BOOST_NOEXCEPT + template< bool fOtherConstV > + typename boost::enable_if_c< !fOtherConstV && fOtherConstV != fConstV, iter& >::type operator= (iter< fOtherConstV > const& that) BOOST_NOEXCEPT { m_pNode = that.m_pNode; return *this; } // Comparison - template< bool f > - bool operator== (iter< f > const& that) const BOOST_NOEXCEPT { return (m_pNode == that.m_pNode); } - template< bool f > - bool operator!= (iter< f > const& that) const BOOST_NOEXCEPT { return (m_pNode != that.m_pNode); } + template< bool fOtherConstV > + typename boost::enable_if_c< !fOtherConstV || fOtherConstV == fConstV, bool >::type operator== (iter< fOtherConstV > const& that) const BOOST_NOEXCEPT { return (m_pNode == that.m_pNode); } + template< bool fOtherConstV > + typename boost::enable_if_c< !fOtherConstV || fOtherConstV == fConstV, bool >::type operator!= (iter< fOtherConstV > const& that) const BOOST_NOEXCEPT { return (m_pNode != that.m_pNode); } // Modification iter& operator++ () BOOST_NOEXCEPT From 1e92e84b8070b65ff05af4973ab3bfd2dd5b21b1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 27 Apr 2020 21:47:41 +0300 Subject: [PATCH 076/309] Added checking for IP version in addresses in syslog backend. The syslog sink backend now verifies the IP version of the local and target addresses set by user. The addresses must have the same IP version as was specified in the ip_version named parameter on the sink backend construction. When an address is obtained as a result of host name resolution, only addresses with matching IP version are considered. This should protect against using local and target addresses with mismatching IP versions, which results in errors on sending datagrams. Fixes https://github.com/boostorg/log/issues/119. --- doc/changelog.qbk | 6 ++++++ src/syslog_backend.cpp | 24 +++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 3ec53932e9..b28abe777d 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.19, Boost 1.74] + +[*Bug fixes:] + +* The [link log.detailed.sink_backends.syslog syslog] sink backend now verifies the IP version of the local and target addresses set by user. The addresses must have the same IP version as was specified in the `ip_version` named parameter on the sink backend construction (by default, IPv4 is assumed). When an address is obtained as a result of host name resolution, only addresses with matching IP version are considered. ([github_issue 119]) + [heading 2.18, Boost 1.73] [*New Features:] diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 19731880b4..d4b5085bbf 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2018. + * Copyright Andrey Semashev 2007 - 2020. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -508,17 +508,19 @@ BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_ #if !defined(BOOST_LOG_NO_ASIO) typedef implementation::udp_socket_based udp_socket_based_impl; + asio::ip::udp protocol = asio::ip::udp::v4(); switch (ip_version) { case v4: - m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v4()); break; case v6: - m_pImpl = new udp_socket_based_impl(fac, asio::ip::udp::v6()); + protocol = asio::ip::udp::v6(); break; default: BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified"); } + + m_pImpl = new udp_socket_based_impl(fac, protocol); #endif } @@ -531,14 +533,15 @@ BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, un typedef implementation::udp_socket_based udp_socket_based_impl; if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { - char service_name[std::numeric_limits< int >::digits10 + 3]; - boost::log::aux::snprintf(service_name, sizeof(service_name), "%d", static_cast< int >(port)); + char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; + boost::log::aux::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); asio::ip::udp::endpoint local_address; { lock_guard< mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( + impl->m_Protocol, addr, service_name, asio::ip::resolver_base::address_configured | asio::ip::resolver_base::passive @@ -561,6 +564,9 @@ BOOST_LOG_API void syslog_backend::set_local_address(boost::asio::ip::address co typedef implementation::udp_socket_based udp_socket_based_impl; if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { + if ((impl->m_Protocol == asio::ip::udp::v4() && !addr.is_v4()) || (impl->m_Protocol == asio::ip::udp::v6() && !addr.is_v6())) + BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified in the local address"); + impl->m_pSocket.reset(new syslog_udp_socket( impl->m_pService->m_IOContext, impl->m_Protocol, asio::ip::udp::endpoint(addr, port))); } @@ -573,14 +579,15 @@ BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, u typedef implementation::udp_socket_based udp_socket_based_impl; if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { - char service_name[std::numeric_limits< int >::digits10 + 3]; - boost::log::aux::snprintf(service_name, sizeof(service_name), "%d", static_cast< int >(port)); + char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; + boost::log::aux::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); asio::ip::udp::endpoint remote_address; { lock_guard< mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( + impl->m_Protocol, addr, service_name, asio::ip::resolver_query_base::address_configured @@ -603,6 +610,9 @@ BOOST_LOG_API void syslog_backend::set_target_address(boost::asio::ip::address c typedef implementation::udp_socket_based udp_socket_based_impl; if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { + if ((impl->m_Protocol == asio::ip::udp::v4() && !addr.is_v4()) || (impl->m_Protocol == asio::ip::udp::v6() && !addr.is_v6())) + BOOST_LOG_THROW_DESCR(setup_error, "Incorrect IP version specified in the target address"); + impl->m_TargetHost = asio::ip::udp::endpoint(addr, port); } } From 112d6f0fbc86ec8f420a7432fc5003c82447b48a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 2 May 2020 18:50:08 +0300 Subject: [PATCH 077/309] Changed macro checks in the footer to match the header. --- include/boost/log/detail/footer.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/boost/log/detail/footer.hpp b/include/boost/log/detail/footer.hpp index ba0d2f0cb4..b3f97f2011 100644 --- a/include/boost/log/detail/footer.hpp +++ b/include/boost/log/detail/footer.hpp @@ -11,7 +11,8 @@ #pragma warning(pop) -#elif defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ + && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 #pragma GCC diagnostic pop From 4019d171a31e501d71dfbd61fc682fb449cbdf50 Mon Sep 17 00:00:00 2001 From: Eugene Zelenko Date: Sun, 3 May 2020 20:29:19 -0700 Subject: [PATCH 078/309] Use BOOST_OVERRIDE to fix GCC -Wsuggest-override and Clang-tidy modernize-use-override warnings. --- .../boost/log/attributes/attribute_value.hpp | 2 +- .../log/attributes/attribute_value_impl.hpp | 4 +-- .../log/detail/attachable_sstream_buf.hpp | 6 ++-- .../log/detail/date_time_format_parser.hpp | 6 ++-- include/boost/log/exceptions.hpp | 30 +++++++++---------- include/boost/log/sinks/async_frontend.hpp | 8 ++--- .../boost/log/sinks/basic_sink_frontend.hpp | 2 +- include/boost/log/sinks/sync_frontend.hpp | 6 ++-- .../boost/log/sources/severity_feature.hpp | 4 +-- src/default_sink.hpp | 8 ++--- src/named_scope.cpp | 8 ++--- src/setup/default_filter_factory.hpp | 14 ++++----- src/setup/default_formatter_factory.hpp | 2 +- src/setup/init_from_settings.cpp | 6 ++-- src/syslog_backend.cpp | 4 +-- src/text_file_backend.cpp | 8 ++--- src/threadsafe_queue.cpp | 10 +++---- src/timer.cpp | 2 +- 18 files changed, 65 insertions(+), 65 deletions(-) diff --git a/include/boost/log/attributes/attribute_value.hpp b/include/boost/log/attributes/attribute_value.hpp index 197ef860bf..a309af628f 100644 --- a/include/boost/log/attributes/attribute_value.hpp +++ b/include/boost/log/attributes/attribute_value.hpp @@ -98,7 +98,7 @@ class attribute_value /*! * \return The attribute value that refers to self implementation. */ - virtual attribute_value get_value() { return attribute_value(this); } + attribute_value get_value() BOOST_OVERRIDE { return attribute_value(this); } /*! * \return The attribute value type diff --git a/include/boost/log/attributes/attribute_value_impl.hpp b/include/boost/log/attributes/attribute_value_impl.hpp index e18015bec3..468d127a99 100644 --- a/include/boost/log/attributes/attribute_value_impl.hpp +++ b/include/boost/log/attributes/attribute_value_impl.hpp @@ -73,7 +73,7 @@ class attribute_value_impl : * * \return \c true if the value has been dispatched, \c false otherwise */ - virtual bool dispatch(type_dispatcher& dispatcher) + bool dispatch(type_dispatcher& dispatcher) BOOST_OVERRIDE { type_dispatcher::callback< value_type > callback = dispatcher.get_callback< value_type >(); if (callback) @@ -88,7 +88,7 @@ class attribute_value_impl : /*! * \return The attribute value type */ - typeindex::type_index get_type() const { return typeindex::type_id< value_type >(); } + typeindex::type_index get_type() const BOOST_OVERRIDE { return typeindex::type_id< value_type >(); } /*! * \return Reference to the contained value. diff --git a/include/boost/log/detail/attachable_sstream_buf.hpp b/include/boost/log/detail/attachable_sstream_buf.hpp index e196689c80..1077589983 100644 --- a/include/boost/log/detail/attachable_sstream_buf.hpp +++ b/include/boost/log/detail/attachable_sstream_buf.hpp @@ -244,7 +244,7 @@ class basic_ostringstreambuf : protected: //! Puts all buffered data to the string - int sync() + int sync() BOOST_OVERRIDE { char_type* pBase = this->pbase(); char_type* pPtr = this->pptr(); @@ -256,7 +256,7 @@ class basic_ostringstreambuf : return 0; } //! Puts an unbuffered character to the string - int_type overflow(int_type c) + int_type overflow(int_type c) BOOST_OVERRIDE { this_type::sync(); if (!traits_type::eq_int_type(c, traits_type::eof())) @@ -268,7 +268,7 @@ class basic_ostringstreambuf : return traits_type::not_eof(c); } //! Puts a character sequence to the string - std::streamsize xsputn(const char_type* s, std::streamsize n) + std::streamsize xsputn(const char_type* s, std::streamsize n) BOOST_OVERRIDE { this_type::sync(); return static_cast< std::streamsize >(this->append(s, static_cast< size_type >(n))); diff --git a/include/boost/log/detail/date_time_format_parser.hpp b/include/boost/log/detail/date_time_format_parser.hpp index 3219690025..8d66d354ff 100644 --- a/include/boost/log/detail/date_time_format_parser.hpp +++ b/include/boost/log/detail/date_time_format_parser.hpp @@ -343,21 +343,21 @@ struct date_time_format_parser_callback : typedef CharT char_type; //! Destructor - virtual ~date_time_format_parser_callback() {} + ~date_time_format_parser_callback() BOOST_OVERRIDE {} /*! * \brief The function is called when the parser discovers a string literal in the format string * * \param lit The string of characters not interpreted as a placeholder */ - virtual void on_literal(iterator_range< const char_type* > const& lit) = 0; + void on_literal(iterator_range< const char_type* > const& lit) BOOST_OVERRIDE = 0; /*! * \brief The method is called when an unknown placeholder is found in the format string * * \param ph The placeholder with the leading percent sign */ - virtual void on_placeholder(iterator_range< const char_type* > const& ph) + void on_placeholder(iterator_range< const char_type* > const& ph) BOOST_OVERRIDE { // By default interpret all unrecognized placeholders as literals on_literal(ph); diff --git a/include/boost/log/exceptions.hpp b/include/boost/log/exceptions.hpp index 32d55d40c5..f129ea8272 100644 --- a/include/boost/log/exceptions.hpp +++ b/include/boost/log/exceptions.hpp @@ -83,12 +83,12 @@ class BOOST_LOG_API bad_alloc : /*! * Destructor */ - ~bad_alloc() throw(); + ~bad_alloc() throw() BOOST_OVERRIDE; /*! * Error message accessor. */ - const char* what() const throw(); + const char* what() const throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); @@ -114,7 +114,7 @@ class BOOST_LOG_API capacity_limit_reached : /*! * Destructor */ - ~capacity_limit_reached() throw(); + ~capacity_limit_reached() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); @@ -140,7 +140,7 @@ class BOOST_LOG_API runtime_error : /*! * Destructor */ - ~runtime_error() throw(); + ~runtime_error() throw() BOOST_OVERRIDE; }; /*! @@ -161,7 +161,7 @@ class BOOST_LOG_API missing_value : /*! * Destructor */ - ~missing_value() throw(); + ~missing_value() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -190,7 +190,7 @@ class BOOST_LOG_API invalid_type : /*! * Destructor */ - ~invalid_type() throw(); + ~invalid_type() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -223,7 +223,7 @@ class BOOST_LOG_API invalid_value : /*! * Destructor */ - ~invalid_value() throw(); + ~invalid_value() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -250,7 +250,7 @@ class BOOST_LOG_API parse_error : /*! * Destructor */ - ~parse_error() throw(); + ~parse_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -281,7 +281,7 @@ class BOOST_LOG_API conversion_error : /*! * Destructor */ - ~conversion_error() throw(); + ~conversion_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -304,7 +304,7 @@ class BOOST_LOG_API system_error : /*! * Destructor */ - ~system_error() throw(); + ~system_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr, int system_error_code); @@ -331,7 +331,7 @@ class BOOST_LOG_API logic_error : /*! * Destructor */ - ~logic_error() throw(); + ~logic_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line, const char* descr); @@ -357,7 +357,7 @@ class BOOST_LOG_API odr_violation : /*! * Destructor */ - ~odr_violation() throw(); + ~odr_violation() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -384,7 +384,7 @@ class BOOST_LOG_API unexpected_call : /*! * Destructor */ - ~unexpected_call() throw(); + ~unexpected_call() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -411,7 +411,7 @@ class BOOST_LOG_API setup_error : /*! * Destructor */ - ~setup_error() throw(); + ~setup_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); @@ -438,7 +438,7 @@ class BOOST_LOG_API limitation_error : /*! * Destructor */ - ~limitation_error() throw(); + ~limitation_error() throw() BOOST_OVERRIDE; #ifndef BOOST_LOG_DOXYGEN_PASS static BOOST_LOG_NORETURN void throw_(const char* file, std::size_t line); diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index d7bfd30aed..97c2ec3afa 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -304,7 +304,7 @@ class asynchronous_sink : /*! * Destructor. Implicitly stops the dedicated feeding thread, if one is running. */ - ~asynchronous_sink() BOOST_NOEXCEPT + ~asynchronous_sink() BOOST_NOEXCEPT BOOST_OVERRIDE { try { @@ -328,7 +328,7 @@ class asynchronous_sink : /*! * Enqueues the log record to the backend */ - void consume(record_view const& rec) + void consume(record_view const& rec) BOOST_OVERRIDE { if (BOOST_UNLIKELY(m_FlushRequested.load(boost::memory_order_acquire))) { @@ -343,7 +343,7 @@ class asynchronous_sink : /*! * The method attempts to pass logging record to the backend */ - bool try_consume(record_view const& rec) + bool try_consume(record_view const& rec) BOOST_OVERRIDE { if (!m_FlushRequested.load(boost::memory_order_acquire)) { @@ -439,7 +439,7 @@ class asynchronous_sink : * Unlike \c feed_records, in case of ordering queueing the method also feeds records * that were enqueued during the ordering window, attempting to empty the queue completely. */ - void flush() + void flush() BOOST_OVERRIDE { unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (m_FeedingThreadID != thread::id() || m_DedicatedFeedingThread.joinable()) diff --git a/include/boost/log/sinks/basic_sink_frontend.hpp b/include/boost/log/sinks/basic_sink_frontend.hpp index 3686bc5917..e30c6a28cc 100644 --- a/include/boost/log/sinks/basic_sink_frontend.hpp +++ b/include/boost/log/sinks/basic_sink_frontend.hpp @@ -122,7 +122,7 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : * * \param attrs A set of attribute values of a logging record */ - bool will_consume(attribute_value_set const& attrs) + bool will_consume(attribute_value_set const& attrs) BOOST_OVERRIDE { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) try diff --git a/include/boost/log/sinks/sync_frontend.hpp b/include/boost/log/sinks/sync_frontend.hpp index 6a927d0571..ccf5c9022f 100644 --- a/include/boost/log/sinks/sync_frontend.hpp +++ b/include/boost/log/sinks/sync_frontend.hpp @@ -148,7 +148,7 @@ class synchronous_sink : /*! * Passes the log record to the backend */ - void consume(record_view const& rec) + void consume(record_view const& rec) BOOST_OVERRIDE { base_type::feed_record(rec, m_BackendMutex, *m_pBackend); } @@ -156,7 +156,7 @@ class synchronous_sink : /*! * The method attempts to pass logging record to the backend */ - bool try_consume(record_view const& rec) + bool try_consume(record_view const& rec) BOOST_OVERRIDE { return base_type::try_feed_record(rec, m_BackendMutex, *m_pBackend); } @@ -166,7 +166,7 @@ class synchronous_sink : * may take considerable time to complete and may block both the calling thread and threads * attempting to put new records into the sink while this call is in progress. */ - void flush() + void flush() BOOST_OVERRIDE { base_type::flush_backend(m_BackendMutex, *m_pBackend); } diff --git a/include/boost/log/sources/severity_feature.hpp b/include/boost/log/sources/severity_feature.hpp index 101769bda1..83a9991ec3 100644 --- a/include/boost/log/sources/severity_feature.hpp +++ b/include/boost/log/sources/severity_feature.hpp @@ -67,7 +67,7 @@ namespace aux { { public: //! The method dispatches the value to the given object - bool dispatch(type_dispatcher& dispatcher) + bool dispatch(type_dispatcher& dispatcher) BOOST_OVERRIDE { type_dispatcher::callback< value_type > callback = dispatcher.get_callback< value_type >(); if (callback) @@ -80,7 +80,7 @@ namespace aux { } //! The method is called when the attribute value is passed to another thread - intrusive_ptr< attribute_value::impl > detach_from_thread() + intrusive_ptr< attribute_value::impl > detach_from_thread() BOOST_OVERRIDE { #if !defined(BOOST_LOG_NO_THREADS) return new attributes::attribute_value_impl< value_type >( diff --git a/src/default_sink.hpp b/src/default_sink.hpp index bdcd3f46f0..ed2c033886 100644 --- a/src/default_sink.hpp +++ b/src/default_sink.hpp @@ -56,10 +56,10 @@ class default_sink : public: default_sink(); - ~default_sink(); - bool will_consume(attribute_value_set const&); - void consume(record_view const& rec); - void flush(); + ~default_sink() BOOST_OVERRIDE; + bool will_consume(attribute_value_set const&) BOOST_OVERRIDE; + void consume(record_view const& rec) BOOST_OVERRIDE; + void flush() BOOST_OVERRIDE; }; } // namespace aux diff --git a/src/named_scope.cpp b/src/named_scope.cpp index fff80a1d4a..176e91fbfb 100644 --- a/src/named_scope.cpp +++ b/src/named_scope.cpp @@ -92,7 +92,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! The method dispatches the value to the given object. It returns true if the //! object was capable to consume the real attribute value type and false otherwise. - bool dispatch(type_dispatcher& dispatcher) + bool dispatch(type_dispatcher& dispatcher) BOOST_OVERRIDE { type_dispatcher::callback< scope_stack > callback = dispatcher.get_callback< scope_stack >(); @@ -108,11 +108,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { /*! * \return The attribute value type */ - typeindex::type_index get_type() const { return typeindex::type_id< scope_stack >(); } + typeindex::type_index get_type() const BOOST_OVERRIDE { return typeindex::type_id< scope_stack >(); } //! The method is called when the attribute value is passed to another thread (e.g. //! in case of asynchronous logging). The value should ensure it properly owns all thread-specific data. - intrusive_ptr< attribute_value::impl > detach_from_thread() + intrusive_ptr< attribute_value::impl > detach_from_thread() BOOST_OVERRIDE { if (!m_DetachedValue) { @@ -186,7 +186,7 @@ struct BOOST_SYMBOL_VISIBLE named_scope::impl : } //! The method returns the actual attribute value. It must not return NULL. - attribute_value get_value() + attribute_value get_value() BOOST_OVERRIDE { return attribute_value(new named_scope_value(&get_scope_list())); } diff --git a/src/setup/default_filter_factory.hpp b/src/setup/default_filter_factory.hpp index 455eb42434..e5d55a63ee 100644 --- a/src/setup/default_filter_factory.hpp +++ b/src/setup/default_filter_factory.hpp @@ -70,20 +70,20 @@ class default_filter_factory : typedef typename base_type::string_type string_type; //! The callback for equality relation filter - virtual filter on_equality_relation(attribute_name const& name, string_type const& arg); + filter on_equality_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for inequality relation filter - virtual filter on_inequality_relation(attribute_name const& name, string_type const& arg); + filter on_inequality_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for less relation filter - virtual filter on_less_relation(attribute_name const& name, string_type const& arg); + filter on_less_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for greater relation filter - virtual filter on_greater_relation(attribute_name const& name, string_type const& arg); + filter on_greater_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for less or equal relation filter - virtual filter on_less_or_equal_relation(attribute_name const& name, string_type const& arg); + filter on_less_or_equal_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for greater or equal relation filter - virtual filter on_greater_or_equal_relation(attribute_name const& name, string_type const& arg); + filter on_greater_or_equal_relation(attribute_name const& name, string_type const& arg) BOOST_OVERRIDE; //! The callback for custom relation filter - virtual filter on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg); + filter on_custom_relation(attribute_name const& name, string_type const& rel, string_type const& arg) BOOST_OVERRIDE; private: //! The function parses the argument value for a binary relation and constructs the corresponding filter diff --git a/src/setup/default_formatter_factory.hpp b/src/setup/default_formatter_factory.hpp index 6359b3be8b..8428137ed5 100644 --- a/src/setup/default_formatter_factory.hpp +++ b/src/setup/default_formatter_factory.hpp @@ -45,7 +45,7 @@ class default_formatter_factory : typedef typename base_type::args_map args_map; //! The function creates a formatter for the specified attribute. - virtual formatter_type create_formatter(attribute_name const& name, args_map const& args); + formatter_type create_formatter(attribute_name const& name, args_map const& args) BOOST_OVERRIDE; }; } // namespace aux diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 7b5b6285a4..91c46ab642 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -434,7 +434,7 @@ class default_console_sink_factory : public: //! The function constructs a sink that writes log records to the console - shared_ptr< sinks::sink > create_sink(settings_section const& params) + shared_ptr< sinks::sink > create_sink(settings_section const& params) BOOST_OVERRIDE { return base_type::select_backend_character_type(params, impl()); } @@ -454,7 +454,7 @@ class default_text_file_sink_factory : public: //! The function constructs a sink that writes log records to a text file - shared_ptr< sinks::sink > create_sink(settings_section const& params) + shared_ptr< sinks::sink > create_sink(settings_section const& params) BOOST_OVERRIDE { typedef sinks::text_file_backend backend_t; shared_ptr< backend_t > backend = boost::make_shared< backend_t >(); @@ -579,7 +579,7 @@ class default_syslog_sink_factory : public: //! The function constructs a sink that writes log records to syslog - shared_ptr< sinks::sink > create_sink(settings_section const& params) + shared_ptr< sinks::sink > create_sink(settings_section const& params) BOOST_OVERRIDE { // Construct the backend typedef sinks::syslog_backend backend_t; diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index d4b5085bbf..9ce19f4a99 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -194,7 +194,7 @@ struct syslog_backend::implementation::native : } //! The method sends the formatted message to the syslog host - void send(syslog::level lev, string_type const& formatted_message) + void send(syslog::level lev, string_type const& formatted_message) BOOST_OVERRIDE { int native_level; switch (lev) @@ -447,7 +447,7 @@ struct syslog_backend::implementation::udp_socket_based : } //! The method sends the formatted message to the syslog host - void send(syslog::level lev, string_type const& formatted_message) + void send(syslog::level lev, string_type const& formatted_message) BOOST_OVERRIDE { if (!m_pSocket.get()) { diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index f71f832d91..1fbf0c27a9 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -659,14 +659,14 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { uintmax_t max_files); //! Destructor - ~file_collector(); + ~file_collector() BOOST_OVERRIDE; //! The function stores the specified file in the storage - void store_file(filesystem::path const& file_name); + void store_file(filesystem::path const& file_name) BOOST_OVERRIDE; //! Scans the target directory for the files that have already been stored uintmax_t scan_for_files( - file::scan_method method, filesystem::path const& pattern, unsigned int* counter); + file::scan_method method, filesystem::path const& pattern, unsigned int* counter) BOOST_OVERRIDE; //! The function updates storage restrictions void update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files); @@ -1345,7 +1345,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ { // The file stream is not operational. One possible reason is that there is no more free space // on the file system. In this case it is possible that this log record will fail to be written as well, - // leaving the newly creted file empty. Eventually this results in lots of empty log files. + // leaving the newly created file empty. Eventually this results in lots of empty log files. // We should take precautions to avoid this. https://svn.boost.org/trac/boost/ticket/11016 prev_file_name = m_pImpl->m_FileName; close_file(); diff --git a/src/threadsafe_queue.cpp b/src/threadsafe_queue.cpp index bbad463dec..1a1656194a 100644 --- a/src/threadsafe_queue.cpp +++ b/src/threadsafe_queue.cpp @@ -76,11 +76,11 @@ class threadsafe_queue_impl_generic : m_Head.node = m_Tail.node = first_node; } - ~threadsafe_queue_impl_generic() + ~threadsafe_queue_impl_generic() BOOST_OVERRIDE { } - node_base* reset_last_node() + node_base* reset_last_node() BOOST_OVERRIDE { BOOST_ASSERT(m_Head.node == m_Tail.node); node_base* p = m_Head.node; @@ -88,12 +88,12 @@ class threadsafe_queue_impl_generic : return p; } - bool unsafe_empty() + bool unsafe_empty() BOOST_OVERRIDE { return m_Head.node == m_Tail.node; } - void push(node_base* p) + void push(node_base* p) BOOST_OVERRIDE { set_next(p, NULL); exclusive_lock_guard< mutex_type > _(m_Tail.mutex); @@ -101,7 +101,7 @@ class threadsafe_queue_impl_generic : m_Tail.node = p; } - bool try_pop(node_base*& node_to_free, node_base*& node_with_value) + bool try_pop(node_base*& node_to_free, node_base*& node_with_value) BOOST_OVERRIDE { exclusive_lock_guard< mutex_type > _(m_Head.mutex); node_base* next = get_next(m_Head.node); diff --git a/src/timer.cpp b/src/timer.cpp index f9b4cdfdb5..db55ea7bcd 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -131,7 +131,7 @@ class BOOST_SYMBOL_VISIBLE timer::impl : */ impl() : m_BaseTimePoint(utc_time_traits::get_clock()) {} - attribute_value get_value() + attribute_value get_value() BOOST_OVERRIDE { return attribute_value(new attribute_value_impl< value_type >( utc_time_traits::get_clock() - m_BaseTimePoint)); From a79103cb3dedb6582d24a09e553874e0a5b5f6bc Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 5 May 2020 14:41:56 +0300 Subject: [PATCH 079/309] Removed linking with Boost.DateTime. Boost.DateTime is now header-only. --- build/Jamfile.v2 | 1 - test/Jamfile.v2 | 1 - 2 files changed, 2 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index a172767ab5..36446d1bde 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -213,7 +213,6 @@ project boost/log gcc,windows:-Wl,--enable-auto-import gcc,cygwin:-Wl,--enable-auto-import - /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS multi:/boost/atomic//boost_atomic diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 1124693230..eed81d8eb5 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -61,7 +61,6 @@ project /boost/log//boost_log /boost/log//boost_log_setup - /boost/date_time//boost_date_time /boost/regex//boost_regex /boost/filesystem//boost_filesystem /boost/test//boost_unit_test_framework From 89d1ff541d236ef8ad70931d350b35be6699a902 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 5 May 2020 23:06:33 +0300 Subject: [PATCH 080/309] Added clang-10 jobs to Travis CI. --- .travis.yml | 40 +++++++++++++++++++++++++++------------- 1 file changed, 27 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7a8b2369df..6eb816741e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -288,48 +288,62 @@ matrix: - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" + - os: linux + dist: xenial + compiler: clang-10 + env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 + addons: + apt: + packages: + - clang-10 + - libstdc++-9-dev + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" + - os: linux dist: xenial compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - - clang-9 + - clang-10 - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-9 - - libc++-9-dev - - libc++abi-9-dev + - clang-10 + - libc++-10-dev + - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-9 - - libc++-9-dev - - libc++abi-9-dev + - clang-10 + - libc++-10-dev + - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X From 4d16fb6608013a12d86a6c5a491e42dd7712c111 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 7 May 2020 17:34:42 +0300 Subject: [PATCH 081/309] Disable UBSAN tests in C++20 mode to work around Boost.Xpressive bug. UBSAN inticates test failures caused by Boost.Xpressive. To be fixed by: https://github.com/boostorg/xpressive/pull/13 --- .travis.yml | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6eb816741e..6bbd97e8b1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -304,28 +304,30 @@ matrix: - os: linux dist: xenial - compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 + compiler: clang-libc++ + env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - clang-10 - - libstdc++-9-dev + - libc++-10-dev + - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" +# Note: Don't run UBSAN tests in C++20 mode because of Boost.Xpressive bug to be fixed by https://github.com/boostorg/xpressive/pull/13. +# Re-enable C++20 when that bug is fixed. - os: linux dist: xenial - compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + compiler: clang-UBSAN + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - clang-10 - - libc++-10-dev - - libc++abi-10-dev + - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" @@ -334,7 +336,7 @@ matrix: - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: From 706fed3bf4f57f00d8a2da5c044e5322b39ece19 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 7 May 2020 17:48:38 +0300 Subject: [PATCH 082/309] Avoid unnecessary copy of the filename string. --- src/text_file_backend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 1fbf0c27a9..dd60085806 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -773,8 +773,8 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { info.m_TimeStamp = filesystem::last_write_time(src_path); info.m_Size = filesystem::file_size(src_path); - filesystem::path file_name_path = src_path.filename(); - path_string_type file_name = file_name_path.native(); + const filesystem::path file_name_path = src_path.filename(); + path_string_type const& file_name = file_name_path.native(); info.m_Path = m_StorageDir / file_name_path; // Check if the file is already in the target directory @@ -862,7 +862,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (m_MinFreeSpace) free_space = filesystem::space(m_StorageDir).available; m_TotalSize -= old_info.m_Size; - m_Files.erase(it++); + it = m_Files.erase(it); } catch (system::system_error&) { @@ -874,7 +874,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { { // If it's not a file or is absent, just remove it from the list m_TotalSize -= old_info.m_Size; - m_Files.erase(it++); + it = m_Files.erase(it); } } From 9a85efde0840e3e4954f07da66dbdad72cc1a636 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 7 May 2020 20:35:14 +0300 Subject: [PATCH 083/309] Added noexcept specifiers. Made logger move ctors more noexcept-friendly. Logger move constructors don't need to add the attributes to the logger attributes since the latter are moved from the source logger, just as the attributes. This allows move constructors to be noexcept, provided that they are non-noexcept for other reasons. Closes https://github.com/boostorg/log/issues/121. --- .../boost/log/attributes/attribute_value.hpp | 2 +- .../log/attributes/attribute_value_impl.hpp | 6 +- include/boost/log/attributes/constant.hpp | 6 +- include/boost/log/attributes/named_scope.hpp | 2 +- .../boost/log/attributes/scoped_attribute.hpp | 11 ++-- include/boost/log/detail/enqueued_record.hpp | 8 +-- include/boost/log/detail/format.hpp | 4 +- include/boost/log/detail/locks.hpp | 8 +-- include/boost/log/detail/timestamp.hpp | 4 +- include/boost/log/sources/basic_logger.hpp | 44 +++++++------ include/boost/log/sources/channel_feature.hpp | 7 +- .../log/sources/exception_handler_feature.hpp | 5 +- .../boost/log/sources/severity_feature.hpp | 24 +++---- .../boost/log/sources/threading_models.hpp | 64 +++++++++++-------- include/boost/log/utility/setup/settings.hpp | 16 ++--- include/boost/log/utility/strictest_lock.hpp | 5 ++ src/named_scope_format_parser.cpp | 4 +- 17 files changed, 128 insertions(+), 92 deletions(-) diff --git a/include/boost/log/attributes/attribute_value.hpp b/include/boost/log/attributes/attribute_value.hpp index a309af628f..595ae21887 100644 --- a/include/boost/log/attributes/attribute_value.hpp +++ b/include/boost/log/attributes/attribute_value.hpp @@ -114,7 +114,7 @@ class attribute_value /*! * Default constructor. Creates an empty (absent) attribute value. */ - BOOST_DEFAULTED_FUNCTION(attribute_value(), {}) + BOOST_DEFAULTED_FUNCTION(attribute_value(), BOOST_NOEXCEPT {}) /*! * Copy constructor diff --git a/include/boost/log/attributes/attribute_value_impl.hpp b/include/boost/log/attributes/attribute_value_impl.hpp index 468d127a99..f1439525bd 100644 --- a/include/boost/log/attributes/attribute_value_impl.hpp +++ b/include/boost/log/attributes/attribute_value_impl.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -64,7 +65,10 @@ class attribute_value_impl : /*! * Constructor with initialization of the stored value */ - explicit attribute_value_impl(BOOST_RV_REF(value_type) v) : m_value(boost::move(v)) {} + explicit attribute_value_impl(BOOST_RV_REF(value_type) v) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< value_type >::value) : + m_value(boost::move(v)) + { + } /*! * Attribute value dispatching method. diff --git a/include/boost/log/attributes/constant.hpp b/include/boost/log/attributes/constant.hpp index f10b0a7e5b..bfc2877879 100644 --- a/include/boost/log/attributes/constant.hpp +++ b/include/boost/log/attributes/constant.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -66,7 +67,10 @@ class constant : /*! * Constructor with the stored value initialization */ - explicit impl(BOOST_RV_REF(value_type) value) : base_type(boost::move(value)) {} + explicit impl(BOOST_RV_REF(value_type) value) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< value_type >::value) : + base_type(boost::move(value)) + { + } }; public: diff --git a/include/boost/log/attributes/named_scope.hpp b/include/boost/log/attributes/named_scope.hpp index ed338c6726..0587028dea 100644 --- a/include/boost/log/attributes/named_scope.hpp +++ b/include/boost/log/attributes/named_scope.hpp @@ -20,9 +20,9 @@ #include #include #include -#include #include #include +#include #include #include #include diff --git a/include/boost/log/attributes/scoped_attribute.hpp b/include/boost/log/attributes/scoped_attribute.hpp index 88dd218e4c..b258150f15 100644 --- a/include/boost/log/attributes/scoped_attribute.hpp +++ b/include/boost/log/attributes/scoped_attribute.hpp @@ -15,6 +15,7 @@ #ifndef BOOST_LOG_ATTRIBUTES_SCOPED_ATTRIBUTE_HPP_INCLUDED_ #define BOOST_LOG_ATTRIBUTES_SCOPED_ATTRIBUTE_HPP_INCLUDED_ +#include #include #include #include @@ -81,14 +82,14 @@ class scoped_logger_attribute : if (res.second) m_itAttribute = res.first; else - m_pLogger = 0; // if there already is a same-named attribute, don't register anything + m_pLogger = NULL; // if there already is a same-named attribute, don't register anything } //! Move constructor - scoped_logger_attribute(BOOST_RV_REF(scoped_logger_attribute) that) : + scoped_logger_attribute(BOOST_RV_REF(scoped_logger_attribute) that) BOOST_NOEXCEPT : m_pLogger(that.m_pLogger), m_itAttribute(that.m_itAttribute) { - that.m_pLogger = 0; + that.m_pLogger = NULL; } //! Destructor @@ -101,9 +102,9 @@ class scoped_logger_attribute : #ifndef BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT BOOST_DELETED_FUNCTION(scoped_logger_attribute(scoped_logger_attribute const&)) #else // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT - scoped_logger_attribute(scoped_logger_attribute const& that) : m_pLogger(that.m_pLogger), m_itAttribute(that.m_itAttribute) + scoped_logger_attribute(scoped_logger_attribute const& that) BOOST_NOEXCEPT : m_pLogger(that.m_pLogger), m_itAttribute(that.m_itAttribute) { - const_cast< scoped_logger_attribute& >(that).m_pLogger = 0; + const_cast< scoped_logger_attribute& >(that).m_pLogger = NULL; } #endif // BOOST_LOG_BROKEN_REFERENCE_FROM_RVALUE_INIT diff --git a/include/boost/log/detail/enqueued_record.hpp b/include/boost/log/detail/enqueued_record.hpp index f4821363a2..a5c6e01811 100644 --- a/include/boost/log/detail/enqueued_record.hpp +++ b/include/boost/log/detail/enqueued_record.hpp @@ -63,10 +63,10 @@ class enqueued_record boost::log::aux::timestamp m_timestamp; record_view m_record; - enqueued_record(enqueued_record const& that) : m_timestamp(that.m_timestamp), m_record(that.m_record) + enqueued_record(enqueued_record const& that) BOOST_NOEXCEPT : m_timestamp(that.m_timestamp), m_record(that.m_record) { } - enqueued_record(BOOST_RV_REF(enqueued_record) that) : + enqueued_record(BOOST_RV_REF(enqueued_record) that) BOOST_NOEXCEPT : m_timestamp(that.m_timestamp), m_record(boost::move(that.m_record)) { @@ -76,13 +76,13 @@ class enqueued_record m_record(rec) { } - enqueued_record& operator= (BOOST_COPY_ASSIGN_REF(enqueued_record) that) + enqueued_record& operator= (BOOST_COPY_ASSIGN_REF(enqueued_record) that) BOOST_NOEXCEPT { m_timestamp = that.m_timestamp; m_record = that.m_record; return *this; } - enqueued_record& operator= (BOOST_RV_REF(enqueued_record) that) + enqueued_record& operator= (BOOST_RV_REF(enqueued_record) that) BOOST_NOEXCEPT { m_timestamp = that.m_timestamp; m_record = boost::move(that.m_record); diff --git a/include/boost/log/detail/format.hpp b/include/boost/log/detail/format.hpp index 1394c14697..0ce0340b7f 100644 --- a/include/boost/log/detail/format.hpp +++ b/include/boost/log/detail/format.hpp @@ -94,13 +94,13 @@ struct format_description { } - format_description(BOOST_RV_REF(format_description) that) + format_description(BOOST_RV_REF(format_description) that) BOOST_NOEXCEPT { literal_chars.swap(that.literal_chars); format_elements.swap(that.format_elements); } - format_description& operator= (format_description that) + format_description& operator= (format_description that) BOOST_NOEXCEPT { literal_chars.swap(that.literal_chars); format_elements.swap(that.format_elements); diff --git a/include/boost/log/detail/locks.hpp b/include/boost/log/detail/locks.hpp index 224d8e59bb..fcc32a2c68 100644 --- a/include/boost/log/detail/locks.hpp +++ b/include/boost/log/detail/locks.hpp @@ -55,7 +55,7 @@ class no_lock /*! * Constructs the pseudo-lock. The mutex is not affected during the construction. */ - explicit no_lock(MutexT&) {} + explicit no_lock(MutexT&) BOOST_NOEXCEPT {} private: no_lock(no_lock const&); @@ -117,7 +117,7 @@ struct exclusive_auto_unlocker template< typename MutexT > struct exclusive_lock_guard { - explicit exclusive_lock_guard(MutexT& m) : m_Mutex(m) + explicit exclusive_lock_guard(MutexT& m) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m.lock())) : m_Mutex(m) { m.lock(); } @@ -137,7 +137,7 @@ struct exclusive_lock_guard template< typename MutexT > struct shared_lock_guard { - explicit shared_lock_guard(MutexT& m) : m_Mutex(m) + explicit shared_lock_guard(MutexT& m) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m.lock_shared())) : m_Mutex(m) { m.lock_shared(); } @@ -158,7 +158,7 @@ template< typename MutexT1, typename MutexT2 > class multiple_unique_lock2 { public: - multiple_unique_lock2(MutexT1& m1, MutexT2& m2) : + multiple_unique_lock2(MutexT1& m1, MutexT2& m2) BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(m1.lock()) && BOOST_NOEXCEPT_EXPR(m2.lock())) : m_p1(&m1), m_p2(&m2) { diff --git a/include/boost/log/detail/timestamp.hpp b/include/boost/log/detail/timestamp.hpp index 7c8bd84532..da7e0b8073 100644 --- a/include/boost/log/detail/timestamp.hpp +++ b/include/boost/log/detail/timestamp.hpp @@ -41,7 +41,7 @@ class duration int64_t m_ticks; public: - explicit duration(int64_t ticks = 0) : m_ticks(ticks) {} + explicit duration(int64_t ticks = 0) BOOST_NOEXCEPT : m_ticks(ticks) {} #if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) int64_t milliseconds() const { return m_ticks; } @@ -58,7 +58,7 @@ class timestamp uint64_t m_ticks; public: - explicit timestamp(uint64_t ticks = 0) : m_ticks(ticks) {} + explicit timestamp(uint64_t ticks = 0) BOOST_NOEXCEPT : m_ticks(ticks) {} duration operator- (timestamp that) const { diff --git a/include/boost/log/sources/basic_logger.hpp b/include/boost/log/sources/basic_logger.hpp index 58bd6594c5..8138e65ab9 100644 --- a/include/boost/log/sources/basic_logger.hpp +++ b/include/boost/log/sources/basic_logger.hpp @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include #include #include @@ -92,7 +94,7 @@ class basic_logger : #if !defined(BOOST_LOG_NO_THREADS) //! Lock requirement for the swap_unlocked method - typedef boost::log::aux::exclusive_lock_guard< threading_model > swap_lock; + typedef boost::log::aux::multiple_unique_lock2< threading_model, threading_model > swap_lock; //! Lock requirement for the add_attribute_unlocked method typedef boost::log::aux::exclusive_lock_guard< threading_model > add_attribute_lock; //! Lock requirement for the remove_attribute_unlocked method @@ -144,7 +146,7 @@ class basic_logger : */ basic_logger(basic_logger const& that) : threading_model(static_cast< threading_model const& >(that)), - m_pCore(core::get()), + m_pCore(that.m_pCore), m_Attributes(that.m_Attributes) { } @@ -155,11 +157,13 @@ class basic_logger : * * \param that Source logger */ - basic_logger(BOOST_RV_REF(basic_logger) that) : - threading_model(boost::move(static_cast< threading_model& >(that))) + basic_logger(BOOST_RV_REF(basic_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< threading_model >::value && + boost::is_nothrow_move_constructible< core_ptr >::value && + boost::is_nothrow_move_constructible< attribute_set >::value) : + threading_model(boost::move(static_cast< threading_model& >(that))), + m_pCore(boost::move(that.m_pCore)), + m_Attributes(boost::move(that.m_Attributes)) { - m_pCore.swap(that.m_pCore); - m_Attributes.swap(that.m_Attributes); } /*! * Constructor with named arguments. The constructor ignores all arguments. The result of @@ -188,15 +192,15 @@ class basic_logger : /*! * An accessor to the threading model base */ - threading_model& get_threading_model() { return *this; } + threading_model& get_threading_model() BOOST_NOEXCEPT { return *this; } /*! * An accessor to the threading model base */ - threading_model const& get_threading_model() const { return *this; } + threading_model const& get_threading_model() const BOOST_NOEXCEPT { return *this; } /*! * An accessor to the final logger */ - final_type* final_this() + final_type* final_this() BOOST_NOEXCEPT { BOOST_LOG_ASSUME(this != NULL); return static_cast< final_type* >(this); @@ -204,7 +208,7 @@ class basic_logger : /*! * An accessor to the final logger */ - final_type const* final_this() const + final_type const* final_this() const BOOST_NOEXCEPT { BOOST_LOG_ASSUME(this != NULL); return static_cast< final_type const* >(this); @@ -293,7 +297,7 @@ class basic_logger : template< typename CharT, typename FinalT, typename ThreadingModelT > inline void swap( basic_logger< CharT, FinalT, ThreadingModelT >& left, - basic_logger< CharT, FinalT, ThreadingModelT >& right) + basic_logger< CharT, FinalT, ThreadingModelT >& right) BOOST_NOEXCEPT_IF(boost::is_nothrow_swappable< FinalT >::value) { static_cast< FinalT& >(left).swap(static_cast< FinalT& >(right)); } @@ -332,6 +336,9 @@ class basic_composite_logger : //! Threading model being used typedef typename base_type::threading_model threading_model; + //! Lock requirement for the swap_unlocked method + typedef typename base_type::swap_lock swap_lock; + #if !defined(BOOST_LOG_NO_THREADS) public: @@ -353,7 +360,7 @@ class basic_composite_logger : /*! * Move constructor */ - basic_composite_logger(BOOST_RV_REF(logger_base) that) : + basic_composite_logger(BOOST_RV_REF(logger_base) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value) : base_type(boost::move(static_cast< base_type& >(that))) { } @@ -476,11 +483,8 @@ class basic_composite_logger : */ void swap(basic_composite_logger& that) { - boost::log::aux::multiple_unique_lock2< - threading_model, - threading_model - > lock(base_type::get_threading_model(), that.get_threading_model()); - base_type::swap_unlocked(that); + swap_lock lock(base_type::get_threading_model(), that.get_threading_model()); + base_type::swap_unlocked(static_cast< base_type& >(that)); } protected: @@ -530,7 +534,7 @@ class basic_composite_logger< CharT, FinalT, single_thread_model, FeaturesT > : base_type(static_cast< base_type const& >(that)) { } - basic_composite_logger(BOOST_RV_REF(logger_base) that) : + basic_composite_logger(BOOST_RV_REF(logger_base) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value) : base_type(boost::move(static_cast< base_type& >(that))) { } @@ -582,7 +586,7 @@ class basic_composite_logger< CharT, FinalT, single_thread_model, FeaturesT > : } void swap(basic_composite_logger& that) { - base_type::swap_unlocked(that); + base_type::swap_unlocked(static_cast< base_type& >(that)); } protected: @@ -601,7 +605,7 @@ class basic_composite_logger< CharT, FinalT, single_thread_model, FeaturesT > : BOOST_DEFAULTED_FUNCTION(class_type(), {})\ class_type(class_type const& that) : class_type::logger_base(\ static_cast< typename_keyword() class_type::logger_base const& >(that)) {}\ - class_type(BOOST_RV_REF(class_type) that) : class_type::logger_base(\ + class_type(BOOST_RV_REF(class_type) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< typename_keyword() class_type::logger_base >::value) : class_type::logger_base(\ ::boost::move(static_cast< typename_keyword() class_type::logger_base& >(that))) {}\ BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_FORWARD(class_type, class_type::logger_base)\ diff --git a/include/boost/log/sources/channel_feature.hpp b/include/boost/log/sources/channel_feature.hpp index d7e88c4aad..894c2697a5 100644 --- a/include/boost/log/sources/channel_feature.hpp +++ b/include/boost/log/sources/channel_feature.hpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -76,7 +77,7 @@ class basic_channel_logger : typedef typename strictest_lock< typename base_type::swap_lock, #ifndef BOOST_LOG_NO_THREADS - boost::log::aux::exclusive_lock_guard< threading_model > + boost::log::aux::multiple_unique_lock2< threading_model, threading_model > #else no_lock< threading_model > #endif // !defined(BOOST_LOG_NO_THREADS) @@ -109,16 +110,16 @@ class basic_channel_logger : base_type(static_cast< base_type const& >(that)), m_ChannelAttr(that.m_ChannelAttr) { + // Our attributes must refer to our channel attribute base_type::attributes()[boost::log::aux::default_attribute_names::channel()] = m_ChannelAttr; } /*! * Move constructor */ - basic_channel_logger(BOOST_RV_REF(basic_channel_logger) that) : + basic_channel_logger(BOOST_RV_REF(basic_channel_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value && boost::is_nothrow_move_constructible< channel_attribute >::value) : base_type(boost::move(static_cast< base_type& >(that))), m_ChannelAttr(boost::move(that.m_ChannelAttr)) { - base_type::attributes()[boost::log::aux::default_attribute_names::channel()] = m_ChannelAttr; } /*! * Constructor with arguments. Allows to register a channel name attribute on construction. diff --git a/include/boost/log/sources/exception_handler_feature.hpp b/include/boost/log/sources/exception_handler_feature.hpp index d29041109d..146815e0d4 100644 --- a/include/boost/log/sources/exception_handler_feature.hpp +++ b/include/boost/log/sources/exception_handler_feature.hpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -77,7 +78,7 @@ class basic_exception_handler_logger : typedef typename strictest_lock< typename base_type::swap_lock, #ifndef BOOST_LOG_NO_THREADS - boost::log::aux::exclusive_lock_guard< threading_model > + boost::log::aux::multiple_unique_lock2< threading_model, threading_model > #else no_lock< threading_model > #endif // !defined(BOOST_LOG_NO_THREADS) @@ -105,7 +106,7 @@ class basic_exception_handler_logger : /*! * Move constructor */ - basic_exception_handler_logger(BOOST_RV_REF(basic_exception_handler_logger) that) : + basic_exception_handler_logger(BOOST_RV_REF(basic_exception_handler_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value && boost::is_nothrow_move_constructible< exception_handler_type >::value) : base_type(boost::move(static_cast< base_type& >(that))), m_ExceptionHandler(boost::move(that.m_ExceptionHandler)) { diff --git a/include/boost/log/sources/severity_feature.hpp b/include/boost/log/sources/severity_feature.hpp index 83a9991ec3..e798fb0dde 100644 --- a/include/boost/log/sources/severity_feature.hpp +++ b/include/boost/log/sources/severity_feature.hpp @@ -17,9 +17,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -98,11 +100,11 @@ namespace aux { { } //! Copy constructor - severity_level(severity_level const& that) : attribute(static_cast< attribute const& >(that)) + severity_level(severity_level const& that) BOOST_NOEXCEPT : attribute(static_cast< attribute const& >(that)) { } //! Move constructor - severity_level(BOOST_RV_REF(severity_level) that) : attribute(boost::move(static_cast< attribute& >(that))) + severity_level(BOOST_RV_REF(severity_level) that) BOOST_NOEXCEPT : attribute(boost::move(static_cast< attribute& >(that))) { } //! Constructor for casting support @@ -114,16 +116,16 @@ namespace aux { /*! * Copy assignment */ - severity_level& operator= (BOOST_COPY_ASSIGN_REF(severity_level) that) + severity_level& operator= (BOOST_COPY_ASSIGN_REF(severity_level) that) BOOST_NOEXCEPT { - attribute::operator= (that); + attribute::operator= (static_cast< attribute const& >(that)); return *this; } /*! * Move assignment */ - severity_level& operator= (BOOST_RV_REF(severity_level) that) + severity_level& operator= (BOOST_RV_REF(severity_level) that) BOOST_NOEXCEPT { this->swap(that); return *this; @@ -175,7 +177,7 @@ class basic_severity_logger : typedef typename strictest_lock< typename base_type::swap_lock, #ifndef BOOST_LOG_NO_THREADS - boost::log::aux::exclusive_lock_guard< threading_model > + boost::log::aux::multiple_unique_lock2< threading_model, threading_model > #else no_lock< threading_model > #endif // !defined(BOOST_LOG_NO_THREADS) @@ -206,17 +208,19 @@ class basic_severity_logger : m_DefaultSeverity(that.m_DefaultSeverity), m_SeverityAttr(that.m_SeverityAttr) { + // Our attributes must refer to our severity attribute base_type::attributes()[boost::log::aux::default_attribute_names::severity()] = m_SeverityAttr; } /*! * Move constructor */ - basic_severity_logger(BOOST_RV_REF(basic_severity_logger) that) : + basic_severity_logger(BOOST_RV_REF(basic_severity_logger) that) BOOST_NOEXCEPT_IF(boost::is_nothrow_move_constructible< base_type >::value && + boost::is_nothrow_move_constructible< severity_level >::value && + boost::is_nothrow_move_constructible< severity_attribute >::value) : base_type(boost::move(static_cast< base_type& >(that))), m_DefaultSeverity(boost::move(that.m_DefaultSeverity)), m_SeverityAttr(boost::move(that.m_SeverityAttr)) { - base_type::attributes()[boost::log::aux::default_attribute_names::severity()] = m_SeverityAttr; } /*! * Constructor with named arguments. Allows to setup the default level for log records. @@ -257,9 +261,7 @@ class basic_severity_logger : void swap_unlocked(basic_severity_logger& that) { base_type::swap_unlocked(static_cast< base_type& >(that)); - severity_level t = m_DefaultSeverity; - m_DefaultSeverity = that.m_DefaultSeverity; - that.m_DefaultSeverity = t; + boost::swap(m_DefaultSeverity, that.m_DefaultSeverity); m_SeverityAttr.swap(that.m_SeverityAttr); } }; diff --git a/include/boost/log/sources/threading_models.hpp b/include/boost/log/sources/threading_models.hpp index 5fe6d1a6e4..b9a5220873 100644 --- a/include/boost/log/sources/threading_models.hpp +++ b/include/boost/log/sources/threading_models.hpp @@ -17,6 +17,7 @@ #ifndef BOOST_LOG_SOURCES_THREADING_MODELS_HPP_INCLUDED_ #define BOOST_LOG_SOURCES_THREADING_MODELS_HPP_INCLUDED_ +#include #include #include // is_mutex_type #if !defined(BOOST_LOG_NO_THREADS) @@ -38,66 +39,79 @@ namespace sources { struct single_thread_model { // We provide methods for the most advanced locking concept: UpgradeLockable - void lock_shared() const {} - bool try_lock_shared() const { return true; } + void lock_shared() const BOOST_NOEXCEPT {} + bool try_lock_shared() const BOOST_NOEXCEPT { return true; } template< typename TimeT > - bool timed_lock_shared(TimeT const&) const { return true; } - void unlock_shared() const {} - void lock() const {} - bool try_lock() const { return true; } + bool timed_lock_shared(TimeT const&) const BOOST_NOEXCEPT { return true; } + void unlock_shared() const BOOST_NOEXCEPT {} + void lock() const BOOST_NOEXCEPT {} + bool try_lock() const BOOST_NOEXCEPT { return true; } template< typename TimeT > - bool timed_lock(TimeT const&) const { return true; } - void unlock() const {} - void lock_upgrade() const {} - bool try_lock_upgrade() const { return true; } + bool timed_lock(TimeT const&) const BOOST_NOEXCEPT { return true; } + void unlock() const BOOST_NOEXCEPT {} + void lock_upgrade() const BOOST_NOEXCEPT {} + bool try_lock_upgrade() const BOOST_NOEXCEPT { return true; } template< typename TimeT > - bool timed_lock_upgrade(TimeT const&) const { return true; } - void unlock_upgrade() const {} - void unlock_upgrade_and_lock() const {} - void unlock_and_lock_upgrade() const {} - void unlock_and_lock_shared() const {} - void unlock_upgrade_and_lock_shared() const {} - - void swap(single_thread_model&) {} + bool timed_lock_upgrade(TimeT const&) const BOOST_NOEXCEPT { return true; } + void unlock_upgrade() const BOOST_NOEXCEPT {} + void unlock_upgrade_and_lock() const BOOST_NOEXCEPT {} + void unlock_and_lock_upgrade() const BOOST_NOEXCEPT {} + void unlock_and_lock_shared() const BOOST_NOEXCEPT {} + void unlock_upgrade_and_lock_shared() const BOOST_NOEXCEPT {} + + void swap(single_thread_model&) BOOST_NOEXCEPT {} }; +inline void swap(single_thread_model&, single_thread_model&) BOOST_NOEXCEPT +{ +} + #if !defined(BOOST_LOG_NO_THREADS) //! Multi-thread locking model with maximum locking capabilities template< typename MutexT > struct multi_thread_model { - multi_thread_model() {} - multi_thread_model(multi_thread_model const&) {} - multi_thread_model& operator= (multi_thread_model const&) { return *this; } + multi_thread_model() BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor< MutexT >::value) {} + multi_thread_model(multi_thread_model const&) BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor< MutexT >::value) {} + multi_thread_model& operator= (multi_thread_model const&) BOOST_NOEXCEPT { return *this; } +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + multi_thread_model(multi_thread_model&&) BOOST_NOEXCEPT_IF(boost::has_nothrow_constructor< MutexT >::value) {} + multi_thread_model& operator= (multi_thread_model&&) BOOST_NOEXCEPT { return *this; } +#endif void lock_shared() const { m_Mutex.lock_shared(); } bool try_lock_shared() const { return m_Mutex.try_lock_shared(); } template< typename TimeT > bool timed_lock_shared(TimeT const& t) const { return m_Mutex.timed_lock_shared(t); } - void unlock_shared() const { m_Mutex.unlock_shared(); } + void unlock_shared() const BOOST_NOEXCEPT { m_Mutex.unlock_shared(); } void lock() const { m_Mutex.lock(); } bool try_lock() const { return m_Mutex.try_lock(); } template< typename TimeT > bool timed_lock(TimeT const& t) const { return m_Mutex.timed_lock(t); } - void unlock() const { m_Mutex.unlock(); } + void unlock() const BOOST_NOEXCEPT { m_Mutex.unlock(); } void lock_upgrade() const { m_Mutex.lock_upgrade(); } bool try_lock_upgrade() const { return m_Mutex.try_lock_upgrade(); } template< typename TimeT > bool timed_lock_upgrade(TimeT const& t) const { return m_Mutex.timed_lock_upgrade(t); } - void unlock_upgrade() const { m_Mutex.unlock_upgrade(); } + void unlock_upgrade() const BOOST_NOEXCEPT { m_Mutex.unlock_upgrade(); } void unlock_upgrade_and_lock() const { m_Mutex.unlock_upgrade_and_lock(); } void unlock_and_lock_upgrade() const { m_Mutex.unlock_and_lock_upgrade(); } void unlock_and_lock_shared() const { m_Mutex.unlock_and_lock_shared(); } void unlock_upgrade_and_lock_shared() const { m_Mutex.unlock_upgrade_and_lock_shared(); } - void swap(multi_thread_model&) {} + void swap(multi_thread_model&) BOOST_NOEXCEPT {} private: //! Synchronization primitive mutable MutexT m_Mutex; }; +template< typename MutexT > +inline void swap(multi_thread_model< MutexT >&, multi_thread_model< MutexT >&) BOOST_NOEXCEPT +{ +} + #endif // !defined(BOOST_LOG_NO_THREADS) } // namespace sources diff --git a/include/boost/log/utility/setup/settings.hpp b/include/boost/log/utility/setup/settings.hpp index e7525c4ff4..24a8998fcd 100644 --- a/include/boost/log/utility/setup/settings.hpp +++ b/include/boost/log/utility/setup/settings.hpp @@ -354,14 +354,14 @@ class basic_settings_section /*! * Default constructor. Creates an empty settings container. */ - basic_settings_section() : m_ptree(NULL) + basic_settings_section() BOOST_NOEXCEPT : m_ptree(NULL) { } /*! * Copy constructor. */ - basic_settings_section(basic_settings_section const& that) : m_ptree(that.m_ptree) + basic_settings_section(basic_settings_section const& that) BOOST_NOEXCEPT : m_ptree(that.m_ptree) { } @@ -517,7 +517,7 @@ class basic_settings_section /*! * Swaps two references to settings sections. */ - void swap(basic_settings_section& that) + void swap(basic_settings_section& that) BOOST_NOEXCEPT { property_tree_type* const p = m_ptree; m_ptree = that.m_ptree; @@ -525,13 +525,13 @@ class basic_settings_section } protected: - explicit basic_settings_section(property_tree_type* tree) : m_ptree(tree) + explicit basic_settings_section(property_tree_type* tree) BOOST_NOEXCEPT : m_ptree(tree) { } }; template< typename CharT > -inline void swap(basic_settings_section< CharT >& left, basic_settings_section< CharT >& right) +inline void swap(basic_settings_section< CharT >& left, basic_settings_section< CharT >& right) BOOST_NOEXCEPT { left.swap(right); } @@ -584,7 +584,7 @@ class basic_settings : /*! * Move constructor. */ - basic_settings(BOOST_RV_REF(this_type) that) + basic_settings(BOOST_RV_REF(this_type) that) BOOST_NOEXCEPT { this->swap(that); } @@ -598,7 +598,7 @@ class basic_settings : /*! * Destructor */ - ~basic_settings() + ~basic_settings() BOOST_NOEXCEPT { delete this->m_ptree; } @@ -618,7 +618,7 @@ class basic_settings : /*! * Move assignment operator. */ - basic_settings& operator= (BOOST_RV_REF(basic_settings) that) + basic_settings& operator= (BOOST_RV_REF(basic_settings) that) BOOST_NOEXCEPT { this->swap(that); return *this; diff --git a/include/boost/log/utility/strictest_lock.hpp b/include/boost/log/utility/strictest_lock.hpp index 5dd48b4ffb..accc8b7a70 100644 --- a/include/boost/log/utility/strictest_lock.hpp +++ b/include/boost/log/utility/strictest_lock.hpp @@ -108,6 +108,11 @@ struct thread_access_mode_of< boost::log::aux::shared_lock_guard< MutexT > > : m { }; +template< typename MutexT1, typename MutexT2 > +struct thread_access_mode_of< boost::log::aux::multiple_unique_lock2< MutexT1, MutexT2 > > : mpl::integral_c< lock_access_mode, exclusive_access > +{ +}; + #endif // !defined(BOOST_LOG_NO_THREADS) namespace aux { diff --git a/src/named_scope_format_parser.cpp b/src/named_scope_format_parser.cpp index b393259472..5c8cf4fa23 100644 --- a/src/named_scope_format_parser.cpp +++ b/src/named_scope_format_parser.cpp @@ -595,9 +595,9 @@ class named_scope_formatter public: BOOST_DEFAULTED_FUNCTION(named_scope_formatter(), {}) named_scope_formatter(named_scope_formatter const& that) : m_formatters(that.m_formatters) {} - named_scope_formatter(BOOST_RV_REF(named_scope_formatter) that) { m_formatters.swap(that.m_formatters); } + named_scope_formatter(BOOST_RV_REF(named_scope_formatter) that) BOOST_NOEXCEPT { m_formatters.swap(that.m_formatters); } - named_scope_formatter& operator= (named_scope_formatter that) + named_scope_formatter& operator= (named_scope_formatter that) BOOST_NOEXCEPT { this->swap(that); return *this; From 8c12f2305edeca6d54dcbfd069cb2def938981f4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 7 May 2020 21:31:23 +0300 Subject: [PATCH 084/309] Added a release note about added noexcept markup. --- doc/changelog.qbk | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index b28abe777d..0c843e6de3 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,6 +15,10 @@ * The [link log.detailed.sink_backends.syslog syslog] sink backend now verifies the IP version of the local and target addresses set by user. The addresses must have the same IP version as was specified in the `ip_version` named parameter on the sink backend construction (by default, IPv4 is assumed). When an address is obtained as a result of host name resolution, only addresses with matching IP version are considered. ([github_issue 119]) +[*New Features:] + +* Move constructors and assignment operators of various components were marked `noexcept`. + [heading 2.18, Boost 1.73] [*New Features:] From 157e45ef0a10c9a9ce77b245ddbe61dce92a16dd Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 8 May 2020 02:44:57 +0300 Subject: [PATCH 085/309] Downgrade UBSAN to clang 9 to work around the bug in Boost.Xpressive. --- .travis.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6bbd97e8b1..0fbeba97b3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -317,35 +317,35 @@ matrix: - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" -# Note: Don't run UBSAN tests in C++20 mode because of Boost.Xpressive bug to be fixed by https://github.com/boostorg/xpressive/pull/13. -# Re-enable C++20 when that bug is fixed. +# Note: UBSAN tests are running on clang-9 because it doesn't flag null pointer advancing, which happens in Boost.Xpressive. +# This bug should be fixed by https://github.com/boostorg/xpressive/pull/13. Update to clang-10 when that bug is fixed. - os: linux dist: xenial compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - - clang-10 + - clang-9 - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-10 - - libc++-10-dev - - libc++abi-10-dev + - clang-9 + - libc++-9-dev + - libc++abi-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X From e675ff11713188ce4e66db8482f72b05bc8f0799 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 10 May 2020 19:15:15 +0300 Subject: [PATCH 086/309] Marked keywords as inline variables. --- doc/Jamfile.v2 | 1 + include/boost/log/expressions/formatters/c_decorator.hpp | 8 ++++---- .../boost/log/expressions/formatters/csv_decorator.hpp | 4 ++-- include/boost/log/expressions/formatters/stream.hpp | 2 +- .../boost/log/expressions/formatters/xml_decorator.hpp | 4 ++-- include/boost/log/expressions/keyword.hpp | 2 +- include/boost/log/expressions/message.hpp | 6 +++--- include/boost/log/expressions/record.hpp | 2 +- include/boost/log/utility/manipulators/auto_newline.hpp | 2 +- 9 files changed, 16 insertions(+), 15 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index c2837a7c86..e6df037795 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -48,6 +48,7 @@ local doxygen_params = BOOST_LOG_NO_VTABLE= \\ BOOST_SYMBOL_VISIBLE= \\ BOOST_FORCEINLINE=inline \\ + BOOST_INLINE_VARIABLE=inline \\ BOOST_STATIC_ASSERT(x)= \\ BOOST_STATIC_ASSERT_MSG(x,y)= \\ BOOST_STATIC_CONSTANT(x,y)=\"static constexpr x y\" \\ diff --git a/include/boost/log/expressions/formatters/c_decorator.hpp b/include/boost/log/expressions/formatters/c_decorator.hpp index ec3f485405..fe96fb20b6 100644 --- a/include/boost/log/expressions/formatters/c_decorator.hpp +++ b/include/boost/log/expressions/formatters/c_decorator.hpp @@ -154,10 +154,10 @@ struct c_decorator_gen * For wide-character formatting there is the similar \c wc_decor decorator generator object. */ #ifdef BOOST_LOG_USE_CHAR -const aux::c_decorator_gen< char > c_decor = {}; +BOOST_INLINE_VARIABLE const aux::c_decorator_gen< char > c_decor = {}; #endif #ifdef BOOST_LOG_USE_WCHAR_T -const aux::c_decorator_gen< wchar_t > wc_decor = {}; +BOOST_INLINE_VARIABLE const aux::c_decorator_gen< wchar_t > wc_decor = {}; #endif /*! @@ -254,10 +254,10 @@ struct c_ascii_decorator_gen * For wide-character formatting there is the similar \c wc_ascii_decor decorator generator object. */ #ifdef BOOST_LOG_USE_CHAR -const aux::c_ascii_decorator_gen< char > c_ascii_decor = {}; +BOOST_INLINE_VARIABLE const aux::c_ascii_decorator_gen< char > c_ascii_decor = {}; #endif #ifdef BOOST_LOG_USE_WCHAR_T -const aux::c_ascii_decorator_gen< wchar_t > wc_ascii_decor = {}; +BOOST_INLINE_VARIABLE const aux::c_ascii_decorator_gen< wchar_t > wc_ascii_decor = {}; #endif /*! diff --git a/include/boost/log/expressions/formatters/csv_decorator.hpp b/include/boost/log/expressions/formatters/csv_decorator.hpp index a4c1c28399..e25a89dc39 100644 --- a/include/boost/log/expressions/formatters/csv_decorator.hpp +++ b/include/boost/log/expressions/formatters/csv_decorator.hpp @@ -114,10 +114,10 @@ struct csv_decorator_gen * For wide-character formatting there is the similar \c wcsv_decor decorator generator object. */ #ifdef BOOST_LOG_USE_CHAR -const aux::csv_decorator_gen< char > csv_decor = {}; +BOOST_INLINE_VARIABLE const aux::csv_decorator_gen< char > csv_decor = {}; #endif #ifdef BOOST_LOG_USE_WCHAR_T -const aux::csv_decorator_gen< wchar_t > wcsv_decor = {}; +BOOST_INLINE_VARIABLE const aux::csv_decorator_gen< wchar_t > wcsv_decor = {}; #endif /*! diff --git a/include/boost/log/expressions/formatters/stream.hpp b/include/boost/log/expressions/formatters/stream.hpp index 638ccbd2c8..ef1f747d16 100644 --- a/include/boost/log/expressions/formatters/stream.hpp +++ b/include/boost/log/expressions/formatters/stream.hpp @@ -37,7 +37,7 @@ typedef phoenix::expression::argument< 2 >::type stream_type; /*! * Stream placeholder in formatter template expressions. */ -const stream_type stream = {}; +BOOST_INLINE_VARIABLE const stream_type stream = {}; } // namespace expressions diff --git a/include/boost/log/expressions/formatters/xml_decorator.hpp b/include/boost/log/expressions/formatters/xml_decorator.hpp index ca93a7d58a..02b0fc1d12 100644 --- a/include/boost/log/expressions/formatters/xml_decorator.hpp +++ b/include/boost/log/expressions/formatters/xml_decorator.hpp @@ -112,10 +112,10 @@ struct xml_decorator_gen * For wide-character formatting there is the similar \c wxml_decor decorator generator object. */ #ifdef BOOST_LOG_USE_CHAR -const aux::xml_decorator_gen< char > xml_decor = {}; +BOOST_INLINE_VARIABLE const aux::xml_decorator_gen< char > xml_decor = {}; #endif #ifdef BOOST_LOG_USE_WCHAR_T -const aux::xml_decorator_gen< wchar_t > wxml_decor = {}; +BOOST_INLINE_VARIABLE const aux::xml_decorator_gen< wchar_t > wxml_decor = {}; #endif /*! diff --git a/include/boost/log/expressions/keyword.hpp b/include/boost/log/expressions/keyword.hpp index 47f0121539..7a8223ec76 100644 --- a/include/boost/log/expressions/keyword.hpp +++ b/include/boost/log/expressions/keyword.hpp @@ -200,7 +200,7 @@ struct protoify< boost::reference_wrapper< const boost::log::expressions::attrib #define BOOST_LOG_ATTRIBUTE_KEYWORD_IMPL(keyword_, name_, value_type_, tag_ns_)\ BOOST_LOG_ATTRIBUTE_KEYWORD_TYPE_IMPL(keyword_, name_, value_type_, tag_ns_)\ - const BOOST_PP_CAT(keyword_, _type) keyword_ = {}; + BOOST_INLINE_VARIABLE const BOOST_PP_CAT(keyword_, _type) keyword_ = {}; #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/expressions/message.hpp b/include/boost/log/expressions/message.hpp index e68aa37949..394ad793c6 100644 --- a/include/boost/log/expressions/message.hpp +++ b/include/boost/log/expressions/message.hpp @@ -95,7 +95,7 @@ typedef attribute_keyword< tag::message > message_type; /*! * Generic message keyword. */ -const message_type message = {}; +BOOST_INLINE_VARIABLE const message_type message = {}; #if defined(BOOST_LOG_USE_CHAR) /*! @@ -105,7 +105,7 @@ typedef attribute_keyword< tag::smessage > smessage_type; /*! * Narrow message keyword. */ -const smessage_type smessage = {}; +BOOST_INLINE_VARIABLE const smessage_type smessage = {}; #endif #if defined(BOOST_LOG_USE_WCHAR_T) @@ -116,7 +116,7 @@ typedef attribute_keyword< tag::wmessage > wmessage_type; /*! * Wide message keyword. */ -const wmessage_type wmessage = {}; +BOOST_INLINE_VARIABLE const wmessage_type wmessage = {}; #endif } // namespace expressions diff --git a/include/boost/log/expressions/record.hpp b/include/boost/log/expressions/record.hpp index cfcf62b266..e7f360fe0a 100644 --- a/include/boost/log/expressions/record.hpp +++ b/include/boost/log/expressions/record.hpp @@ -37,7 +37,7 @@ typedef phoenix::expression::argument< 1 >::type record_type; /*! * Log record placeholder in formatter template expressions. */ -const record_type record = {}; +BOOST_INLINE_VARIABLE const record_type record = {}; } // namespace expressions diff --git a/include/boost/log/utility/manipulators/auto_newline.hpp b/include/boost/log/utility/manipulators/auto_newline.hpp index 933a670de5..d973b92256 100644 --- a/include/boost/log/utility/manipulators/auto_newline.hpp +++ b/include/boost/log/utility/manipulators/auto_newline.hpp @@ -32,7 +32,7 @@ BOOST_LOG_OPEN_NAMESPACE * inserted into the stream is already a newline. */ struct auto_newline_manip {} -const auto_newline = {}; +BOOST_INLINE_VARIABLE const auto_newline = {}; /*! * Stream output operator for the \c auto_newline manipulator From d4db5c3937de644fc0ff5f9a81af1db1c787935a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 10 May 2020 23:33:02 +0300 Subject: [PATCH 087/309] Upgraded UBSAN to clang 10. https://github.com/boostorg/xpressive/pull/13 has been merged, which means Boost.Xpressive issue should be fixed. --- .travis.yml | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 0fbeba97b3..71b5d203ba 100644 --- a/.travis.yml +++ b/.travis.yml @@ -317,35 +317,33 @@ matrix: - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" -# Note: UBSAN tests are running on clang-9 because it doesn't flag null pointer advancing, which happens in Boost.Xpressive. -# This bug should be fixed by https://github.com/boostorg/xpressive/pull/13. Update to clang-10 when that bug is fixed. - os: linux dist: xenial compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 addons: apt: packages: - - clang-9 + - clang-10 - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux dist: xenial compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" + env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: apt: packages: - - clang-9 - - libc++-9-dev - - libc++abi-9-dev + - clang-10 + - libc++-10-dev + - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X From 15f5f4ed58e0ff2a5dae5d2da879287acc32b4af Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 11 May 2020 22:25:06 +0300 Subject: [PATCH 088/309] Added range_manip output manipulator for formatting ranges. --- doc/changelog.qbk | 1 + doc/log.qbk | 1 + doc/utilities.qbk | 16 ++ .../boost/log/utility/manipulators/range.hpp | 187 ++++++++++++++++++ test/run/util_manip_range.cpp | 158 +++++++++++++++ 5 files changed, 363 insertions(+) create mode 100644 include/boost/log/utility/manipulators/range.hpp create mode 100644 test/run/util_manip_range.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 0c843e6de3..b0eba5e205 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -18,6 +18,7 @@ [*New Features:] * Move constructors and assignment operators of various components were marked `noexcept`. +* Added a new [link log.detailed.utilities.manipulators.range `range_manip`] stream manipulator that can be used for outputting elements of a range, optionally separated by a delimiter. [heading 2.18, Boost 1.73] diff --git a/doc/log.qbk b/doc/log.qbk index a4083b801f..1521d9065f 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -38,6 +38,7 @@ [def __boost_optional__ [@http://www.boost.org/doc/libs/release/libs/optional/index.html Boost.Optional]] [def __boost_variant__ [@http://www.boost.org/doc/libs/release/doc/html/variant.html Boost.Variant]] [def __boost_intrusive__ [@http://www.boost.org/doc/libs/release/doc/html/intrusive.html Boost.Intrusive]] +[def __boost_range__ [@http://www.boost.org/doc/libs/release/libs/range/index.html Boost.Range]] [def __boost_iostreams__ [@http://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html Boost.IOStreams]] [def __boost_mpl__ [@http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html Boost.MPL]] [def __boost_exception__ [@http://www.boost.org/doc/libs/release/libs/exception/doc/boost-exception.html Boost.Exception]] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index 0f92aa35dc..be14541bee 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -262,6 +262,22 @@ Sometimes it can be useful to be able to insert a newline character in the outpu [endsect] +[section:range Range manipulator] + + #include <``[boost_log_utility_manipulators_range_hpp]``> + +It can be useful to be able to output elements of a container (or, more generally, a range), preferably separated with a delimiter. The `range_manip` manipulator allows to do this: + + std::vector< int > ints{ 1, 2, 3 }; + + BOOST_LOG(lg) << "Integers: { " << logging::range_manip(ints, ", ") << " }"; // Outputs: "Integers: { 1, 2, 3 }" + +[tip This manipulator can also be used with regular output streams, not necessarily loggers.] + +Here, `range_manip` accepts two arguments - the range of elements, and, optionally, a delimiter. The range can be any type supported by __boost_range__ `begin()` and `end()` free functions, which includes any standard containers and arrays. Elements of the range must support stream insertion operator. The delimiter argument, if specified, is inserted into stream between elements. The delimiter can be any type that supports stream insertion. If delimiter is not specified, the elements are output into the stream without separation. + +[endsect] + [endsect] [section:ipc Interprocess communication tools] diff --git a/include/boost/log/utility/manipulators/range.hpp b/include/boost/log/utility/manipulators/range.hpp new file mode 100644 index 0000000000..2dcd57b49e --- /dev/null +++ b/include/boost/log/utility/manipulators/range.hpp @@ -0,0 +1,187 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/manipulators/range.hpp + * \author Andrey Semashev + * \date 11.05.2020 + * + * The header contains implementation of a stream manipulator for inserting a range of elements, optionally separated with a delimiter. + */ + +#ifndef BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * Stream manipulator for inserting a range of elements, optionally separated with a delimiter. + */ +template< typename RangeT, typename DelimiterT > +class range_manipulator +{ +private: + typedef typename conditional< + is_scalar< DelimiterT >::value, + DelimiterT, + DelimiterT const& + >::type stored_delimiter_type; + +private: + RangeT const& m_range; + stored_delimiter_type m_delimiter; + +public: + //! Initializing constructor + range_manipulator(RangeT const& range, stored_delimiter_type delimiter) BOOST_NOEXCEPT : + m_range(range), + m_delimiter(delimiter) + { + } + + //! The method outputs elements of the range separated with delimiter + template< typename StreamT > + void output(StreamT& stream) const + { + typedef typename boost::range_const_iterator< RangeT >::type const_iterator; + const_iterator it = boost::begin(m_range); + const const_iterator end = boost::end(m_range); + if (BOOST_LIKELY(it != end)) + { + stream << *it; + + for (++it; it != end; ++it) + { + stream << m_delimiter; + stream << *it; + } + } + } +}; + +/*! + * Stream manipulator for inserting a range of elements. Specialization for when there is no delimiter. + */ +template< typename RangeT > +class range_manipulator< RangeT, void > +{ +private: + RangeT const& m_range; + +public: + //! Initializing constructor + explicit range_manipulator(RangeT const& range) BOOST_NOEXCEPT : + m_range(range) + { + } + + //! The method outputs elements of the range + template< typename StreamT > + void output(StreamT& stream) const + { + typedef typename boost::range_const_iterator< RangeT >::type const_iterator; + const_iterator it = boost::begin(m_range); + const const_iterator end = boost::end(m_range); + for (; it != end; ++it) + { + stream << *it; + } + } +}; + +/*! + * Stream output operator for \c range_manipulator. Outputs every element of the range, separated with a delimiter, if one was specified on manipulator construction. + */ +template< typename StreamT, typename RangeT, typename DelimiterT > +inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, range_manipulator< RangeT, DelimiterT > const& manip) +{ + if (BOOST_LIKELY(strm.good())) + manip.output(strm); + + return strm; +} + +/*! + * Range manipulator generator function. + * + * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename RangeT, typename DelimiterT > +inline typename boost::enable_if_c< + is_scalar< DelimiterT >::value, + range_manipulator< RangeT, DelimiterT > +>::type range_manip(RangeT const& range, DelimiterT delimiter) BOOST_NOEXCEPT +{ + return range_manipulator< RangeT, DelimiterT >(range, delimiter); +} + +/*! + * Range manipulator generator function. + * + * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename RangeT, typename DelimiterT > +inline typename boost::disable_if_c< + is_scalar< DelimiterT >::value, + range_manipulator< RangeT, DelimiterT > +>::type range_manip(RangeT const& range, DelimiterT const& delimiter) BOOST_NOEXCEPT +{ + return range_manipulator< RangeT, DelimiterT >(range, delimiter); +} + +/*! + * Range manipulator generator function. + * + * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename RangeT, typename DelimiterElementT, std::size_t N > +inline range_manipulator< RangeT, DelimiterElementT* > range_manip(RangeT const& range, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT +{ + return range_manipulator< RangeT, DelimiterElementT* >(range, delimiter); +} + +/*! + * Range manipulator generator function. + * + * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. + * \returns Manipulator to be inserted into the stream. + */ +template< typename RangeT > +inline range_manipulator< RangeT, void > range_manip(RangeT const& range) BOOST_NOEXCEPT +{ + return range_manipulator< RangeT, void >(range); +} + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_MANIPULATORS_RANGE_HPP_INCLUDED_ diff --git a/test/run/util_manip_range.cpp b/test/run/util_manip_range.cpp new file mode 100644 index 0000000000..d07914d60b --- /dev/null +++ b/test/run/util_manip_range.cpp @@ -0,0 +1,158 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_manip_range.cpp + * \author Andrey Semashev + * \date 11.05.2020 + * + * \brief This header contains tests for the range manipulator. + */ + +#define BOOST_TEST_MODULE util_manip_range + +#include +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; + +struct my_int_wrapper +{ + int n; + + my_int_wrapper(int x = 0) BOOST_NOEXCEPT : n(x) {} +}; + +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_int_wrapper miw) +{ + if (BOOST_LIKELY(strm.good())) + strm << '{' << miw.n << '}'; + + return strm; +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(int_no_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + std::vector< int > data; + data.push_back(1); + data.push_back(2); + data.push_back(3); + + ostream_type strm_dump; + strm_dump << logging::range_manip(data); + + ostream_type strm_correct; + strm_correct << "123"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(int_char_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + std::vector< int > data; + data.push_back(1); + data.push_back(2); + data.push_back(3); + + ostream_type strm_dump; + strm_dump << logging::range_manip(data, ' '); + + ostream_type strm_correct; + strm_correct << "1 2 3"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(int_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + std::vector< int > data; + data.push_back(1); + data.push_back(2); + data.push_back(3); + + ostream_type strm_dump; + strm_dump << logging::range_manip(data, ", "); + + ostream_type strm_correct; + strm_correct << "1, 2, 3"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(int_std_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + std::vector< int > data; + data.push_back(1); + data.push_back(2); + data.push_back(3); + + string_type separator; + separator.push_back(','); + separator.push_back(' '); + + ostream_type strm_dump; + strm_dump << logging::range_manip(data, separator); + + ostream_type strm_correct; + strm_correct << "1, 2, 3"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(miw_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + std::list< my_int_wrapper > data; + data.push_back(my_int_wrapper(1)); + data.push_back(my_int_wrapper(2)); + data.push_back(my_int_wrapper(3)); + + ostream_type strm_dump; + strm_dump << logging::range_manip(data, ", "); + + ostream_type strm_correct; + strm_correct << "{1}, {2}, {3}"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(array_int_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + int data[3] = { 1, 2, 3 }; + + ostream_type strm_dump; + strm_dump << logging::range_manip(data, ", "); + + ostream_type strm_correct; + strm_correct << "1, 2, 3"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} From a2cb720ed1e315e478e559ad0bdd17409d014bb8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 12 May 2020 00:20:41 +0300 Subject: [PATCH 089/309] Added tuple_manip output manipulator for formatting heterogeneous sequences. --- doc/changelog.qbk | 1 + doc/log.qbk | 1 + doc/utilities.qbk | 22 ++ .../boost/log/utility/manipulators/tuple.hpp | 220 ++++++++++++++++++ test/run/util_manip_tuple.cpp | 140 +++++++++++ 5 files changed, 384 insertions(+) create mode 100644 include/boost/log/utility/manipulators/tuple.hpp create mode 100644 test/run/util_manip_tuple.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index b0eba5e205..070a4b1e4c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -19,6 +19,7 @@ * Move constructors and assignment operators of various components were marked `noexcept`. * Added a new [link log.detailed.utilities.manipulators.range `range_manip`] stream manipulator that can be used for outputting elements of a range, optionally separated by a delimiter. +* Added a new [link log.detailed.utilities.manipulators.tuple `tuple_manip`] stream manipulator that can be used for outputting elements of a tuple or any other heterogeneous sequence, optionally separated by a delimiter. [heading 2.18, Boost 1.73] diff --git a/doc/log.qbk b/doc/log.qbk index 1521d9065f..4bfbb71995 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -40,6 +40,7 @@ [def __boost_intrusive__ [@http://www.boost.org/doc/libs/release/doc/html/intrusive.html Boost.Intrusive]] [def __boost_range__ [@http://www.boost.org/doc/libs/release/libs/range/index.html Boost.Range]] [def __boost_iostreams__ [@http://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html Boost.IOStreams]] +[def __boost_fusion__ [@http://www.boost.org/doc/libs/release/libs/fusion/index.html Boost.Fusion]] [def __boost_mpl__ [@http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html Boost.MPL]] [def __boost_exception__ [@http://www.boost.org/doc/libs/release/libs/exception/doc/boost-exception.html Boost.Exception]] [def __boost_scope_exit__ [@http://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index be14541bee..5169397733 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -278,6 +278,28 @@ Here, `range_manip` accepts two arguments - the range of elements, and, optional [endsect] +[section:tuple Tuple manipulator] + + #include <``[boost_log_utility_manipulators_tuple_hpp]``> + +Tuple manipulator allows to output elements of a heterogeneous sequence (put simply, a tuple) to a stream, possibly separated with a delimiter. For example: + + #include + + std::tuple< std::string, int, char > address{ "Baker Street", 221, 'b' }; + + BOOST_LOG(lg) << "Address: " << logging::tuple_manip(address, ", "); // Outputs: "Address: Baker Street, 221, b" + +[note In order to support different types of sequences, users may need to `#include` additional support headers from __boost_fusion__, like `boost/fusion/include/std_tuple.hpp` in this example. See __boost_fusion__ documentation.] + +[tip This manipulator can also be used with regular output streams, not necessarily loggers.] + +Here, `tuple_manip` accepts two arguments - the sequence of elements, and, optionally, a delimiter. The heterogeneous sequence can be any sequence supported by __boost_fusion__, for example `std::pair`, `std::tuple`, `boost::tuple`, `boost::fusion::vector` or any structure that has been adapted using one of the `BOOST_FUSION_ADAPT*` macros. Elements of the sequence must support stream insertion operator. The delimiter argument, if specified, is inserted into stream between elements. The delimiter can be any type that supports stream insertion. If delimiter is not specified, the elements are output into the stream without separation. + +[tip You can also use tuples generated by `std::tie` or `boost::tie` with this manipulator, which allows unified formatting of disjoint variables without having to copy them into a structure.] + +[endsect] + [endsect] [section:ipc Interprocess communication tools] diff --git a/include/boost/log/utility/manipulators/tuple.hpp b/include/boost/log/utility/manipulators/tuple.hpp new file mode 100644 index 0000000000..5c03e03bc5 --- /dev/null +++ b/include/boost/log/utility/manipulators/tuple.hpp @@ -0,0 +1,220 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/manipulators/tuple.hpp + * \author Andrey Semashev + * \date 11.05.2020 + * + * The header contains implementation of a stream manipulator for inserting a tuple or any heterogeneous sequence of elements, optionally separated with a delimiter. + */ + +#ifndef BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * Stream manipulator for inserting a heterogeneous sequence of elements, optionally separated with a delimiter. + */ +template< typename TupleT, typename DelimiterT > +class tuple_manipulator +{ +private: + typedef typename conditional< + is_scalar< DelimiterT >::value, + DelimiterT, + DelimiterT const& + >::type stored_delimiter_type; + + template< typename StreamT > + struct output_visitor + { + typedef boost::true_type result_type; + + output_visitor(StreamT& stream, stored_delimiter_type delimiter) BOOST_NOEXCEPT : + m_stream(stream), + m_delimiter(delimiter) + { + } + + template< typename T > + result_type operator() (boost::true_type, T const& elem) const + { + m_stream << m_delimiter; + return operator()(boost::false_type(), elem); + } + + template< typename T > + result_type operator() (boost::false_type, T const& elem) const + { + m_stream << elem; + return result_type(); + } + + private: + StreamT& m_stream; + stored_delimiter_type m_delimiter; + }; + +private: + TupleT const& m_tuple; + stored_delimiter_type m_delimiter; + +public: + //! Initializing constructor + tuple_manipulator(TupleT const& tuple, stored_delimiter_type delimiter) BOOST_NOEXCEPT : + m_tuple(tuple), + m_delimiter(delimiter) + { + } + + //! The method outputs elements of the sequence separated with delimiter + template< typename StreamT > + void output(StreamT& stream) const + { + boost::fusion::fold(m_tuple, boost::false_type(), output_visitor< StreamT >(stream, m_delimiter)); + } +}; + +/*! + * Stream manipulator for inserting a heterogeneous sequence of elements. Specialization for when there is no delimiter. + */ +template< typename TupleT > +class tuple_manipulator< TupleT, void > +{ +private: + template< typename StreamT > + struct output_visitor + { + typedef void result_type; + + explicit output_visitor(StreamT& stream) BOOST_NOEXCEPT : + m_stream(stream) + { + } + + template< typename T > + result_type operator() (T const& elem) const + { + m_stream << elem; + } + + private: + StreamT& m_stream; + }; + +private: + TupleT const& m_tuple; + +public: + //! Initializing constructor + explicit tuple_manipulator(TupleT const& tuple) BOOST_NOEXCEPT : + m_tuple(tuple) + { + } + + //! The method outputs elements of the sequence + template< typename StreamT > + void output(StreamT& stream) const + { + boost::fusion::for_each(m_tuple, output_visitor< StreamT >(stream)); + } +}; + +/*! + * Stream output operator for \c tuple_manipulator. Outputs every element of the sequence, separated with a delimiter, if one was specified on manipulator construction. + */ +template< typename StreamT, typename TupleT, typename DelimiterT > +inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, tuple_manipulator< TupleT, DelimiterT > const& manip) +{ + if (BOOST_LIKELY(strm.good())) + manip.output(strm); + + return strm; +} + +/*! + * Tuple manipulator generator function. + * + * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename TupleT, typename DelimiterT > +inline typename boost::enable_if_c< + is_scalar< DelimiterT >::value, + tuple_manipulator< TupleT, DelimiterT > +>::type tuple_manip(TupleT const& tuple, DelimiterT delimiter) BOOST_NOEXCEPT +{ + return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter); +} + +/*! + * Tuple manipulator generator function. + * + * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename TupleT, typename DelimiterT > +inline typename boost::disable_if_c< + is_scalar< DelimiterT >::value, + tuple_manipulator< TupleT, DelimiterT > +>::type tuple_manip(TupleT const& tuple, DelimiterT const& delimiter) BOOST_NOEXCEPT +{ + return tuple_manipulator< TupleT, DelimiterT >(tuple, delimiter); +} + +/*! + * Tuple manipulator generator function. + * + * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. + * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. + * \returns Manipulator to be inserted into the stream. + */ +template< typename TupleT, typename DelimiterElementT, std::size_t N > +inline tuple_manipulator< TupleT, DelimiterElementT* > tuple_manip(TupleT const& tuple, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT +{ + return tuple_manipulator< TupleT, DelimiterElementT* >(tuple, delimiter); +} + +/*! + * Tuple manipulator generator function. + * + * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. + * \returns Manipulator to be inserted into the stream. + */ +template< typename TupleT > +inline tuple_manipulator< TupleT, void > tuple_manip(TupleT const& tuple) BOOST_NOEXCEPT +{ + return tuple_manipulator< TupleT, void >(tuple); +} + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_MANIPULATORS_TUPLE_HPP_INCLUDED_ diff --git a/test/run/util_manip_tuple.cpp b/test/run/util_manip_tuple.cpp new file mode 100644 index 0000000000..d30b71fbf9 --- /dev/null +++ b/test/run/util_manip_tuple.cpp @@ -0,0 +1,140 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_manip_tuple.cpp + * \author Andrey Semashev + * \date 11.05.2020 + * + * \brief This header contains tests for the tuple manipulator. + */ + +#define BOOST_TEST_MODULE util_manip_tuple + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; + +struct my_int_wrapper +{ + int n; + + my_int_wrapper(int x = 0) BOOST_NOEXCEPT : n(x) {} +}; + +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_int_wrapper miw) +{ + if (BOOST_LIKELY(strm.good())) + strm << '{' << miw.n << '}'; + + return strm; +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(pair_no_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef test_data< char_type > test_data_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + std::pair< int, string_type > data(1, test_data_type::abc()); + + ostream_type strm_dump; + strm_dump << logging::tuple_manip(data); + + ostream_type strm_correct; + strm_correct << "1abc"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(tuple_char_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef test_data< char_type > test_data_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + boost::tuple< int, my_int_wrapper, string_type > data(1, my_int_wrapper(5), string_type(test_data_type::abc())); + + ostream_type strm_dump; + strm_dump << logging::tuple_manip(data, ' '); + + ostream_type strm_correct; + strm_correct << "1 {5} abc"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(tuple_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef test_data< char_type > test_data_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + boost::tuple< int, my_int_wrapper, string_type > data(1, my_int_wrapper(5), string_type(test_data_type::abc())); + + ostream_type strm_dump; + strm_dump << logging::tuple_manip(data, ", "); + + ostream_type strm_correct; + strm_correct << "1, {5}, abc"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(tuple_std_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef test_data< char_type > test_data_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + boost::tuple< int, my_int_wrapper, string_type > data(1, my_int_wrapper(5), string_type(test_data_type::abc())); + + string_type separator; + separator.push_back(','); + separator.push_back(' '); + + ostream_type strm_dump; + strm_dump << logging::tuple_manip(data, separator); + + ostream_type strm_correct; + strm_correct << "1, {5}, abc"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(tie_string_separator, CharT, char_types) +{ + typedef CharT char_type; + typedef test_data< char_type > test_data_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + int x = 1; + my_int_wrapper y(5); + string_type z(test_data_type::abc()); + + ostream_type strm_dump; + strm_dump << logging::tuple_manip(boost::tie(x, y, z), ", "); + + ostream_type strm_correct; + strm_correct << "1, {5}, abc"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} From 65037a0c2f6e902fc467006155ac83a7c1c07a20 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 12 May 2020 01:32:24 +0300 Subject: [PATCH 090/309] Added optional_manip output manipulator for formatting optional values. --- doc/changelog.qbk | 1 + doc/utilities.qbk | 25 ++ .../log/utility/manipulators/optional.hpp | 253 ++++++++++++++++++ test/run/util_manip_optional.cpp | 179 +++++++++++++ 4 files changed, 458 insertions(+) create mode 100644 include/boost/log/utility/manipulators/optional.hpp create mode 100644 test/run/util_manip_optional.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 070a4b1e4c..eebceff033 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -20,6 +20,7 @@ * Move constructors and assignment operators of various components were marked `noexcept`. * Added a new [link log.detailed.utilities.manipulators.range `range_manip`] stream manipulator that can be used for outputting elements of a range, optionally separated by a delimiter. * Added a new [link log.detailed.utilities.manipulators.tuple `tuple_manip`] stream manipulator that can be used for outputting elements of a tuple or any other heterogeneous sequence, optionally separated by a delimiter. +* Added a new [link log.detailed.utilities.manipulators.optional `optional_manip`] stream manipulator that can be used for outputting optionally present values. [heading 2.18, Boost 1.73] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index 5169397733..016f56b779 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -300,6 +300,31 @@ Here, `tuple_manip` accepts two arguments - the sequence of elements, and, optio [endsect] +[section:optional Optional manipulator] + + #include <``[boost_log_utility_manipulators_optional_hpp]``> + +Optional manipulator allows to output an optional value to the output stream. If the value is not present, the manipulator allows to specify a "none" marker to output instead. For example: + + boost::optional< int > param1; + boost::optional< int > param2 = 10; + + BOOST_LOG(lg) << "param1: " << logging::optional_manip(param1, "[none]") << ", param2: " << logging::optional_manip(param2, "[none]"); // Outputs: "param1: [none], param2: 10" + +[tip This manipulator can also be used with regular output streams, not necessarily loggers.] + +Here, `optional_manip` accepts two arguments - the optional value, and, optionally, a "none" marker. The optional value can be any type that supports the following: + +* Contextually convertible to `bool`, where `true` indicates that the value is present. +* Can be dereferenced using `operator*()`, and the result of this operator is the value. +* The result of dereferencing must support stream insertion operator. + +Examples of types that fit these requirements are `boost::optional` (see __boost_optional__), `std::optional` and pointers to objects. + +The "none" marker argument, if specified, is inserted into stream in case if the optional value is not present (i.e. the contextual conversion to `bool` yields `false`). The marker can be any type that supports stream insertion. If the marker is not specified, no output is produced if the value is not present. + +[endsect] + [endsect] [section:ipc Interprocess communication tools] diff --git a/include/boost/log/utility/manipulators/optional.hpp b/include/boost/log/utility/manipulators/optional.hpp new file mode 100644 index 0000000000..aef5c29c6d --- /dev/null +++ b/include/boost/log/utility/manipulators/optional.hpp @@ -0,0 +1,253 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/manipulators/optional.hpp + * \author Andrey Semashev + * \date 12.05.2020 + * + * The header contains implementation of a stream manipulator for inserting an optional value. + */ + +#ifndef BOOST_LOG_UTILITY_MANIPULATORS_OPTIONAL_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_MANIPULATORS_OPTIONAL_HPP_INCLUDED_ + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * Stream manipulator for inserting an optional value. + */ +template< typename OptionalT, typename NoneT > +class optional_manipulator +{ +private: + typedef typename conditional< + is_scalar< OptionalT >::value, + OptionalT, + OptionalT const& + >::type stored_optional_type; + + typedef typename conditional< + is_scalar< NoneT >::value, + NoneT, + NoneT const& + >::type stored_none_type; + +private: + stored_optional_type m_optional; + stored_none_type m_none; + +public: + //! Initializing constructor + optional_manipulator(stored_optional_type opt, stored_none_type none) BOOST_NOEXCEPT : + m_optional(opt), + m_none(none) + { + } + + //! The method outputs the value, if it is present, otherwise outputs the "none" marker + template< typename StreamT > + void output(StreamT& stream) const + { + if (!!m_optional) + stream << *m_optional; + else + stream << m_none; + } +}; + +/*! + * Stream manipulator for inserting an optional value. Specialization for no "none" marker. + */ +template< typename OptionalT > +class optional_manipulator< OptionalT, void > +{ +private: + typedef typename conditional< + is_scalar< OptionalT >::value, + OptionalT, + OptionalT const& + >::type stored_optional_type; + +private: + stored_optional_type m_optional; + +public: + //! Initializing constructor + optional_manipulator(stored_optional_type opt) BOOST_NOEXCEPT : + m_optional(opt) + { + } + + //! The method outputs the value, if it is present + template< typename StreamT > + void output(StreamT& stream) const + { + if (!!m_optional) + stream << *m_optional; + } +}; + +/*! + * Stream output operator for \c optional_manipulator. Outputs the optional value or the "none" marker, if one was specified on manipulator construction. + */ +template< typename StreamT, typename OptionalT, typename NoneT > +inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, optional_manipulator< OptionalT, NoneT > const& manip) +{ + if (BOOST_LIKELY(strm.good())) + manip.output(strm); + + return strm; +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneT > +inline typename boost::enable_if_c< + is_scalar< OptionalT >::value && is_scalar< NoneT >::value, + optional_manipulator< OptionalT, NoneT > +>::type optional_manip(OptionalT opt, NoneT none) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneT >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneT > +inline typename boost::enable_if_c< + is_scalar< OptionalT >::value && !is_scalar< NoneT >::value, + optional_manipulator< OptionalT, NoneT > +>::type optional_manip(OptionalT opt, NoneT const& none) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneT >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneElementT, std::size_t N > +inline typename boost::enable_if_c< + is_scalar< OptionalT >::value, + optional_manipulator< OptionalT, NoneElementT* > +>::type optional_manip(OptionalT opt, NoneElementT (&none)[N]) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneElementT* >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneT > +inline typename boost::enable_if_c< + !is_scalar< OptionalT >::value && !is_array< OptionalT >::value && is_scalar< NoneT >::value, + optional_manipulator< OptionalT, NoneT > +>::type optional_manip(OptionalT const& opt, NoneT none) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneT >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneT > +inline typename boost::enable_if_c< + !is_scalar< OptionalT >::value && !is_array< OptionalT >::value && !is_scalar< NoneT >::value, + optional_manipulator< OptionalT, NoneT > +>::type optional_manip(OptionalT const& opt, NoneT const& none) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneT >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT, typename NoneElementT, std::size_t N > +inline typename boost::enable_if_c< + !is_scalar< OptionalT >::value && !is_array< OptionalT >::value, + optional_manipulator< OptionalT, NoneElementT* > +>::type optional_manip(OptionalT const& opt, NoneElementT (&none)[N]) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, NoneElementT* >(opt, none); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT > +inline typename boost::enable_if_c< + is_scalar< OptionalT >::value, + optional_manipulator< OptionalT, void > +>::type optional_manip(OptionalT opt) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, void >(opt); +} + +/*! + * Optional manipulator generator function. + * + * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. + * \returns Manipulator to be inserted into the stream. + */ +template< typename OptionalT > +inline typename boost::enable_if_c< + !is_scalar< OptionalT >::value && !is_array< OptionalT >::value, + optional_manipulator< OptionalT, void > +>::type optional_manip(OptionalT const& opt) BOOST_NOEXCEPT +{ + return optional_manipulator< OptionalT, void >(opt); +} + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_MANIPULATORS_OPTIONAL_HPP_INCLUDED_ diff --git a/test/run/util_manip_optional.cpp b/test/run/util_manip_optional.cpp new file mode 100644 index 0000000000..226da29f23 --- /dev/null +++ b/test/run/util_manip_optional.cpp @@ -0,0 +1,179 @@ +/* + * Copyright Andrey Semashev 2020. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_manip_optional.cpp + * \author Andrey Semashev + * \date 12.05.2020 + * + * \brief This header contains tests for the optional manipulator. + */ + +#define BOOST_TEST_MODULE util_manip_optional + +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; + +struct my_int_wrapper +{ + int n; + + my_int_wrapper(int x = 0) BOOST_NOEXCEPT : n(x) {} +}; + +template< typename CharT, typename TraitsT > +inline std::basic_ostream< CharT, TraitsT >& operator<< (std::basic_ostream< CharT, TraitsT >& strm, my_int_wrapper miw) +{ + if (BOOST_LIKELY(strm.good())) + strm << '{' << miw.n << '}'; + + return strm; +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(opt_none_no_marker, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + boost::optional< int > data; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data); + + BOOST_CHECK(equal_strings(strm_dump.str(), string_type())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(opt_none_with_marker_char, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + boost::optional< int > data; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, '-'); + + ostream_type strm_correct; + strm_correct << "-"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(opt_none_with_marker_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + boost::optional< int > data; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, "[none]"); + + ostream_type strm_correct; + strm_correct << "[none]"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(opt_none_with_marker_std_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + typedef std::basic_string< char_type > string_type; + + boost::optional< int > data; + + string_type marker; + marker.push_back('['); + marker.push_back('n'); + marker.push_back('o'); + marker.push_back('n'); + marker.push_back('e'); + marker.push_back(']'); + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, marker); + + ostream_type strm_correct; + strm_correct << "[none]"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(ptr_none_with_marker_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + const int* data = 0; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, "[none]"); + + ostream_type strm_correct; + strm_correct << "[none]"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(opt_int_with_marker_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + boost::optional< int > data; + data = 7; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, "[none]"); + + ostream_type strm_correct; + strm_correct << "7"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(ptr_int_with_marker_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + int n = 7; + int* data = &n; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, "[none]"); + + ostream_type strm_correct; + strm_correct << "7"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(ptr_miw_with_marker_string, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + my_int_wrapper n(7); + const my_int_wrapper* data = &n; + + ostream_type strm_dump; + strm_dump << logging::optional_manip(data, "[none]"); + + ostream_type strm_correct; + strm_correct << "{7}"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} From 00b051011cd541625847155cb50a2b2661af250d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 12 May 2020 11:25:55 +0300 Subject: [PATCH 091/309] Removed unnecessary check for stream being good. The stream will be checked in the operator<< of the value anyway, and we don't save much performance by checking the stream before invoking optional_manipulator::output. --- include/boost/log/utility/manipulators/optional.hpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/boost/log/utility/manipulators/optional.hpp b/include/boost/log/utility/manipulators/optional.hpp index aef5c29c6d..a063bc5039 100644 --- a/include/boost/log/utility/manipulators/optional.hpp +++ b/include/boost/log/utility/manipulators/optional.hpp @@ -112,9 +112,7 @@ class optional_manipulator< OptionalT, void > template< typename StreamT, typename OptionalT, typename NoneT > inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& strm, optional_manipulator< OptionalT, NoneT > const& manip) { - if (BOOST_LIKELY(strm.good())) - manip.output(strm); - + manip.output(strm); return strm; } From 76baf3fd3e58b9930e183ff0ca15952a480bd6ca Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 13 May 2020 19:53:32 +0300 Subject: [PATCH 092/309] Added notes about lifetime of objects used with manipulators. --- .../boost/log/utility/manipulators/optional.hpp | 16 ++++++++++++++++ include/boost/log/utility/manipulators/range.hpp | 8 ++++++++ include/boost/log/utility/manipulators/tuple.hpp | 8 ++++++++ 3 files changed, 32 insertions(+) diff --git a/include/boost/log/utility/manipulators/optional.hpp b/include/boost/log/utility/manipulators/optional.hpp index a063bc5039..0f1056b5ef 100644 --- a/include/boost/log/utility/manipulators/optional.hpp +++ b/include/boost/log/utility/manipulators/optional.hpp @@ -122,6 +122,8 @@ inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, Stre * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneT > inline typename boost::enable_if_c< @@ -138,6 +140,8 @@ inline typename boost::enable_if_c< * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneT > inline typename boost::enable_if_c< @@ -154,6 +158,8 @@ inline typename boost::enable_if_c< * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneElementT, std::size_t N > inline typename boost::enable_if_c< @@ -170,6 +176,8 @@ inline typename boost::enable_if_c< * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneT > inline typename boost::enable_if_c< @@ -186,6 +194,8 @@ inline typename boost::enable_if_c< * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneT > inline typename boost::enable_if_c< @@ -202,6 +212,8 @@ inline typename boost::enable_if_c< * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \param none Marker used to indicate when the value is not present. Optional. If not specified, nothing is output if the value is not present. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a opt and \a none objects must outlive the created manipulator object. */ template< typename OptionalT, typename NoneElementT, std::size_t N > inline typename boost::enable_if_c< @@ -217,6 +229,8 @@ inline typename boost::enable_if_c< * * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \returns Manipulator to be inserted into the stream. + * + * \note \a opt object must outlive the created manipulator object. */ template< typename OptionalT > inline typename boost::enable_if_c< @@ -232,6 +246,8 @@ inline typename boost::enable_if_c< * * \param opt Optional value to output. The optional value must support contextual conversion to \c bool and dereferencing, and its dereferencing result must support stream output. * \returns Manipulator to be inserted into the stream. + * + * \note \a opt object must outlive the created manipulator object. */ template< typename OptionalT > inline typename boost::enable_if_c< diff --git a/include/boost/log/utility/manipulators/range.hpp b/include/boost/log/utility/manipulators/range.hpp index 2dcd57b49e..0c5fb8c920 100644 --- a/include/boost/log/utility/manipulators/range.hpp +++ b/include/boost/log/utility/manipulators/range.hpp @@ -127,6 +127,8 @@ inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, Stre * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a range and \a delimiter objects must outlive the created manipulator object. */ template< typename RangeT, typename DelimiterT > inline typename boost::enable_if_c< @@ -143,6 +145,8 @@ inline typename boost::enable_if_c< * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a range and \a delimiter objects must outlive the created manipulator object. */ template< typename RangeT, typename DelimiterT > inline typename boost::disable_if_c< @@ -159,6 +163,8 @@ inline typename boost::disable_if_c< * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a range and \a delimiter objects must outlive the created manipulator object. */ template< typename RangeT, typename DelimiterElementT, std::size_t N > inline range_manipulator< RangeT, DelimiterElementT* > range_manip(RangeT const& range, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT @@ -171,6 +177,8 @@ inline range_manipulator< RangeT, DelimiterElementT* > range_manip(RangeT const& * * \param range Range of elements to output. The range must support begin and end iterators, and its elements must support stream output. * \returns Manipulator to be inserted into the stream. + * + * \note \a delimiter object must outlive the created manipulator object. */ template< typename RangeT > inline range_manipulator< RangeT, void > range_manip(RangeT const& range) BOOST_NOEXCEPT diff --git a/include/boost/log/utility/manipulators/tuple.hpp b/include/boost/log/utility/manipulators/tuple.hpp index 5c03e03bc5..a2bc0c2b59 100644 --- a/include/boost/log/utility/manipulators/tuple.hpp +++ b/include/boost/log/utility/manipulators/tuple.hpp @@ -160,6 +160,8 @@ inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, Stre * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object. */ template< typename TupleT, typename DelimiterT > inline typename boost::enable_if_c< @@ -176,6 +178,8 @@ inline typename boost::enable_if_c< * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object. */ template< typename TupleT, typename DelimiterT > inline typename boost::disable_if_c< @@ -192,6 +196,8 @@ inline typename boost::disable_if_c< * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. * \param delimiter Delimiter to separate elements in the output. Optional. If not specified, elements are output without separation. * \returns Manipulator to be inserted into the stream. + * + * \note Both \a tuple and \a delimiter objects must outlive the created manipulator object. */ template< typename TupleT, typename DelimiterElementT, std::size_t N > inline tuple_manipulator< TupleT, DelimiterElementT* > tuple_manip(TupleT const& tuple, DelimiterElementT (&delimiter)[N]) BOOST_NOEXCEPT @@ -204,6 +210,8 @@ inline tuple_manipulator< TupleT, DelimiterElementT* > tuple_manip(TupleT const& * * \param tuple Heterogeneous sequence of elements to output. The sequence must be supported by Boost.Fusion, and its elements must support stream output. * \returns Manipulator to be inserted into the stream. + * + * \note \a tuple object must outlive the created manipulator object. */ template< typename TupleT > inline tuple_manipulator< TupleT, void > tuple_manip(TupleT const& tuple) BOOST_NOEXCEPT From 2e93f7d86e068169a9bc18b596a9e06a58571ffd Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 22 May 2020 18:25:47 +0300 Subject: [PATCH 093/309] Added gcc 10 build jobs to Travis CI. --- .travis.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 71b5d203ba..ad7580c678 100644 --- a/.travis.yml +++ b/.travis.yml @@ -122,14 +122,25 @@ matrix: sources: - sourceline: "ppa:ubuntu-toolchain-r/test" + - os: linux + dist: bionic + compiler: gcc-10 + env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 + addons: + apt: + packages: + - g++-10 + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + - os: linux dist: bionic compiler: gcc-UBSAN - env: UBSAN=1 TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17,2a UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold + env: UBSAN=1 TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: apt: packages: - - g++-9 + - g++-10 sources: - sourceline: "ppa:ubuntu-toolchain-r/test" From 477c7663846018f034564385aeb7167c071c3f31 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Jun 2020 00:51:32 +0300 Subject: [PATCH 094/309] Added a FreeBSD job in Travis CI. --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index ad7580c678..95520461d8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -367,6 +367,9 @@ matrix: # env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z # osx_image: xcode10.1 +# clang, FreeBSD + - os: freebsd + env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,17 install: - GIT_FETCH_JOBS=8 From 2b28f477c5b5958aa5be5d8fa600dc74badb3de1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Jun 2020 19:06:33 +0300 Subject: [PATCH 095/309] Disable gcc warnings about ignoring attributes on _SECURITY_ATTRIBUTES. --- include/boost/log/utility/permissions.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/boost/log/utility/permissions.hpp b/include/boost/log/utility/permissions.hpp index 8562f7fe73..d28a9e0897 100644 --- a/include/boost/log/utility/permissions.hpp +++ b/include/boost/log/utility/permissions.hpp @@ -33,9 +33,17 @@ struct _SECURITY_ATTRIBUTES; namespace boost { #ifdef BOOST_WINDOWS +#if defined(BOOST_GCC) && BOOST_GCC >= 40600 +#pragma GCC diagnostic push +// type attributes ignored after type is already defined +#pragma GCC diagnostic ignored "-Wattributes" +#endif namespace winapi { struct BOOST_LOG_MAY_ALIAS _SECURITY_ATTRIBUTES; } +#if defined(BOOST_GCC) && BOOST_GCC >= 40600 +#pragma GCC diagnostic pop +#endif #endif namespace interprocess { From 027c33406337463e737f45084fe0c59dab7eb7d8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 8 Jun 2020 01:06:59 +0300 Subject: [PATCH 096/309] Marked system library targets explicit. --- build/Jamfile.v2 | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 36446d1bde..ea614b94f3 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -1,5 +1,5 @@ # -# Copyright Andrey Semashev 2007 - 2016. +# Copyright Andrey Semashev 2007 - 2020. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) @@ -32,12 +32,14 @@ lib advapi32 ; lib secur32 ; lib ws2_32 ; lib mswsock ; +explicit psapi advapi32 secur32 ws2_32 mswsock ; # UNIX libs lib rt ; lib socket ; lib nsl ; lib ipv6 ; +explicit rt socket nsl ipv6 ; rule has-config-flag ( flag : properties * ) { @@ -71,7 +73,7 @@ rule check-instruction-set ( properties * ) rule select-regex-backend ( properties * ) { - local result = ; + local result ; # Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching. if ! ( @@ -88,7 +90,7 @@ rule select-regex-backend ( properties * ) rule check-pthread-mutex-robust ( properties * ) { - local result = ; + local result ; local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : pthread-supports-robust-mutexes ] ; if $(has_pthread_mutex_robust) @@ -101,7 +103,7 @@ rule check-pthread-mutex-robust ( properties * ) rule check-atomic-int32 ( properties * ) { - local result = ; + local result ; local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : native-atomic-int32-supported ] ; if ! $(has_atomic_int32) @@ -114,7 +116,7 @@ rule check-atomic-int32 ( properties * ) rule check-native-syslog ( properties * ) { - local result = ; + local result ; if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] { From e7d4fd2d13f753cee86ac2ffd82259ab460e1237 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 1 Aug 2020 21:59:33 +0300 Subject: [PATCH 097/309] Include config.hpp before checking BOOST_LOG_WITHOUT_SYSLOG. Boost.Log's config.hpp may define BOOST_LOG_WITHOUT_SYSLOG if no native syslog API or Boost.ASIO is available, so we need to include the header before checking the macro. Closes https://github.com/boostorg/log/pull/123. --- src/syslog_backend.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 9ce19f4a99..b39838d58b 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -13,9 +13,10 @@ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. */ +#include + #ifndef BOOST_LOG_WITHOUT_SYSLOG -#include #include #include #include From dd5a8f1b419e71b8c1514847ad81d8ffa08f3fd8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 20 Aug 2020 19:57:21 +0300 Subject: [PATCH 098/309] Fixed file counter in the target filename generated by text file backend. The file counter gets incremented when a new file is opened. Since the target filename was generated later, on file rotation, the target filename got the next value of the counter. This caused some values of the counter being skipped when the application restarts and scans for the previous log files. Fixes https://github.com/boostorg/log/issues/125. --- doc/changelog.qbk | 6 ++++++ src/text_file_backend.cpp | 3 ++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index eebceff033..ddb45bda70 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.20, Boost 1.75] + +[*Bug fixes:] + +* Corrected the file counter that would be used in [link log.detailed.sink_backends.text_file `text_file_backend`] when generating the target file name (based on the pattern set by `set_target_file_name_pattern` method) when the log file is rotated. The backend used to use the next value of file counter, which could cause some counter values to be skipped on application restarts. ([github_issue 125]) + [heading 2.19, Boost 1.74] [*Bug fixes:] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index dd60085806..a0688c22f5 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1491,7 +1491,8 @@ BOOST_LOG_API void text_file_backend::rotate_file() { if (!!m_pImpl->m_TargetFileNameGenerator) { - filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); + // File counter was incremented when the file was opened, we have to use the same counter value we used to generate the original filename + filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter - 1u); if (new_file_name != prev_file_name) { From 7344ce3cda965cb4c24edc328bdd50e65b5291e7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 21 Aug 2020 15:19:17 +0300 Subject: [PATCH 099/309] Switch gcc-10 and clang-10 to Ubuntu Focal; clang-9 to Ubuntu Bionic. Also enabled CI for feature branches. --- .travis.yml | 34 +++++++++++++++------------------- appveyor.yml | 1 + 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 95520461d8..d3755692b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,16 +8,11 @@ sudo: false python: "2.7" -os: - - linux - - osx - -dist: bionic - branches: only: - master - develop + - /feature\/.*/ env: matrix: @@ -31,6 +26,7 @@ matrix: include: # gcc, Linux - os: linux + dist: focal compiler: gcc env: TOOLSET=gcc COMPILER=g++ CXXSTD=03,11 EXTRA_TESTS=1 @@ -123,7 +119,7 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux - dist: bionic + dist: focal compiler: gcc-10 env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 addons: @@ -134,7 +130,7 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux - dist: bionic + dist: focal compiler: gcc-UBSAN env: UBSAN=1 TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: @@ -286,7 +282,7 @@ matrix: key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: xenial + dist: bionic compiler: clang-9 env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a addons: @@ -296,11 +292,11 @@ matrix: - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main" + - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: xenial + dist: focal compiler: clang-10 env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 addons: @@ -310,11 +306,11 @@ matrix: - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: xenial + dist: focal compiler: clang-libc++ env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -325,11 +321,11 @@ matrix: - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: xenial + dist: focal compiler: clang-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 addons: @@ -339,11 +335,11 @@ matrix: - libstdc++-9-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - os: linux - dist: xenial + dist: focal compiler: clang-libc++-UBSAN env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" addons: @@ -354,7 +350,7 @@ matrix: - libc++abi-10-dev sources: - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-10 main" + - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" # clang, OS X @@ -369,7 +365,7 @@ matrix: # clang, FreeBSD - os: freebsd - env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,17 + env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,17,2a install: - GIT_FETCH_JOBS=8 diff --git a/appveyor.yml b/appveyor.yml index ee69f21b13..14ae6e810a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -10,6 +10,7 @@ branches: only: - master - develop + - /feature\/.*/ environment: matrix: From f319a186ad2efcace4d102afa1eafd50f196274e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 21 Aug 2020 20:18:08 +0300 Subject: [PATCH 100/309] Reverted gcc-10 to Ubuntu Bionic because of ICE in Boost.Xpressive. --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d3755692b4..305b7d71ab 100644 --- a/.travis.yml +++ b/.travis.yml @@ -119,7 +119,7 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux - dist: focal + dist: bionic compiler: gcc-10 env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 addons: @@ -130,7 +130,7 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" - os: linux - dist: focal + dist: bionic compiler: gcc-UBSAN env: UBSAN=1 TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold addons: From 54c307ebed9a1ebf62a506c6e310f6aba271855c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 3 Sep 2020 11:58:58 +0300 Subject: [PATCH 101/309] Removed unused includes. --- include/boost/log/sources/basic_logger.hpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/boost/log/sources/basic_logger.hpp b/include/boost/log/sources/basic_logger.hpp index 8138e65ab9..818f8e259a 100644 --- a/include/boost/log/sources/basic_logger.hpp +++ b/include/boost/log/sources/basic_logger.hpp @@ -27,9 +27,6 @@ #include #include #include -#include -#include -#include #include #include #include From 48d2319d7bc36528fdb8adb2ad529c34a1844b04 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 7 Sep 2020 01:11:37 +0300 Subject: [PATCH 102/309] Added gcc-like SSSE3/AVX2 flags for qcc. Presumably, qcc is based on gcc, so it should accept the same flags. --- build/Jamfile.v2 | 8 ++++---- config/x86-ext/Jamfile.jam | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index ea614b94f3..b4bae7c28b 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -293,11 +293,11 @@ rule ssse3-targets-cond ( properties * ) if x86 in [ log-architecture.deduce-architecture $(properties) ] { - local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler-supports-ssse3 ] ; + local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler supports SSSE3 ] ; if $(has_ssse3) { result = ; - if gcc in $(properties) || clang in $(properties) + if gcc in $(properties) || clang in $(properties) || qcc in $(properties) { result = "-msse -msse2 -msse3 -mssse3" ; } @@ -356,11 +356,11 @@ rule avx2-targets-cond ( properties * ) if x86 in [ log-architecture.deduce-architecture $(properties) ] { - local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler-supports-avx2 ] ; + local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler supports AVX2 ] ; if $(has_avx2) { result = ; - if gcc in $(properties) + if gcc in $(properties) || qcc in $(properties) { result = "-mavx -mavx2 -fabi-version=0" ; } diff --git a/config/x86-ext/Jamfile.jam b/config/x86-ext/Jamfile.jam index 0e9695aae4..5c11714784 100644 --- a/config/x86-ext/Jamfile.jam +++ b/config/x86-ext/Jamfile.jam @@ -16,6 +16,7 @@ project /boost/log/x86-extensions obj ssse3 : ssse3.cpp : gcc:"-msse -msse2 -msse3 -mssse3" + qcc:"-msse -msse2 -msse3 -mssse3" clang:"-msse -msse2 -msse3 -mssse3" intel-linux:"-xSSSE3" intel-darwin:"-xSSSE3" @@ -25,6 +26,7 @@ obj ssse3 : ssse3.cpp obj avx2 : avx2.cpp : gcc:"-mavx -mavx2 -fabi-version=0" + qcc:"-mavx -mavx2 -fabi-version=0" clang:"-mavx -mavx2" intel-linux:"-xCORE-AVX2 -fabi-version=0" intel-darwin:"-xCORE-AVX2 -fabi-version=0" From f1108cdb0c8e8978d5b93b093e2781af6ec2337f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 7 Sep 2020 11:00:50 +0300 Subject: [PATCH 103/309] Fixed Jamfile and made config messages more human-friendly. --- build/Jamfile.v2 | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index b4bae7c28b..08b9be839b 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -92,7 +92,7 @@ rule check-pthread-mutex-robust ( properties * ) { local result ; - local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : pthread-supports-robust-mutexes ] ; + local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : "pthread supports robust mutexes" ] ; if $(has_pthread_mutex_robust) { result = BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST ; @@ -105,7 +105,7 @@ rule check-atomic-int32 ( properties * ) { local result ; - local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : native-atomic-int32-supported ] ; + local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : "native atomic int32 supported" ] ; if ! $(has_atomic_int32) { result = BOOST_LOG_WITHOUT_IPC ; @@ -120,7 +120,7 @@ rule check-native-syslog ( properties * ) if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] { - local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : native-syslog-supported ] ; + local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : "native syslog supported" ] ; if $(has_native_syslog) { result = BOOST_LOG_USE_NATIVE_SYSLOG ; @@ -138,7 +138,7 @@ rule check-message-compiler ( properties * ) { if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] { - local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ; + local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : "has message compiler" ] ; if ! $(has_mc) { result = BOOST_LOG_WITHOUT_EVENT_LOG ; @@ -293,7 +293,7 @@ rule ssse3-targets-cond ( properties * ) if x86 in [ log-architecture.deduce-architecture $(properties) ] { - local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler supports SSSE3 ] ; + local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : "compiler supports SSSE3" ] ; if $(has_ssse3) { result = ; @@ -356,7 +356,7 @@ rule avx2-targets-cond ( properties * ) if x86 in [ log-architecture.deduce-architecture $(properties) ] { - local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler supports AVX2 ] ; + local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : "compiler supports AVX2" ] ; if $(has_avx2) { result = ; @@ -418,14 +418,14 @@ rule select-arch-specific-sources ( properties * ) if x86 in [ log-architecture.deduce-architecture $(properties) ] { - local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : compiler-supports-ssse3 ] ; + local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : "compiler supports SSSE3" ] ; if $(has_ssse3) { result += BOOST_LOG_USE_SSSE3 ; result += $(BOOST_LOG_COMMON_SSSE3_SRC) ; } - local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : compiler-supports-avx2 ] ; + local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : "compiler supports AVX2" ] ; if $(has_avx2) { result += BOOST_LOG_USE_AVX2 ; From b4399c040706caab791aadc31a33352f8fc66607 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 02:50:08 +0300 Subject: [PATCH 104/309] Moved SSSE3/AVX2 compiler flag deduction to a common submodule. Also, use gcc-style command line arguments by default as most compilers tend to support them. Marked config obj targets explicit. --- build/Jamfile.v2 | 101 +---------------- ...g-architecture.jam => log-arch-config.jam} | 104 +++++++++++++----- config/atomic-int32/Jamfile.jam | 2 +- config/message-compiler/Jamfile.jam | 2 + config/native-syslog/Jamfile.jam | 2 +- config/pthread-mutex-robust/Jamfile.jam | 2 +- config/x86-ext/Jamfile.jam | 25 +---- config/xopen-source-600/Jamfile.jam | 1 + 8 files changed, 90 insertions(+), 149 deletions(-) rename build/{log-architecture.jam => log-arch-config.jam} (51%) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 08b9be839b..82a66069b8 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -12,7 +12,7 @@ import path ; import project ; import feature ; import configure ; -import log-architecture ; +import log-arch-config ; import log-platform-config ; using mc ; @@ -56,7 +56,7 @@ rule has-config-flag ( flag : properties * ) rule check-instruction-set ( properties * ) { local result ; - local instruction_set = [ feature.get-values "log-instruction-set" : [ log-architecture.deduce-instruction-set $(properties) ] ] ; + local instruction_set = [ log-arch-config.deduce-instruction-set $(properties) ] ; if $(instruction_set) = i386 || $(instruction_set) = i486 { @@ -287,59 +287,13 @@ BOOST_LOG_COMMON_AVX2_SRC = dump_avx2 ; -rule ssse3-targets-cond ( properties * ) -{ - local result = no ; - - if x86 in [ log-architecture.deduce-architecture $(properties) ] - { - local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : "compiler supports SSSE3" ] ; - if $(has_ssse3) - { - result = ; - if gcc in $(properties) || clang in $(properties) || qcc in $(properties) - { - result = "-msse -msse2 -msse3 -mssse3" ; - } - else if intel in $(properties) - { - if win in $(properties) - { - result = "/QxSSSE3" ; - } - else - { - result = "-xSSSE3" ; - } - } - else if msvc in $(properties) - { - # MSVC doesn't really care about these switches, all SSE intrinsics are always available, but still... - # Also 64 bit MSVC doesn't have the /arch:SSE2 switch as it is the default. - if 32 in [ log-architecture.deduce-address-model $(properties) ] - { - result = "/arch:SSE2" ; - } - } - } - } - -# if ! no in $(result) -# { -# ECHO Boost.Log: Using SSSE3 optimized implementation ; -# } -# ECHO $(result) ; - - return $(result) ; -} - for local src in $(BOOST_LOG_COMMON_SSSE3_SRC) { obj $(src) : ## sources ## $(src).cpp : ## requirements ## - @ssse3-targets-cond + @log-arch-config.ssse3-flags shared:BOOST_LOG_DLL BOOST_LOG_BUILDING_THE_LIB=1 : ## default-build ## @@ -350,58 +304,13 @@ for local src in $(BOOST_LOG_COMMON_SSSE3_SRC) explicit $(src) ; } -rule avx2-targets-cond ( properties * ) -{ - local result = no ; - - if x86 in [ log-architecture.deduce-architecture $(properties) ] - { - local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : "compiler supports AVX2" ] ; - if $(has_avx2) - { - result = ; - if gcc in $(properties) || qcc in $(properties) - { - result = "-mavx -mavx2 -fabi-version=0" ; - } - else if clang in $(properties) - { - result = "-mavx -mavx2" ; - } - else if intel in $(properties) - { - if win in $(properties) - { - result = "/arch:CORE-AVX2" ; - } - else - { - result = "-xCORE-AVX2 -fabi-version=0" ; - } - } - else if msvc in $(properties) - { - result = "/arch:AVX" ; - } - } - } - -# if ! no in $(result) -# { -# ECHO Boost.Log: Using AVX2 optimized implementation ; -# } -# ECHO $(result) ; - - return $(result) ; -} - for local src in $(BOOST_LOG_COMMON_AVX2_SRC) { obj $(src) : ## sources ## $(src).cpp : ## requirements ## - @avx2-targets-cond + @log-arch-config.avx2-flags shared:BOOST_LOG_DLL BOOST_LOG_BUILDING_THE_LIB=1 : ## default-build ## @@ -416,7 +325,7 @@ rule select-arch-specific-sources ( properties * ) { local result ; - if x86 in [ log-architecture.deduce-architecture $(properties) ] + if x86 in [ log-arch-config.deduce-architecture $(properties) ] { local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : "compiler supports SSSE3" ] ; if $(has_ssse3) diff --git a/build/log-architecture.jam b/build/log-arch-config.jam similarity index 51% rename from build/log-architecture.jam rename to build/log-arch-config.jam index 785dda0f5c..2a053d5685 100644 --- a/build/log-architecture.jam +++ b/build/log-arch-config.jam @@ -1,7 +1,7 @@ -# log-architecture.jam +# log-arch-config.jam # # Copyright 2012 Steven Watanabe -# Copyright 2013 Andrey Semashev +# Copyright 2013, 2020 Andrey Semashev # # Distributed under the Boost Software License Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at @@ -15,10 +15,6 @@ import feature ; local here = [ modules.binding $(__name__) ] ; -feature.feature log-architecture : : free ; -feature.feature log-address-model : : free ; -feature.feature log-instruction-set : : free ; - project.push-current [ project.current ] ; project.load [ path.join [ path.make $(here:D) ] ../../config/checks/architecture ] ; project.pop-current ; @@ -28,63 +24,53 @@ rule deduce-address-model ( properties * ) local address_model = [ feature.get-values "address-model" : $(properties) ] ; if $(address_model) { - return $(address_model) ; + return $(address_model) ; } else { if [ configure.builds /boost/architecture//32 : $(properties) : 32-bit ] { - return 32 ; + return 32 ; } else if [ configure.builds /boost/architecture//64 : $(properties) : 64-bit ] { - return 64 ; + return 64 ; } } } -rule address-model ( ) -{ - return @log-architecture.deduce-address-model ; -} - rule deduce-architecture ( properties * ) { local architecture = [ feature.get-values "architecture" : $(properties) ] ; if $(architecture) { - return $(architecture) ; + return $(architecture) ; } else { if [ configure.builds /boost/architecture//x86 : $(properties) : x86 ] { - return x86 ; + return x86 ; } else if [ configure.builds /boost/architecture//arm : $(properties) : arm ] { - return arm ; + return arm ; } else if [ configure.builds /boost/architecture//mips1 : $(properties) : mips1 ] { - return mips1 ; + return mips1 ; } else if [ configure.builds /boost/architecture//power : $(properties) : power ] { - return power ; + return power ; } else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ] { - return sparc ; + return sparc ; } } } -rule architecture ( ) -{ - return @log-architecture.deduce-architecture ; -} - rule deduce-instruction-set ( properties * ) { local result ; @@ -92,21 +78,79 @@ rule deduce-instruction-set ( properties * ) if $(instruction_set) { - result = $(instruction_set) ; + result = $(instruction_set) ; } else { - if x86 in $(properties) && 32 in $(properties) + if x86 in [ deduce-architecture $(properties) ] && 32 in [ deduce-address-model $(properties) ] { # We build for Pentium Pro and later CPUs by default. This is used as the target in many Linux distributions, and Windows and OS X also seem to not support older CPUs. - result = i686 ; + result = i686 ; + } + } + + return $(result) ; +} + +rule ssse3-flags ( properties * ) +{ + local result ; + + if intel in $(properties) + { + if win in $(properties) + { + result = "/QxSSSE3" ; + } + else + { + result = "-xSSSE3" ; + } + } + else if msvc in $(properties) + { + # MSVC doesn't really care about these switches, all SSE intrinsics are always available, but still... + # Also 64 bit MSVC doesn't have the /arch:SSE2 switch as it is the default. + if 32 in [ deduce-address-model $(properties) ] + { + result = "/arch:SSE2" ; } } + else + { + result = "-msse -msse2 -msse3 -mssse3" ; + } return $(result) ; } -rule instruction-set ( ) +rule avx2-flags ( properties * ) { - return @log-architecture.deduce-instruction-set ; + local result ; + + if intel in $(properties) + { + if win in $(properties) + { + result = "/arch:CORE-AVX2" ; + } + else + { + result = "-xCORE-AVX2 -fabi-version=0" ; + } + } + else if msvc in $(properties) + { + result = "/arch:AVX" ; + } + else if clang in $(properties) + { + result = "-mavx -mavx2" ; + } + else + { + result = "-mavx -mavx2 -fabi-version=0" ; + } + + return $(result) ; } diff --git a/config/atomic-int32/Jamfile.jam b/config/atomic-int32/Jamfile.jam index 5b08d8d783..2f8d4baf29 100644 --- a/config/atomic-int32/Jamfile.jam +++ b/config/atomic-int32/Jamfile.jam @@ -12,8 +12,8 @@ project /boost/log/atomic-int32 : source-location . : requirements @log-platform-config.set-platform-defines - off ; obj atomic_int32 : atomic_int32.cpp ; +explicit atomic_int32 ; diff --git a/config/message-compiler/Jamfile.jam b/config/message-compiler/Jamfile.jam index 37d98d107c..6716021bbb 100644 --- a/config/message-compiler/Jamfile.jam +++ b/config/message-compiler/Jamfile.jam @@ -17,6 +17,8 @@ project /boost/log/message-compiler ; obj simple_event_log : windows/simple_event_log.mc ; +explicit simple_event_log ; # This test target verifies that Message Compiler (mc) is available and supported by the current toolset alias test-availability : simple_event_log ; +explicit test-availability ; diff --git a/config/native-syslog/Jamfile.jam b/config/native-syslog/Jamfile.jam index fa5dfcd0aa..dd9143f50a 100644 --- a/config/native-syslog/Jamfile.jam +++ b/config/native-syslog/Jamfile.jam @@ -12,8 +12,8 @@ project /boost/log/native-syslog : source-location . : requirements @log-platform-config.set-platform-defines - off ; obj native_syslog : native_syslog.cpp ; +explicit native_syslog ; diff --git a/config/pthread-mutex-robust/Jamfile.jam b/config/pthread-mutex-robust/Jamfile.jam index 6082e66e1f..ac3de06bd6 100644 --- a/config/pthread-mutex-robust/Jamfile.jam +++ b/config/pthread-mutex-robust/Jamfile.jam @@ -12,8 +12,8 @@ project /boost/log/pthread-mutex-robust : source-location . : requirements @log-platform-config.set-platform-defines - off ; obj pthread_mutex_robust : pthread_mutex_robust.cpp ; +explicit pthread_mutex_robust ; diff --git a/config/x86-ext/Jamfile.jam b/config/x86-ext/Jamfile.jam index 5c11714784..5379dbd164 100644 --- a/config/x86-ext/Jamfile.jam +++ b/config/x86-ext/Jamfile.jam @@ -6,6 +6,7 @@ # import project ; +import log-arch-config ; project /boost/log/x86-extensions : source-location . @@ -13,24 +14,8 @@ project /boost/log/x86-extensions off ; -obj ssse3 : ssse3.cpp - : - gcc:"-msse -msse2 -msse3 -mssse3" - qcc:"-msse -msse2 -msse3 -mssse3" - clang:"-msse -msse2 -msse3 -mssse3" - intel-linux:"-xSSSE3" - intel-darwin:"-xSSSE3" - intel-win:"/QxSSSE3" - ; - -obj avx2 : avx2.cpp - : - gcc:"-mavx -mavx2 -fabi-version=0" - qcc:"-mavx -mavx2 -fabi-version=0" - clang:"-mavx -mavx2" - intel-linux:"-xCORE-AVX2 -fabi-version=0" - intel-darwin:"-xCORE-AVX2 -fabi-version=0" - intel-win:"/arch:CORE-AVX2" - msvc:"/arch:AVX" - ; +obj ssse3 : ssse3.cpp : @log-arch-config.ssse3-flags ; +explicit ssse3 ; +obj avx2 : avx2.cpp : @log-arch-config.avx2-flags ; +explicit avx2 ; diff --git a/config/xopen-source-600/Jamfile.jam b/config/xopen-source-600/Jamfile.jam index 0d744dcfd7..d2a28ad567 100644 --- a/config/xopen-source-600/Jamfile.jam +++ b/config/xopen-source-600/Jamfile.jam @@ -14,3 +14,4 @@ project /boost/log/xopen-source-600 ; obj xopen_source_600 : xopen_source_600.cpp ; +explicit xopen_source_600 ; From 0505022c77a7fca48e7b3327ff6ddad473c226d8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 15:15:22 +0300 Subject: [PATCH 105/309] Replaced volatile version counter in basic_sink_frontend with an atomic. This should silence clang-cl warnings about deprecated uses of volatile. Note that the previous code, although not conforming to the standard C++ memory model, did not have a problem in practice, since all relevant architectures implement plain aligned 32-bit loads and stores atomically. The code only modifies the counter under a mutex lock, so the atomic is only needed to prevent load/store slicing. Closes https://github.com/boostorg/log/issues/128. --- doc/changelog.qbk | 1 + .../boost/log/sinks/basic_sink_frontend.hpp | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index ddb45bda70..d82e03df7c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Corrected the file counter that would be used in [link log.detailed.sink_backends.text_file `text_file_backend`] when generating the target file name (based on the pattern set by `set_target_file_name_pattern` method) when the log file is rotated. The backend used to use the next value of file counter, which could cause some counter values to be skipped on application restarts. ([github_issue 125]) +* Replaced a volatile version counter in `basic_sink_frontend` with an atomic. This should silence clang-cl warnings about deprecated uses of `volatile`. ([github_issue 128]) [heading 2.19, Boost 1.74] diff --git a/include/boost/log/sinks/basic_sink_frontend.hpp b/include/boost/log/sinks/basic_sink_frontend.hpp index e30c6a28cc..38ecf0ea54 100644 --- a/include/boost/log/sinks/basic_sink_frontend.hpp +++ b/include/boost/log/sinks/basic_sink_frontend.hpp @@ -26,6 +26,8 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) +#include +#include #include #include #include @@ -312,7 +314,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : formatting_context() : #if !defined(BOOST_LOG_NO_THREADS) - m_Version(0), + m_Version(0u), #endif m_FormattingStream(m_FormattedRecord) { @@ -334,7 +336,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : #if !defined(BOOST_LOG_NO_THREADS) //! State version - volatile unsigned int m_Version; + boost::atomic< unsigned int > m_Version; //! Formatter functor formatter_type m_Formatter; @@ -360,7 +362,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : explicit basic_formatting_sink_frontend(bool cross_thread) : basic_sink_frontend(cross_thread) #if !defined(BOOST_LOG_NO_THREADS) - , m_Version(0) + , m_Version(0u) #endif { } @@ -374,7 +376,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : #if !defined(BOOST_LOG_NO_THREADS) boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); m_Formatter = formatter; - ++m_Version; + m_Version.opaque_add(1u, boost::memory_order_relaxed); #else m_Context.m_Formatter = formatter; #endif @@ -387,7 +389,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : #if !defined(BOOST_LOG_NO_THREADS) boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); m_Formatter.reset(); - ++m_Version; + m_Version.opaque_add(1u, boost::memory_order_relaxed); #else m_Context.m_Formatter.reset(); #endif @@ -413,7 +415,7 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : #if !defined(BOOST_LOG_NO_THREADS) boost::log::aux::exclusive_lock_guard< mutex_type > lock(this->frontend_mutex()); m_Locale = loc; - ++m_Version; + m_Version.opaque_add(1u, boost::memory_order_relaxed); #else m_Context.m_FormattingStream.imbue(loc); #endif @@ -438,11 +440,11 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : #if !defined(BOOST_LOG_NO_THREADS) context = m_pContext.get(); - if (!context || context->m_Version != m_Version) + if (!context || context->m_Version != m_Version.load(boost::memory_order_relaxed)) { { boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex()); - context = new formatting_context(m_Version, m_Locale, m_Formatter); + context = new formatting_context(m_Version.load(boost::memory_order_relaxed), m_Locale, m_Formatter); } m_pContext.reset(context); } From ac3beeb0979a0db9f6efe66ff074acdda6aa5c9a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 16:02:39 +0300 Subject: [PATCH 106/309] Make clang-cl use gcc-style warning pragmas and disable __assume warnings. Closes https://github.com/boostorg/log/issues/127. --- include/boost/log/detail/footer.hpp | 6 +++--- include/boost/log/detail/header.hpp | 13 ++++++++++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/include/boost/log/detail/footer.hpp b/include/boost/log/detail/footer.hpp index b3f97f2011..e749822cf6 100644 --- a/include/boost/log/detail/footer.hpp +++ b/include/boost/log/detail/footer.hpp @@ -7,12 +7,12 @@ #if !defined(BOOST_LOG_ENABLE_WARNINGS) -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) #pragma warning(pop) -#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ - && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ + && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) #pragma GCC diagnostic pop diff --git a/include/boost/log/detail/header.hpp b/include/boost/log/detail/header.hpp index 95984ff402..37495c00c2 100644 --- a/include/boost/log/detail/header.hpp +++ b/include/boost/log/detail/header.hpp @@ -9,7 +9,7 @@ #if !defined(BOOST_LOG_ENABLE_WARNINGS) -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(__clang__) #pragma warning(push, 3) // 'm_A' : class 'A' needs to have dll-interface to be used by clients of class 'B' @@ -45,8 +45,10 @@ // 'X': This function or variable may be unsafe. Consider using Y instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #pragma warning(disable: 4996) -#elif defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ - && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 +#elif (defined(__GNUC__) && !(defined(__INTEL_COMPILER) || defined(__ICL) || defined(__ICC) || defined(__ECC)) \ + && (__GNUC__ * 100 + __GNUC_MINOR__) >= 406) || defined(__clang__) + +// Note: clang-cl goes here as well, as it seems to support gcc-style warning control pragmas. #pragma GCC diagnostic push // 'var' defined but not used @@ -61,6 +63,11 @@ #pragma GCC diagnostic ignored "-Wunused-local-typedefs" #endif +#if defined(__clang__) +// the argument to '__builtin_assume' has side effects that will be discarded +#pragma clang diagnostic ignored "-Wassume" +#endif // defined(__clang__) + #endif #endif // !defined(BOOST_LOG_ENABLE_WARNINGS) From 4485deb0c7fd32ef348e6cfcf723ad0e5f7e49b6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 16:07:35 +0300 Subject: [PATCH 107/309] Added definition of BOOST_LOG_ASSUME for clang. clang supports __builtin_assume starting with clang 3.6. --- include/boost/log/detail/config.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 189e5e4746..3d1ee3f5eb 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -171,6 +171,12 @@ // An MS-like compilers' extension that allows to optimize away the needless code #if defined(_MSC_VER) # define BOOST_LOG_ASSUME(expr) __assume(expr) +#elif defined(__has_builtin) +# if __has_builtin(__builtin_assume) +# define BOOST_LOG_ASSUME(expr) __builtin_assume(expr) +# else +# define BOOST_LOG_ASSUME(expr) +# endif #else # define BOOST_LOG_ASSUME(expr) #endif From 4ef885fc7ad8463a6a85cebfe71b5b9105ada230 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 17:41:08 +0300 Subject: [PATCH 108/309] Moved MSVC C/C++ runtime deprecated macros to a common place. The _SCL_SECURE_NO_WARNINGS, _SCL_SECURE_NO_DEPRECATE, _CRT_SECURE_NO_WARNINGS and _CRT_SECURE_NO_DEPRECATE macros need to be defined for every compiler that uses MSVC C/C++ runtime, so instead of duplicating these definitions in multiple places, define them for Windows platform regardless of the compiler. In particular, they are now defined for clang-cl. --- build/Jamfile.v2 | 10 ---------- build/log-platform-config.jam | 13 ++++++++++++- example/advanced_usage/Jamfile.v2 | 9 +-------- example/async_log/Jamfile.v2 | 9 +-------- example/basic_usage/Jamfile.v2 | 9 +-------- example/bounded_async_log/Jamfile.v2 | 9 +-------- example/doc/Jamfile.v2 | 9 +-------- example/event_log/Jamfile.v2 | 9 +-------- example/keywords/Jamfile.v2 | 9 +-------- example/multiple_files/Jamfile.v2 | 9 +-------- example/multiple_threads/Jamfile.v2 | 9 +-------- example/native_syslog/Jamfile.v2 | 9 +-------- example/rotating_file/Jamfile.v2 | 9 +-------- example/settings_file/Jamfile.v2 | 9 +-------- example/settings_file_custom_factories/Jamfile.v2 | 9 +-------- example/syslog/Jamfile.v2 | 9 +-------- example/trivial/Jamfile.v2 | 9 +-------- example/wide_char/Jamfile.v2 | 9 +-------- test/Jamfile.v2 | 10 ---------- 19 files changed, 28 insertions(+), 149 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 82a66069b8..6c812f1ddf 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -175,16 +175,6 @@ project boost/log BOOST_SPIRIT_USE_PHOENIX_V3=1 BOOST_THREAD_DONT_USE_CHRONO=1 # Don't introduce false dependency on Boost.Chrono - # Disable warnings about using 'insecure' standard C functions - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE - msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration diff --git a/build/log-platform-config.jam b/build/log-platform-config.jam index cee01cc100..16af8cb346 100644 --- a/build/log-platform-config.jam +++ b/build/log-platform-config.jam @@ -20,7 +20,18 @@ project.pop-current ; rule set-platform-defines ( properties * ) { - local result = ; + local result ; + + if windows in $(properties) + { + # Disable warnings about using 'insecure' standard C functions. + # These affect MSVC C/C++ library headers, which are used by various compilers. Define them universally on Windows to avoid + # duplicating them for every compiler in every jamfile. + result += _SCL_SECURE_NO_WARNINGS ; + result += _SCL_SECURE_NO_DEPRECATE ; + result += _CRT_SECURE_NO_WARNINGS ; + result += _CRT_SECURE_NO_DEPRECATE ; + } if ( windows in $(properties) ) || ( cygwin in $(properties) ) { diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index 542bd18b6d..31381a1cdc 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index bb2438d433..f1181c531b 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index 56a9d5eb5a..df0a62396b 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index 36e47a29a1..0aaa7b69fd 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 1ef9938880..185298a172 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -55,19 +55,12 @@ project @check-message-compiler shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index bcc17f46b4..c6f65fc812 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -50,19 +50,12 @@ project @check-message-compiler shared - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index 54db6e1126..85073adaef 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index 81e3e5dda1..f7bbf0f614 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 269a0cb795..77230f2f7b 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index 51ee1c2e15..e9670461a3 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index f91c942ebe..d622e64954 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index 8459f7d76f..957fd815d8 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/settings_file_custom_factories/Jamfile.v2 b/example/settings_file_custom_factories/Jamfile.v2 index 8032af9b6e..7f80d4e4c9 100644 --- a/example/settings_file_custom_factories/Jamfile.v2 +++ b/example/settings_file_custom_factories/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index a4d1a97108..31d173c519 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 3a02bf3832..9f524ff61c 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index 7a3c518edd..7f997c13db 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -12,19 +12,12 @@ project @log-platform-config.set-platform-defines shared:BOOST_ALL_DYN_LINK - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE darwin:-ftemplate-depth-1024 gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index eed81d8eb5..ba32ba5fa4 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -18,16 +18,6 @@ project common - # Disable warnings about using 'insecure' standard C functions - msvc:_SCL_SECURE_NO_WARNINGS - msvc:_SCL_SECURE_NO_DEPRECATE - msvc:_CRT_SECURE_NO_WARNINGS - msvc:_CRT_SECURE_NO_DEPRECATE - intel-win:_SCL_SECURE_NO_WARNINGS - intel-win:_SCL_SECURE_NO_DEPRECATE - intel-win:_CRT_SECURE_NO_WARNINGS - intel-win:_CRT_SECURE_NO_DEPRECATE - msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration From de4e85e9b3dac499742977f3677c396469a38a1b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 18:23:57 +0300 Subject: [PATCH 109/309] Switched to c++-template-depth feature instead of explicit compiler flags. This allows to specify the limit for other compilers that support it and remove it for clang-cl, which doesn't. --- build/Jamfile.v2 | 6 ++---- example/advanced_usage/Jamfile.v2 | 4 ++-- example/async_log/Jamfile.v2 | 4 ++-- example/basic_usage/Jamfile.v2 | 4 ++-- example/bounded_async_log/Jamfile.v2 | 4 ++-- example/doc/Jamfile.v2 | 4 ++-- example/event_log/Jamfile.v2 | 4 ++-- example/keywords/Jamfile.v2 | 4 ++-- example/multiple_files/Jamfile.v2 | 4 ++-- example/multiple_threads/Jamfile.v2 | 4 ++-- example/native_syslog/Jamfile.v2 | 4 ++-- example/rotating_file/Jamfile.v2 | 4 ++-- example/settings_file/Jamfile.v2 | 4 ++-- example/settings_file_custom_factories/Jamfile.v2 | 4 ++-- example/syslog/Jamfile.v2 | 4 ++-- example/trivial/Jamfile.v2 | 4 ++-- example/wide_char/Jamfile.v2 | 4 ++-- test/Jamfile.v2 | 5 ++--- 18 files changed, 36 insertions(+), 39 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 6c812f1ddf..f15079d51e 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -175,6 +175,8 @@ project boost/log BOOST_SPIRIT_USE_PHOENIX_V3=1 BOOST_THREAD_DONT_USE_CHRONO=1 # Don't introduce false dependency on Boost.Chrono + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration @@ -197,10 +199,6 @@ project boost/log intel-linux:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" intel-darwin:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" - darwin:-ftemplate-depth-1024 - clang:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 - gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components gcc,windows:-Wl,--enable-auto-import gcc,cygwin:-Wl,--enable-auto-import diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index 31381a1cdc..7fd1692335 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index f1181c531b..d8506ff24d 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index df0a62396b..ea7dab52e9 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index 0aaa7b69fd..052aabab04 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 185298a172..1a1fe40595 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -56,13 +56,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index c6f65fc812..d876ec7a73 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -51,13 +51,13 @@ project shared + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index 85073adaef..b53e1ede47 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index f7bbf0f614..3edecd7ac2 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 77230f2f7b..6e1c9b70ee 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index e9670461a3..293d6900b8 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index d622e64954..4ea7f656fb 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index 957fd815d8..0eec5cf665 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/settings_file_custom_factories/Jamfile.v2 b/example/settings_file_custom_factories/Jamfile.v2 index 7f80d4e4c9..7c682a057e 100644 --- a/example/settings_file_custom_factories/Jamfile.v2 +++ b/example/settings_file_custom_factories/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index 31d173c519..3ed4362e55 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 9f524ff61c..1d89159ff1 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index 7f997c13db..dab6836fe7 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -13,13 +13,13 @@ project shared:BOOST_ALL_DYN_LINK + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration msvc:/wd4459 # declaration of 'A' hides global declaration msvc:/wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Disable Intel warnings: diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index ba32ba5fa4..73107a27f7 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -18,6 +18,8 @@ project common + 1024 + msvc:/bigobj msvc:/wd4503 # decorated name length exceeded, name was truncated msvc:/wd4456 # declaration of 'A' hides previous local declaration @@ -41,9 +43,6 @@ project intel-linux:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" intel-darwin:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" - darwin:-ftemplate-depth-1024 - gcc:-ftemplate-depth-1024 - gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 From 84b82a4de4f217daec1e081bc31d5a4683febe95 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 18:28:06 +0300 Subject: [PATCH 110/309] Removed BOOST_LOG_ASSUME postulating that a reference is not null. Normally, this should be inferred by compiler, as references are not allowed to be null. This silences a clang-cl warning. --- src/named_scope.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/named_scope.cpp b/src/named_scope.cpp index 176e91fbfb..8121cbfa7c 100644 --- a/src/named_scope.cpp +++ b/src/named_scope.cpp @@ -57,7 +57,6 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { entry._m_pPrev = top; entry._m_pNext = &this->m_RootNode; - BOOST_LOG_ASSUME(&entry != 0); this->m_RootNode._m_pPrev = top->_m_pNext = const_cast< aux::named_scope_list_node* >( static_cast< const aux::named_scope_list_node* >(&entry)); From 99abc451d7c7f1a452d54a5be2acc275e33bec29 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 8 Sep 2020 21:15:01 +0300 Subject: [PATCH 111/309] Work around clang 3.6 compilation error in attachable_sstream_buf. It looks like the compiler has a bug that prevents it from finding attachable_sstream_buf::append that takes a pointer as the first argument. This commit disables __builtin_assume for the compiler. The builtin was enabled recently and triggered the bug. --- include/boost/log/detail/config.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 3d1ee3f5eb..7eb4d27f03 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -172,7 +172,9 @@ #if defined(_MSC_VER) # define BOOST_LOG_ASSUME(expr) __assume(expr) #elif defined(__has_builtin) -# if __has_builtin(__builtin_assume) +// Clang 3.6 adds __builtin_assume, but enabling it causes weird compilation errors, where the compiler +// doesn't see one of attachable_sstream_buf::append overloads. It works fine with Clang 3.7 and later. +# if __has_builtin(__builtin_assume) && (!defined(__clang__) || (__clang_major__ * 100 + __clang_minor__) >= 307) # define BOOST_LOG_ASSUME(expr) __builtin_assume(expr) # else # define BOOST_LOG_ASSUME(expr) From 3891a7fad9270e298b348a35fc24ce19924b7bf5 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 9 Sep 2020 15:13:20 +0300 Subject: [PATCH 112/309] Fixed running CI on feature branches. --- .travis.yml | 4 +++- appveyor.yml | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 305b7d71ab..32eab182e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -369,8 +369,10 @@ matrix: install: - GIT_FETCH_JOBS=8 + - BOOST_BRANCH=develop + - if [ "$TRAVIS_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi - cd .. - - git clone -b $TRAVIS_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root + - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root - cd boost-root - git submodule init tools/boostdep - git submodule init tools/build diff --git a/appveyor.yml b/appveyor.yml index 14ae6e810a..09b4c1248d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -98,8 +98,10 @@ environment: install: - set GIT_FETCH_JOBS=8 + - set BOOST_BRANCH=develop + - if "%APPVEYOR_REPO_BRANCH%" == "master" set BOOST_BRANCH=master - cd .. - - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root + - git clone -b %BOOST_BRANCH% https://github.com/boostorg/boost.git boost-root - cd boost-root - git submodule init tools/boostdep - git submodule init tools/build From d98067a0edfe38e533c583864d58360b05ac17fc Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 9 Sep 2020 14:24:49 +0300 Subject: [PATCH 113/309] Explicitly specify PP_REPEAT nesting level to nested Boost.Preprocessor macros. This adds a Boost.Log-side workaround for a bug in the new MSVC-14.2 preprocessor enabled with /Zc:preprocessor. The bug still affects other libraries, like Boost.Phoenix. This change may also improve preprocessing speed. Related to https://github.com/boostorg/preprocessor/issues/33. Related to https://github.com/boostorg/log/issues/126. --- include/boost/log/detail/parameter_tools.hpp | 28 +++++++++---------- include/boost/log/sinks/async_frontend.hpp | 24 ++++++++-------- include/boost/log/sinks/sync_frontend.hpp | 12 ++++---- .../sinks/text_ipc_message_queue_backend.hpp | 12 ++++---- include/boost/log/sinks/unlocked_frontend.hpp | 12 ++++---- .../boost/log/utility/exception_handler.hpp | 12 ++++---- include/boost/log/utility/setup/file.hpp | 6 ++-- 7 files changed, 53 insertions(+), 53 deletions(-) diff --git a/include/boost/log/detail/parameter_tools.hpp b/include/boost/log/detail/parameter_tools.hpp index 8ca2c5dbee..bcf75f8ddd 100644 --- a/include/boost/log/detail/parameter_tools.hpp +++ b/include/boost/log/detail/parameter_tools.hpp @@ -46,36 +46,36 @@ public:\ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, macro, args) -#define BOOST_LOG_CTOR_FORWARD_1(n, types)\ +#define BOOST_LOG_CTOR_FORWARD_1(z, n, types)\ template< typename T0 >\ explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ - BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))) {} + BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))) {} -#define BOOST_LOG_CTOR_FORWARD_N(n, types)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ - BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))) {} +#define BOOST_LOG_CTOR_FORWARD_N(z, n, types)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ + BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))) {} #define BOOST_LOG_CTOR_FORWARD(z, n, types)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_FORWARD_1, BOOST_LOG_CTOR_FORWARD_N)(n, types) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_FORWARD_1, BOOST_LOG_CTOR_FORWARD_N)(z, n, types) // The macro expands to a number of templated constructors that aggregate their named arguments // into an ArgumentsPack and pass it to the base class constructor. #define BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_FORWARD(class_type, base_type)\ BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_CTOR_FORWARD, (class_type, base_type)) -#define BOOST_LOG_CTOR_CALL_1(n, types)\ +#define BOOST_LOG_CTOR_CALL_1(z, n, types)\ template< typename T0 >\ explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy())\ - { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))); } + { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))); } -#define BOOST_LOG_CTOR_CALL_N(n, types)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg))\ - { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS(n, arg))); } +#define BOOST_LOG_CTOR_CALL_N(z, n, types)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit BOOST_PP_TUPLE_ELEM(2, 0, types)(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg))\ + { BOOST_PP_TUPLE_ELEM(2, 1, types)((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))); } #define BOOST_LOG_CTOR_CALL(z, n, types)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_CALL_1, BOOST_LOG_CTOR_CALL_N)(n, types) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_CTOR_CALL_1, BOOST_LOG_CTOR_CALL_N)(z, n, types) // The macro expands to a number of templated constructors that aggregate their named arguments // into an ArgumentsPack and pass it to a function call. diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 97c2ec3afa..0827fb98dd 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -56,7 +56,7 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(z, n, data)\ template< typename T0 >\ explicit asynchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ base_type(true),\ @@ -80,32 +80,32 @@ namespace sinks { start_feeding_thread();\ } -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit asynchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(z, n, data)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit asynchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ base_type(true),\ - queue_base_type((BOOST_PP_ENUM_PARAMS(n, arg))),\ - m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))),\ + queue_base_type((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ + m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ - if ((BOOST_PP_ENUM_PARAMS(n, arg))[keywords::start_thread | true])\ + if ((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))[keywords::start_thread | true])\ start_feeding_thread();\ }\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ base_type(true),\ - queue_base_type((BOOST_PP_ENUM_PARAMS(n, arg))),\ + queue_base_type((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ m_pBackend(backend),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ - if ((BOOST_PP_ENUM_PARAMS(n, arg))[keywords::start_thread | true])\ + if ((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))[keywords::start_thread | true])\ start_feeding_thread();\ } #define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(z, n, data) #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/sync_frontend.hpp b/include/boost/log/sinks/sync_frontend.hpp index ccf5c9022f..d92df8d971 100644 --- a/include/boost/log/sinks/sync_frontend.hpp +++ b/include/boost/log/sinks/sync_frontend.hpp @@ -46,20 +46,20 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(z, n, data)\ template< typename T0 >\ explicit synchronous_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ base_type(false),\ m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {} -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit synchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(z, n, data)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit synchronous_sink(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ base_type(false),\ - m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {} + m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS_Z(z, n, arg))) {} #define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(z, n, data) #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/text_ipc_message_queue_backend.hpp b/include/boost/log/sinks/text_ipc_message_queue_backend.hpp index 370ccfb32f..de5ab524bc 100644 --- a/include/boost/log/sinks/text_ipc_message_queue_backend.hpp +++ b/include/boost/log/sinks/text_ipc_message_queue_backend.hpp @@ -44,18 +44,18 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1(n, data)\ +#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1(z, n, data)\ template< typename T0 >\ explicit text_ipc_message_queue_backend(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ m_queue(arg0) {} -#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N(n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit text_ipc_message_queue_backend(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ - m_queue(BOOST_PP_ENUM_PARAMS(n, arg)) {} +#define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N(z, n, data)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit text_ipc_message_queue_backend(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ + m_queue(BOOST_PP_ENUM_PARAMS_Z(z, n, arg)) {} #define BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL(z, n, data)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N)(n, data) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_IPC_BACKEND_CTOR_FORWARD_INTERNAL_N)(z, n, data) #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/unlocked_frontend.hpp b/include/boost/log/sinks/unlocked_frontend.hpp index 918efeb6d2..0b8c7570c6 100644 --- a/include/boost/log/sinks/unlocked_frontend.hpp +++ b/include/boost/log/sinks/unlocked_frontend.hpp @@ -39,20 +39,20 @@ namespace sinks { #ifndef BOOST_LOG_DOXYGEN_PASS -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(n, data)\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1(z, n, data)\ template< typename T0 >\ explicit unlocked_sink(T0 const& arg0, typename boost::log::aux::enable_if_named_parameters< T0, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy()) :\ base_type(false),\ m_pBackend(boost::make_shared< sink_backend_type >(arg0)) {} -#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - explicit unlocked_sink(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg)) :\ +#define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N(z, n, data)\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + explicit unlocked_sink(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg)) :\ base_type(false),\ - m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS(n, arg))) {} + m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS_Z(z, n, arg))) {} #define BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL(z, n, data)\ - BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(n, data) + BOOST_PP_IF(BOOST_PP_EQUAL(n, 1), BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_1, BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL_N)(z, n, data) #endif // BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/utility/exception_handler.hpp b/include/boost/log/utility/exception_handler.hpp index 9b8551ac0d..5206fef8b2 100644 --- a/include/boost/log/utility/exception_handler.hpp +++ b/include/boost/log/utility/exception_handler.hpp @@ -248,26 +248,26 @@ inline typename boost::lazy_enable_if_c< } #define BOOST_LOG_MAKE_EXCEPTION_HANDLER_INTERNAL(z, n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T), typename HandlerT >\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T), typename HandlerT >\ inline exception_handler<\ - BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\ + BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\ HandlerT\ > make_exception_handler(HandlerT const& handler)\ {\ typedef exception_handler<\ - BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\ + BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\ HandlerT\ > eh_t;\ return eh_t(handler);\ }\ - template< BOOST_PP_ENUM_PARAMS(n, typename T), typename HandlerT >\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T), typename HandlerT >\ inline nothrow_exception_handler<\ - BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\ + BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\ HandlerT\ > make_exception_handler(HandlerT const& handler, std::nothrow_t const&)\ {\ typedef nothrow_exception_handler<\ - BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS(n, T) >,\ + BOOST_PP_CAT(mpl::vector, n)< BOOST_PP_ENUM_PARAMS_Z(z, n, T) >,\ HandlerT\ > eh_t;\ return eh_t(handler);\ diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index 03fef7f30b..caacf4aeb8 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -136,13 +136,13 @@ struct file_name_param_traits< T, false > #ifndef BOOST_LOG_DOXYGEN_PASS #define BOOST_LOG_INIT_LOG_TO_FILE_INTERNAL(z, n, data)\ - template< BOOST_PP_ENUM_PARAMS(n, typename T) >\ - inline shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > add_file_log(BOOST_PP_ENUM_BINARY_PARAMS(n, T, const& arg))\ + template< BOOST_PP_ENUM_PARAMS_Z(z, n, typename T) >\ + inline shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > add_file_log(BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, T, const& arg))\ {\ return aux::file_name_param_traits< T0 >::wrap_add_file_log(\ arg0\ BOOST_PP_COMMA_IF(BOOST_PP_GREATER(n, 1))\ - BOOST_PP_EXPR_IF(BOOST_PP_GREATER(n, 1), (BOOST_PP_ENUM_SHIFTED_PARAMS(n, arg)))\ + BOOST_PP_EXPR_IF(BOOST_PP_GREATER(n, 1), (BOOST_PP_ENUM_SHIFTED_PARAMS_Z(z, n, arg)))\ );\ } From e0cb0b7d67e2ab587ab9bf84113ece67235ce951 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Sep 2020 19:44:08 +0300 Subject: [PATCH 114/309] Resolved a possible conflict between flush and run in asynchronous_sink. If run is called in a user's thread, and flush is called before the user's thread enters run, flush would mark the sink frontend as being used by another record feeding thread and run would exit with an exception. To mitigate this, we now only throw exception when either run or feed_records is being called in multiple threads, but not flush. When flush is in progress, run and feed_records will block until the flush is complete. This ensures that the sink backend is only used from one thread at a time. Additionally, stop now explicitly doesn't wait for the ongoing record feeding operation to complete. It is generally not possible to ensure that the record feeding thread has left (or won't enter) the feeding operation after stop returns. When the internal feeding thread is used we ensure that the thread is done by joining it. When user's feeding thread is used it is the user's responsibility to ensure that the thread won't use the frontend past stop. Joining the thread is one possible way to do it. Fixes https://github.com/boostorg/log/issues/131. --- doc/changelog.qbk | 1 + include/boost/log/sinks/async_frontend.hpp | 233 +++++++++++++-------- 2 files changed, 152 insertions(+), 82 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index d82e03df7c..02e59138e8 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,6 +15,7 @@ * Corrected the file counter that would be used in [link log.detailed.sink_backends.text_file `text_file_backend`] when generating the target file name (based on the pattern set by `set_target_file_name_pattern` method) when the log file is rotated. The backend used to use the next value of file counter, which could cause some counter values to be skipped on application restarts. ([github_issue 125]) * Replaced a volatile version counter in `basic_sink_frontend` with an atomic. This should silence clang-cl warnings about deprecated uses of `volatile`. ([github_issue 128]) +* In the [class_sinks_asynchronous_sink] frontend, resolved a possible conflict between `flush` and `run` methods, if `run` is called from a user's thread instead of the internal dedicated thread spawned by the frontend. `run` and `feed_records` methods will wait for `flush` to complete, if one is in progress. Additionally, `stop` now explicitly doesn't wait for the ongoing record feeding operation to complete. ([github_issue 131]) [heading 2.19, Boost 1.74] diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 0827fb98dd..0efcaabfaf 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -26,7 +26,6 @@ #error Boost.Log: Asynchronous sink frontend is only supported in multithreaded environment #endif -#include #include #include #include @@ -62,6 +61,7 @@ namespace sinks { base_type(true),\ queue_base_type(arg0),\ m_pBackend(boost::make_shared< sink_backend_type >(arg0)),\ + m_ActiveOperation(idle),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ @@ -73,6 +73,7 @@ namespace sinks { base_type(true),\ queue_base_type(arg0),\ m_pBackend(backend),\ + m_ActiveOperation(idle),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ @@ -86,6 +87,7 @@ namespace sinks { base_type(true),\ queue_base_type((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ m_pBackend(boost::make_shared< sink_backend_type >(BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ + m_ActiveOperation(idle),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ @@ -97,6 +99,7 @@ namespace sinks { base_type(true),\ queue_base_type((BOOST_PP_ENUM_PARAMS_Z(z, n, arg))),\ m_pBackend(backend),\ + m_ActiveOperation(idle),\ m_StopRequested(false),\ m_FlushRequested(false)\ {\ @@ -113,7 +116,13 @@ namespace sinks { * \brief Asynchronous logging sink frontend * * The frontend starts a separate thread on construction. All logging records are passed - * to the backend in this dedicated thread only. + * to the backend in this dedicated thread. + * + * The user can prevent spawning the internal thread by specifying \c start_thread parameter + * with the value of \c false on construction. In this case log records will be buffered + * in the internal queue until the user calls \c run, \c feed_records or \c flush in his own + * thread. Log record queueing strategy is specified in the \c QueueingStrategyT template + * parameter. */ template< typename SinkBackendT, typename QueueingStrategyT = unbounded_fifo_queue > class asynchronous_sink : @@ -129,51 +138,53 @@ class asynchronous_sink : //! Frontend synchronization mutex type typedef typename base_type::mutex_type frontend_mutex_type; - //! A scope guard that implements thread ID management - class scoped_thread_id + //! Operation bit mask + enum operation + { + idle = 0u, + feeding_records = 1u, + flushing = 3u + }; + + //! Function object to run the log record feeding thread + class run_func { + public: + typedef void result_type; + private: - frontend_mutex_type& m_Mutex; - condition_variable_any& m_Cond; - thread::id& m_ThreadID; - boost::atomic< bool >& m_StopRequested; + asynchronous_sink* m_self; public: - //! Initializing constructor - scoped_thread_id(frontend_mutex_type& mut, condition_variable_any& cond, thread::id& tid, boost::atomic< bool >& sr) - : m_Mutex(mut), m_Cond(cond), m_ThreadID(tid), m_StopRequested(sr) + explicit run_func(asynchronous_sink* self) BOOST_NOEXCEPT : m_self(self) { - lock_guard< frontend_mutex_type > lock(m_Mutex); - if (m_ThreadID != thread::id()) - BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread"); - m_ThreadID = this_thread::get_id(); } + + result_type operator()() const + { + m_self->run(); + } + }; + + //! A scope guard that implements active operation management + class scoped_feeding_opereation + { + private: + asynchronous_sink& m_self; + + public: //! Initializing constructor - scoped_thread_id(unique_lock< frontend_mutex_type >& l, condition_variable_any& cond, thread::id& tid, boost::atomic< bool >& sr) - : m_Mutex(*l.mutex()), m_Cond(cond), m_ThreadID(tid), m_StopRequested(sr) + explicit scoped_feeding_opereation(asynchronous_sink& self) : m_self(self) { - unique_lock< frontend_mutex_type > lock(move(l)); - if (m_ThreadID != thread::id()) - BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread"); - m_ThreadID = this_thread::get_id(); } //! Destructor - ~scoped_thread_id() + ~scoped_feeding_opereation() { - try - { - lock_guard< frontend_mutex_type > lock(m_Mutex); - m_StopRequested.store(false, boost::memory_order_release); - m_ThreadID = thread::id(); - m_Cond.notify_all(); - } - catch (...) - { - } + m_self.complete_feeding_operation(); } - BOOST_DELETED_FUNCTION(scoped_thread_id(scoped_thread_id const&)) - BOOST_DELETED_FUNCTION(scoped_thread_id& operator= (scoped_thread_id const&)) + BOOST_DELETED_FUNCTION(scoped_feeding_opereation(scoped_feeding_opereation const&)) + BOOST_DELETED_FUNCTION(scoped_feeding_opereation& operator= (scoped_feeding_opereation const&)) }; //! A scope guard that resets a flag on destructor @@ -194,7 +205,7 @@ class asynchronous_sink : try { lock_guard< frontend_mutex_type > lock(m_Mutex); - m_Flag.store(false, boost::memory_order_release); + m_Flag.store(false, boost::memory_order_relaxed); m_Cond.notify_all(); } catch (...) @@ -233,11 +244,11 @@ class asynchronous_sink : //! Dedicated record feeding thread thread m_DedicatedFeedingThread; - //! Feeding thread ID - thread::id m_FeedingThreadID; //! Condition variable to implement blocking operations condition_variable_any m_BlockCond; + //! Currently active operation + operation m_ActiveOperation; //! The flag indicates that the feeding loop has to be stopped boost::atomic< bool > m_StopRequested; //! The flag indicates that queue flush has been requested @@ -251,11 +262,12 @@ class asynchronous_sink : * \param start_thread If \c true, the frontend creates a thread to feed * log records to the backend. Otherwise no thread is * started and it is assumed that the user will call - * either \c run or \c feed_records himself. + * \c run, \c feed_records or \c flush himself. */ - asynchronous_sink(bool start_thread = true) : + explicit asynchronous_sink(bool start_thread = true) : base_type(true), m_pBackend(boost::make_shared< sink_backend_type >()), + m_ActiveOperation(idle), m_StopRequested(false), m_FlushRequested(false) { @@ -269,13 +281,14 @@ class asynchronous_sink : * \param start_thread If \c true, the frontend creates a thread to feed * log records to the backend. Otherwise no thread is * started and it is assumed that the user will call - * either \c run or \c feed_records himself. + * \c run, \c feed_records or \c flush himself. * * \pre \a backend is not \c NULL. */ explicit asynchronous_sink(shared_ptr< sink_backend_type > const& backend, bool start_thread = true) : base_type(true), m_pBackend(backend), + m_ActiveOperation(idle), m_StopRequested(false), m_FlushRequested(false) { @@ -292,7 +305,7 @@ class asynchronous_sink : * \li start_thread - If \c true, the frontend creates a thread to feed * log records to the backend. Otherwise no thread is * started and it is assumed that the user will call - * either \c run or \c feed_records himself. + * \c run, \c feed_records or \c flush himself. */ #ifndef BOOST_LOG_DOXYGEN_PASS BOOST_LOG_PARAMETRIZED_CONSTRUCTORS_GEN(BOOST_LOG_SINK_CTOR_FORWARD_INTERNAL, ~) @@ -365,7 +378,16 @@ class asynchronous_sink : void run() { // First check that no other thread is running - scoped_thread_id guard(base_type::frontend_mutex(), m_BlockCond, m_FeedingThreadID, m_StopRequested); + { + unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + if (!start_feeding_operation(lock, feeding_records)) + { + m_StopRequested.store(false, boost::memory_order_relaxed); + return; + } + } + + scoped_feeding_opereation guard(*this); // Now start the feeding loop while (true) @@ -384,40 +406,40 @@ class asynchronous_sink : } /*! - * The method softly interrupts record feeding loop. This method must be called when the \c run - * method execution has to be interrupted. Unlike regular thread interruption, calling - * \c stop will not interrupt the record processing in the middle. Instead, the sink frontend - * will attempt to finish its business with the record in progress and return afterwards. - * This method can be called either if the sink was created with a dedicated thread, - * or if the feeding loop was initiated by user. + * The method softly interrupts record feeding loop. This method must be called when \c run, + * \c feed_records or \c flush method execution has to be interrupted. Unlike regular thread + * interruption, calling \c stop will not interrupt the record processing in the middle. + * Instead, the sink frontend will attempt to finish its business with the record in progress + * and return afterwards. This method can be called either if the sink was created with + * an internal dedicated thread, or if the feeding loop was initiated by user. + * + * If no record feeding operation is in progress, calling \c stop marks the sink frontend + * so that the next feeding operation stops immediately. * * \note Returning from this method does not guarantee that there are no records left buffered * in the sink frontend. It is possible that log records keep coming during and after this * method is called. At some point of execution of this method log records stop being processed, * and all records that come after this point are put into the queue. These records will be * processed upon further calls to \c run or \c feed_records. + * + * \note If the record feeding loop is being run in a user's thread (i.e. \c start_thread was specified + * as \c false on frontend construction), this method does not guarantee that upon return the thread + * has returned from the record feeding loop or that it won't enter it in the future. The method + * only ensures that the record feeding thread will eventually return from the feeding loop. It is + * user's responsibility to synchronize with the user's record feeding thread. */ void stop() { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); - if (m_FeedingThreadID != thread::id() || m_DedicatedFeedingThread.joinable()) + boost::thread feeding_thread; { - try - { - m_StopRequested.store(true, boost::memory_order_release); - queue_base_type::interrupt_dequeue(); - while (m_StopRequested.load(boost::memory_order_acquire)) - m_BlockCond.wait(lock); - } - catch (...) - { - m_StopRequested.store(false, boost::memory_order_release); - throw; - } + lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); - lock.unlock(); - m_DedicatedFeedingThread.join(); + m_StopRequested.store(true, boost::memory_order_release); + m_DedicatedFeedingThread.swap(feeding_thread); } + + if (feeding_thread.joinable()) + feeding_thread.join(); } /*! @@ -428,7 +450,16 @@ class asynchronous_sink : void feed_records() { // First check that no other thread is running - scoped_thread_id guard(base_type::frontend_mutex(), m_BlockCond, m_FeedingThreadID, m_StopRequested); + { + unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + if (!start_feeding_operation(lock, feeding_records)) + { + m_StopRequested.store(false, boost::memory_order_relaxed); + return; + } + } + + scoped_feeding_opereation guard(*this); // Now start the feeding loop do_feed_records(); @@ -437,29 +468,31 @@ class asynchronous_sink : /*! * The method feeds all log records that may have been buffered to the backend and returns. * Unlike \c feed_records, in case of ordering queueing the method also feeds records - * that were enqueued during the ordering window, attempting to empty the queue completely. + * that were enqueued during the ordering window, attempting to drain the queue completely. */ void flush() BOOST_OVERRIDE { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); - if (m_FeedingThreadID != thread::id() || m_DedicatedFeedingThread.joinable()) { - // There is already a thread feeding records, let it do the job - m_FlushRequested.store(true, boost::memory_order_release); - queue_base_type::interrupt_dequeue(); - while (!m_StopRequested.load(boost::memory_order_acquire) && m_FlushRequested.load(boost::memory_order_acquire)) - m_BlockCond.wait(lock); + unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + if (static_cast< unsigned int >(m_ActiveOperation & feeding_records) != 0u) + { + // There is already a thread feeding records, let it do the job + m_FlushRequested.store(true, boost::memory_order_release); + queue_base_type::interrupt_dequeue(); + while (!m_StopRequested.load(boost::memory_order_acquire) && m_FlushRequested.load(boost::memory_order_acquire)) + m_BlockCond.wait(lock); - // The condition may have been signalled when the feeding thread was finishing. - // In that case records may not have been flushed, and we do the flush ourselves. - if (m_FeedingThreadID != thread::id()) - return; - } + // The condition may have been signalled when the feeding operation was finishing. + // In that case records may not have been flushed, and we do the flush ourselves. + if (m_ActiveOperation != idle) + return; + } - m_FlushRequested.store(true, boost::memory_order_release); + m_ActiveOperation = flushing; + m_FlushRequested.store(true, boost::memory_order_relaxed); + } - // Flush records ourselves. The guard releases the lock. - scoped_thread_id guard(lock, m_BlockCond, m_FeedingThreadID, m_StopRequested); + scoped_feeding_opereation guard(*this); do_feed_records(); } @@ -469,7 +502,43 @@ class asynchronous_sink : //! The method spawns record feeding thread void start_feeding_thread() { - boost::thread(boost::bind(&asynchronous_sink::run, this)).swap(m_DedicatedFeedingThread); + boost::thread(run_func(this)).swap(m_DedicatedFeedingThread); + } + + //! Starts record feeding operation. The method blocks or throws if another feeding operation is in progress. + bool start_feeding_operation(unique_lock< frontend_mutex_type >& lock, operation op) + { + while (m_ActiveOperation != idle) + { + if (BOOST_UNLIKELY(op == feeding_records && m_ActiveOperation == feeding_records)) + BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread"); + + if (m_StopRequested.load(boost::memory_order_relaxed)) + { + return false; + } + + m_BlockCond.wait(lock); + } + + m_ActiveOperation = op; + + return true; + } + + //! Completes record feeding operation + void complete_feeding_operation() BOOST_NOEXCEPT + { + try + { + lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); + m_ActiveOperation = idle; + m_StopRequested.store(false, boost::memory_order_relaxed); + m_BlockCond.notify_all(); + } + catch (...) + { + } } //! The record feeding loop From a36417bcf34e9818cbc7e013d18c1c83c9e4221c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 28 Sep 2020 12:21:28 +0300 Subject: [PATCH 115/309] Minor cleanup. --- include/boost/log/sinks/async_frontend.hpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 0efcaabfaf..652cffc931 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -380,11 +380,8 @@ class asynchronous_sink : // First check that no other thread is running { unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); - if (!start_feeding_operation(lock, feeding_records)) - { - m_StopRequested.store(false, boost::memory_order_relaxed); + if (start_feeding_operation(lock, feeding_records)) return; - } } scoped_feeding_opereation guard(*this); @@ -452,11 +449,8 @@ class asynchronous_sink : // First check that no other thread is running { unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); - if (!start_feeding_operation(lock, feeding_records)) - { - m_StopRequested.store(false, boost::memory_order_relaxed); + if (start_feeding_operation(lock, feeding_records)) return; - } } scoped_feeding_opereation guard(*this); @@ -513,9 +507,10 @@ class asynchronous_sink : if (BOOST_UNLIKELY(op == feeding_records && m_ActiveOperation == feeding_records)) BOOST_LOG_THROW_DESCR(unexpected_call, "Asynchronous sink frontend already runs a record feeding thread"); - if (m_StopRequested.load(boost::memory_order_relaxed)) + if (BOOST_UNLIKELY(m_StopRequested.load(boost::memory_order_relaxed))) { - return false; + m_StopRequested.store(false, boost::memory_order_relaxed); + return true; } m_BlockCond.wait(lock); @@ -523,7 +518,7 @@ class asynchronous_sink : m_ActiveOperation = op; - return true; + return false; } //! Completes record feeding operation From d667377004fef39fe83932c0b15120a7b61a4cbb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 1 Dec 2020 15:34:23 +0300 Subject: [PATCH 116/309] Fixed infinite join wait in asynchronous_sink::stop(). Commit e0cb0b7d67e2ab587ab9bf84113ece67235ce951 introduced a bug causing stop() to infinitely wait for the feeding thread to join because it is blocked waiting for new records or notifications. Notify the thread when stop() is called. Fixes https://github.com/boostorg/log/issues/135. --- include/boost/log/sinks/async_frontend.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 652cffc931..a329ce7a24 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -432,6 +432,8 @@ class asynchronous_sink : lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); m_StopRequested.store(true, boost::memory_order_release); + queue_base_type::interrupt_dequeue(); + m_DedicatedFeedingThread.swap(feeding_thread); } From 1c4de7d8c69c8d59327972a1dc839721dc86d9ad Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 7 Dec 2020 02:41:26 +0300 Subject: [PATCH 117/309] In the add_file_log docs, describe the special meaning of the target param. Added a note that the target named parameter enables file collector and limits associated with the target directory. --- include/boost/log/utility/setup/file.hpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index caacf4aeb8..769b223e57 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -168,7 +168,8 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, BOOST_LOG_INIT_LOG_TO_F * after each written record. * \li \c auto_newline_mode - Specifies automatic trailing newline insertion mode. Must be a value of * the \c auto_newline_mode enum. By default, is auto_newline_mode::insert_if_missing. - * \li \c target The target directory to store rotated files in. See sinks::file::make_collector. + * \li \c target The target directory to store rotated files in. Enables file collector and, if specified, limits associated + * with the target directory. See sinks::file::make_collector. * \li \c max_size The maximum total size of rotated files in the target directory. See sinks::file::make_collector. * \li \c min_free_space Minimum free space in the target directory. See sinks::file::make_collector. * \li \c max_files The maximum total number of rotated files in the target directory. See sinks::file::make_collector. @@ -177,7 +178,11 @@ BOOST_PP_REPEAT_FROM_TO(1, BOOST_LOG_MAX_PARAMETER_ARGS, BOOST_LOG_INIT_LOG_TO_F * or a filter lambda expression. * \li \c format Specifies a formatter to install into the sink. May be a string that represents a formatter, * or a formatter lambda expression (either streaming or Boost.Format-like notation). + * * \return Pointer to the constructed sink. + * + * \note The \c target named argument is required to enable the file collector and the limits associated with the target directory. + * If the parameter is not specified, the file collector will not be created and the limits will not be maintained. */ template< typename... ArgsT > shared_ptr< BOOST_LOG_FILE_SINK_FRONTEND_INTERNAL< sinks::text_file_backend > > add_file_log(ArgsT... const& args); From 2cfc379f8f55d45745335f878c3b76c83c3b6283 Mon Sep 17 00:00:00 2001 From: Edward Diener Date: Wed, 20 Jan 2021 13:25:18 -0500 Subject: [PATCH 118/309] [skip ci] Add "cxxstd" json field. The "cxxstd" json field is being added to each Boost library's meta json information for libraries in order to specify the minumum C++ standard compilation level. The value of this field matches one of the values for 'cxxstd' in Boost.Build. The purpose of doing this is to provide information for the Boost website documentation for each library which will specify the minimum C++ standard compilation that an end-user must employ in order to use the particular library. This will aid end-users who want to know if they can successfully use a Boost library based on their C++ compiler's compilation level, without having to search the library's documentation to find this out. --- meta/libraries.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/meta/libraries.json b/meta/libraries.json index 08e82d14e1..6b2ea363fc 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -10,5 +10,6 @@ ], "maintainers": [ "Andrey Semashev " - ] + ], + "cxxstd": "03" } From a75c4f45c4560e4bbcee2f4a77d36eac48675171 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 28 Jan 2021 01:55:20 +0300 Subject: [PATCH 119/309] Corrected a formal race in the threadsafe_queue implementation. The pointer to the next node can be read and written concurrently by push and try_pop methods. This does not impose a real problem as long as pointer-sized loads and stores generated by the compiler are atomic on a given target platform, which it typically is. No memory ordering constraints are needed in this context. To guarantee atomicity, use Boost.Atomic for these pointers. Fixes https://github.com/boostorg/log/issues/139. --- doc/changelog.qbk | 8 +++++++- include/boost/log/detail/threadsafe_queue.hpp | 15 +++------------ src/threadsafe_queue.cpp | 10 ++++++---- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 02e59138e8..d051eee352 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2020. + Copyright Andrey Semashev 2007 - 2021. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.21, Boost 1.76] + +[*Bug fixes:] + +* Corrected a formal race condition in the thread-safe log record queue implementation used in the `unbounded_fifo_queue` policy of the [class_sinks_asynchronous_sink] frontend. The race could be detected by TSAN, but it was not a real problem on most current CPU architectures and compilers. ([github_issue 139]) + [heading 2.20, Boost 1.75] [*Bug fixes:] diff --git a/include/boost/log/detail/threadsafe_queue.hpp b/include/boost/log/detail/threadsafe_queue.hpp index b747ed4c5d..274dc4d37b 100644 --- a/include/boost/log/detail/threadsafe_queue.hpp +++ b/include/boost/log/detail/threadsafe_queue.hpp @@ -27,11 +27,11 @@ #include #include #include -#include +#include #include #include #include -#include +#include #include #include @@ -44,18 +44,9 @@ namespace aux { //! Base class for the thread-safe queue implementation struct threadsafe_queue_impl { - struct BOOST_LOG_MAY_ALIAS pointer_storage - { - union - { - void* data[2]; - type_with_alignment< 2 * sizeof(void*) >::type alignment; - }; - }; - struct node_base { - pointer_storage next; + boost::atomic< node_base* > next; }; static BOOST_LOG_API threadsafe_queue_impl* create(node_base* first_node); diff --git a/src/threadsafe_queue.cpp b/src/threadsafe_queue.cpp index 1a1656194a..cd67c98fa2 100644 --- a/src/threadsafe_queue.cpp +++ b/src/threadsafe_queue.cpp @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include #include #include @@ -96,14 +98,14 @@ class threadsafe_queue_impl_generic : void push(node_base* p) BOOST_OVERRIDE { set_next(p, NULL); - exclusive_lock_guard< mutex_type > _(m_Tail.mutex); + exclusive_lock_guard< mutex_type > lock(m_Tail.mutex); set_next(m_Tail.node, p); m_Tail.node = p; } bool try_pop(node_base*& node_to_free, node_base*& node_with_value) BOOST_OVERRIDE { - exclusive_lock_guard< mutex_type > _(m_Head.mutex); + exclusive_lock_guard< mutex_type > lock(m_Head.mutex); node_base* next = get_next(m_Head.node); if (next) { @@ -119,11 +121,11 @@ class threadsafe_queue_impl_generic : private: BOOST_FORCEINLINE static void set_next(node_base* p, node_base* next) { - p->next.data[0] = next; + p->next.store(next, boost::memory_order_relaxed); } BOOST_FORCEINLINE static node_base* get_next(node_base* p) { - return static_cast< node_base* >(p->next.data[0]); + return p->next.load(boost::memory_order_relaxed); } // Copying and assignment are closed From d99d9891dd785c6690905045e5fa522927107d58 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 28 Jan 2021 02:31:02 +0300 Subject: [PATCH 120/309] Removed the use of virtual functions from threadsafe_queue implementation. This should amount to a more efficient code and smaller binaries. --- include/boost/log/detail/threadsafe_queue.hpp | 41 ++++++++------ src/threadsafe_queue.cpp | 55 ++++++++++++++----- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/include/boost/log/detail/threadsafe_queue.hpp b/include/boost/log/detail/threadsafe_queue.hpp index 274dc4d37b..3280e81c00 100644 --- a/include/boost/log/detail/threadsafe_queue.hpp +++ b/include/boost/log/detail/threadsafe_queue.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -42,23 +42,30 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { //! Base class for the thread-safe queue implementation -struct threadsafe_queue_impl +class threadsafe_queue_impl { +public: struct node_base { boost::atomic< node_base* > next; }; +protected: + threadsafe_queue_impl(); + ~threadsafe_queue_impl(); + +public: static BOOST_LOG_API threadsafe_queue_impl* create(node_base* first_node); + static BOOST_LOG_API void destroy(threadsafe_queue_impl* impl) BOOST_NOEXCEPT; - static BOOST_LOG_API void* operator new (std::size_t size); - static BOOST_LOG_API void operator delete (void* p, std::size_t); + static BOOST_LOG_API node_base* reset_last_node(threadsafe_queue_impl* impl) BOOST_NOEXCEPT; + static BOOST_LOG_API bool unsafe_empty(const threadsafe_queue_impl* impl) BOOST_NOEXCEPT; + static BOOST_LOG_API void push(threadsafe_queue_impl* impl, node_base* p); + static BOOST_LOG_API bool try_pop(threadsafe_queue_impl* impl, node_base*& node_to_free, node_base*& node_with_value); - virtual ~threadsafe_queue_impl() {} - virtual node_base* reset_last_node() = 0; - virtual bool unsafe_empty() = 0; - virtual void push(node_base* p) = 0; - virtual bool try_pop(node_base*& node_to_free, node_base*& node_with_value) = 0; + // Copying and assignment is prohibited + BOOST_DELETED_FUNCTION(threadsafe_queue_impl(threadsafe_queue_impl const&)) + BOOST_DELETED_FUNCTION(threadsafe_queue_impl& operator= (threadsafe_queue_impl const&)) }; //! Thread-safe queue node type @@ -152,7 +159,7 @@ class threadsafe_queue : allocator_type(alloc) { node* p = alloc_traits::allocate(get_allocator(), 1); - if (p) + if (BOOST_LIKELY(!!p)) { try { @@ -185,21 +192,21 @@ class threadsafe_queue : if (!unsafe_empty()) { value_type value; - while (try_pop(value)); + while (try_pop(value)) {} } // Remove the last dummy node - node* p = static_cast< node* >(m_pImpl->reset_last_node()); + node* p = static_cast< node* >(threadsafe_queue_impl::reset_last_node(m_pImpl)); alloc_traits::destroy(get_allocator(), p); alloc_traits::deallocate(get_allocator(), p, 1); - delete m_pImpl; + threadsafe_queue_impl::destroy(m_pImpl); } /*! * Checks if the queue is empty. Not thread-safe, the returned result may not be actual. */ - bool unsafe_empty() const { return m_pImpl->unsafe_empty(); } + bool unsafe_empty() const BOOST_NOEXCEPT { return threadsafe_queue_impl::unsafe_empty(m_pImpl); } /*! * Puts a new element to the end of the queue. Thread-safe, can be called @@ -208,7 +215,7 @@ class threadsafe_queue : void push(const_reference value) { node* p = alloc_traits::allocate(get_allocator(), 1); - if (p) + if (BOOST_LIKELY(!!p)) { try { @@ -219,7 +226,7 @@ class threadsafe_queue : alloc_traits::deallocate(get_allocator(), p, 1); throw; } - m_pImpl->push(p); + threadsafe_queue_impl::push(m_pImpl, p); } else throw std::bad_alloc(); @@ -233,7 +240,7 @@ class threadsafe_queue : bool try_pop(reference value) { threadsafe_queue_impl::node_base *dealloc, *destr; - if (m_pImpl->try_pop(dealloc, destr)) + if (threadsafe_queue_impl::try_pop(m_pImpl, dealloc, destr)) { node* p = static_cast< node* >(destr); auto_deallocate guard(static_cast< allocator_type* >(this), static_cast< node* >(dealloc), p); diff --git a/src/threadsafe_queue.cpp b/src/threadsafe_queue.cpp index cd67c98fa2..3ca581ca0a 100644 --- a/src/threadsafe_queue.cpp +++ b/src/threadsafe_queue.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -78,11 +78,20 @@ class threadsafe_queue_impl_generic : m_Head.node = m_Tail.node = first_node; } - ~threadsafe_queue_impl_generic() BOOST_OVERRIDE + static void* operator new (std::size_t size) { + void* p = alignment::aligned_alloc(BOOST_LOG_CPU_CACHE_LINE_SIZE, size); + if (BOOST_UNLIKELY(!p)) + BOOST_THROW_EXCEPTION(std::bad_alloc()); + return p; } - node_base* reset_last_node() BOOST_OVERRIDE + static void operator delete (void* p, std::size_t) BOOST_NOEXCEPT + { + alignment::aligned_free(p); + } + + node_base* reset_last_node() BOOST_NOEXCEPT { BOOST_ASSERT(m_Head.node == m_Tail.node); node_base* p = m_Head.node; @@ -90,12 +99,12 @@ class threadsafe_queue_impl_generic : return p; } - bool unsafe_empty() BOOST_OVERRIDE + bool unsafe_empty() const BOOST_NOEXCEPT { return m_Head.node == m_Tail.node; } - void push(node_base* p) BOOST_OVERRIDE + void push(node_base* p) { set_next(p, NULL); exclusive_lock_guard< mutex_type > lock(m_Tail.mutex); @@ -103,7 +112,7 @@ class threadsafe_queue_impl_generic : m_Tail.node = p; } - bool try_pop(node_base*& node_to_free, node_base*& node_with_value) BOOST_OVERRIDE + bool try_pop(node_base*& node_to_free, node_base*& node_with_value) { exclusive_lock_guard< mutex_type > lock(m_Head.mutex); node_base* next = get_next(m_Head.node); @@ -133,22 +142,42 @@ class threadsafe_queue_impl_generic : BOOST_DELETED_FUNCTION(threadsafe_queue_impl_generic& operator= (threadsafe_queue_impl_generic const&)) }; +inline threadsafe_queue_impl::threadsafe_queue_impl() +{ +} + +inline threadsafe_queue_impl::~threadsafe_queue_impl() +{ +} + BOOST_LOG_API threadsafe_queue_impl* threadsafe_queue_impl::create(node_base* first_node) { return new threadsafe_queue_impl_generic(first_node); } -BOOST_LOG_API void* threadsafe_queue_impl::operator new (std::size_t size) +BOOST_LOG_API void threadsafe_queue_impl::destroy(threadsafe_queue_impl* impl) BOOST_NOEXCEPT +{ + delete static_cast< threadsafe_queue_impl_generic* >(impl); +} + +BOOST_LOG_API threadsafe_queue_impl::node_base* threadsafe_queue_impl::reset_last_node(threadsafe_queue_impl* impl) BOOST_NOEXCEPT +{ + return static_cast< threadsafe_queue_impl_generic* >(impl)->reset_last_node(); +} + +BOOST_LOG_API bool threadsafe_queue_impl::unsafe_empty(const threadsafe_queue_impl* impl) BOOST_NOEXCEPT +{ + return static_cast< const threadsafe_queue_impl_generic* >(impl)->unsafe_empty(); +} + +BOOST_LOG_API void threadsafe_queue_impl::push(threadsafe_queue_impl* impl, node_base* p) { - void* p = alignment::aligned_alloc(BOOST_LOG_CPU_CACHE_LINE_SIZE, size); - if (BOOST_UNLIKELY(!p)) - BOOST_THROW_EXCEPTION(std::bad_alloc()); - return p; + static_cast< threadsafe_queue_impl_generic* >(impl)->push(p); } -BOOST_LOG_API void threadsafe_queue_impl::operator delete (void* p, std::size_t) +BOOST_LOG_API bool threadsafe_queue_impl::try_pop(threadsafe_queue_impl* impl, node_base*& node_to_free, node_base*& node_with_value) { - alignment::aligned_free(p); + return static_cast< threadsafe_queue_impl_generic* >(impl)->try_pop(node_to_free, node_with_value); } } // namespace aux From 699fcc12815fd91b2e3a3066097beb62cdffc957 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 10 Feb 2021 14:45:52 +0300 Subject: [PATCH 121/309] Made channel loggers deep-copy the channel attribute on copy ctor/assignment. Although attributes are normally only shallow-copied, it is useful to allow the channel attribute to be deep copied when the parent logger is copied. This would eliminate the unexpected effect of modifying the channel in the copy, as it would otherwise affect the original logger. This commit makes copy constructor and assignment of the channel loggers deep-copy the channel value. The problem was reported in: https://stackoverflow.com/questions/66120806/deep-copy-of-boost-logger. Note that any other attributes that might have been added to the logger are still shallow copied. --- doc/changelog.qbk | 1 + include/boost/log/sources/channel_feature.hpp | 2 +- test/run/src_channel_logger_copy.cpp | 46 +++++++++++++++++++ 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 test/run/src_channel_logger_copy.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index d051eee352..b774bc37e9 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Corrected a formal race condition in the thread-safe log record queue implementation used in the `unbounded_fifo_queue` policy of the [class_sinks_asynchronous_sink] frontend. The race could be detected by TSAN, but it was not a real problem on most current CPU architectures and compilers. ([github_issue 139]) +* When copying a logger with a channel attribute (e.g. `channel_logger`), the channel attribute is now deep-copied from the original logger. This means that modifying the channel in the new logger will no longer affect the original logger. [heading 2.20, Boost 1.75] diff --git a/include/boost/log/sources/channel_feature.hpp b/include/boost/log/sources/channel_feature.hpp index 894c2697a5..7893ed8090 100644 --- a/include/boost/log/sources/channel_feature.hpp +++ b/include/boost/log/sources/channel_feature.hpp @@ -108,7 +108,7 @@ class basic_channel_logger : */ basic_channel_logger(basic_channel_logger const& that) : base_type(static_cast< base_type const& >(that)), - m_ChannelAttr(that.m_ChannelAttr) + m_ChannelAttr(that.m_ChannelAttr.get()) { // Our attributes must refer to our channel attribute base_type::attributes()[boost::log::aux::default_attribute_names::channel()] = m_ChannelAttr; diff --git a/test/run/src_channel_logger_copy.cpp b/test/run/src_channel_logger_copy.cpp new file mode 100644 index 0000000000..690110a3de --- /dev/null +++ b/test/run/src_channel_logger_copy.cpp @@ -0,0 +1,46 @@ +/* + * Copyright Andrey Semashev 2021. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file src_channel_logger_copy.cpp + * \author Andrey Semashev + * \date 10.02.2021 + * + * \brief This header contains tests for the channel logger copy constructor and assignment. + */ + +#define BOOST_TEST_MODULE src_channel_logger_copy + +#include +#include +#include + +namespace src = boost::log::sources; + +// Test that copy constructor decouples the channel attribute +BOOST_AUTO_TEST_CASE(copy_constructor) +{ + src::channel_logger< std::string > lg1("channel1"); + src::channel_logger< std::string > lg2 = lg1; + BOOST_CHECK_EQUAL(lg1.channel(), lg2.channel()); + + lg2.channel("channel2"); + BOOST_CHECK_NE(lg1.channel(), lg2.channel()); +} + +// Test that copy assignment decouples the channel attribute +BOOST_AUTO_TEST_CASE(copy_assignment) +{ + src::channel_logger< std::string > lg1("channel1"); + src::channel_logger< std::string > lg2("channel2"); + BOOST_CHECK_NE(lg1.channel(), lg2.channel()); + + lg2 = lg1; + BOOST_CHECK_EQUAL(lg1.channel(), lg2.channel()); + + lg2.channel("channel3"); + BOOST_CHECK_NE(lg1.channel(), lg2.channel()); +} From f8c3e45be3e62848b9f9c0dc8c7f93902ac926ba Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 4 Mar 2021 19:03:27 +0300 Subject: [PATCH 122/309] Resolved Boost.Build warnings and fixed building docs on Windows. Boost.Build was complaining about reserved characters used in boost.url.prefix, which is presumably a colon. Wrapped feature values in double quotes to silence that. In the gen-references action, there was a commented line, which caused errors on Windows. Presumably, because the cmd shell did not interpret # as a comment. Removed the comment to resolve the issue. --- doc/Jamfile.v2 | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index e6df037795..7d95b40956 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -151,7 +151,6 @@ rule gen-references ( target : source : properties * ) } actions gen-references { -# echo "*** Executing " $(NAME:E=xsltproc) -o "$(TARGET)" "$(STYLESHEET)" "$(>)" $(NAME:E=xsltproc) -o "$(TARGET)" "$(STYLESHEET)" "$(>)" } @@ -263,16 +262,16 @@ boostbook log : log_doc : - html/images/log - boost.root=../../../.. - boost.libraries=../../../libs/libraries.htm - nav.layout=none - boost.image=Boost - navig.graphics=1 - chunk.section.depth=2 - boost.compact.function=0 - pdf:boost.url.prefix=http://www.boost.org/doc/libs/release/libs/log/doc/html - pdf:img.src.path=$(images_location)/ + "html/images/log" + "boost.root=../../../.." + "boost.libraries=../../../libs/libraries.htm" + "nav.layout=none" + "boost.image=Boost" + "navig.graphics=1" + "chunk.section.depth=2" + "boost.compact.function=0" + pdf:"boost.url.prefix=http://www.boost.org/doc/libs/release/libs/log/doc/html" + pdf:"img.src.path=$(images_location)/" ; install html/images/log : [ glob *.png ] ; From 7b96f1119b848113bea380bd5d5801f376daeeb2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 4 Mar 2021 19:07:58 +0300 Subject: [PATCH 123/309] Added a note about performance issue of text_multifile_backend on Windows. File open/close operations are slow on Windows, which affects text_multifile_backend. Related to https://github.com/boostorg/log/issues/142. --- doc/sink_backends.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/sink_backends.qbk b/doc/sink_backends.qbk index ebad4aec4c..e30505c185 100644 --- a/doc/sink_backends.qbk +++ b/doc/sink_backends.qbk @@ -227,6 +227,8 @@ In order for file appending to actually happen, it is important that the name of While the text stream and file backends are aimed to store all log records into a single file/stream, this backend serves a different purpose. Assume we have a banking request processing application and we want logs related to every single request to be placed into a separate file. If we can associate some attribute with the request identity then the [class_sinks_text_multifile_backend] backend is the way to go. +[note During its operation, the multi-file backend frequently opens and closes log files, which means that the cost of these operations on a given system will be significant to the logging performance. Windows, especially with antivirus software running, is known to have extremely expensive file open and close operations. For example, compared to Linux, closing a file can be in the order of /hundreds/ times slower, according to [@https://lists.boost.org/Archives/boost/2021/03/250968.php some] [@https://gregoryszorc.com/blog/2015/10/22/append-i/o-performance-on-windows/ reports]. Consider creating multiple [link log.detailed.sink_backends.text_file `text_file_backend`] sinks with appropriate filters or running `text_multifile_backend` as an [link log.detailed.sink_frontends.async asynchronous] sink if you are affected.] + [example_sinks_multifile] You can see we used a regular [link log.detailed.expressions.formatters formatter] in order to specify file naming pattern. Now, every log record with a distinct value of the "RequestID" attribute will be stored in a separate file, no matter how many different requests are being processed by the application concurrently. You can also find the [@boost:/libs/log/example/multiple_files/main.cpp `multiple_files`] example in the library distribution, which shows a similar technique to separate logs generated by different threads of the application. From 6498b7f5ed6823dbe7659c62785458f45f6301f1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 4 Mar 2021 19:16:23 +0300 Subject: [PATCH 124/309] Documented named_scope::sentry constructor parameter t. --- include/boost/log/attributes/named_scope.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/log/attributes/named_scope.hpp b/include/boost/log/attributes/named_scope.hpp index 0587028dea..a9b2978fc7 100644 --- a/include/boost/log/attributes/named_scope.hpp +++ b/include/boost/log/attributes/named_scope.hpp @@ -370,6 +370,7 @@ class BOOST_LOG_API named_scope : * \param sn Scope name. * \param fn File name, in which the scope is located. * \param ln Line number in the file. + * \param t Scope name type. */ sentry(string_literal const& sn, string_literal const& fn, unsigned int ln, scope_entry::scope_name_type t = scope_entry::general) BOOST_NOEXCEPT : m_Entry(sn, fn, ln, t) From c3909b13a5d741545acf11c0da6c21b4d89343b6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 4 Mar 2021 20:49:53 +0300 Subject: [PATCH 125/309] Replaced the use of std::allocator with a new tag type use_std_allocator. This silences libc++ warnings about std::allocator being deprecated in C++17 and later. Fixes https://github.com/boostorg/log/issues/141. --- doc/changelog.qbk | 1 + include/boost/log/detail/allocator_traits.hpp | 18 ++++- include/boost/log/detail/threadsafe_queue.hpp | 3 +- .../predicates/channel_severity_filter.hpp | 77 ++++++++++--------- .../boost/log/utility/use_std_allocator.hpp | 60 +++++++++++++++ 5 files changed, 116 insertions(+), 43 deletions(-) create mode 100644 include/boost/log/utility/use_std_allocator.hpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index b774bc37e9..249331a6dc 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,6 +15,7 @@ * Corrected a formal race condition in the thread-safe log record queue implementation used in the `unbounded_fifo_queue` policy of the [class_sinks_asynchronous_sink] frontend. The race could be detected by TSAN, but it was not a real problem on most current CPU architectures and compilers. ([github_issue 139]) * When copying a logger with a channel attribute (e.g. `channel_logger`), the channel attribute is now deep-copied from the original logger. This means that modifying the channel in the new logger will no longer affect the original logger. +* Replaced the use of `std::allocator` in template parameters with a new tag type `boost::log::use_std_allocator` to silence libc++ warnings about the former being deprecated in C++17 and later. The tag indicates that the instantiated template should be using a specialization of `std::allocator` internally to allocate dynamic memory, so the change has no functional effect. ([github_issue 141]) [heading 2.20, Boost 1.75] diff --git a/include/boost/log/detail/allocator_traits.hpp b/include/boost/log/detail/allocator_traits.hpp index 3f9501c655..7716c9ca60 100644 --- a/include/boost/log/detail/allocator_traits.hpp +++ b/include/boost/log/detail/allocator_traits.hpp @@ -21,6 +21,7 @@ #if defined(BOOST_NO_CXX11_ALLOCATOR) #include #endif +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -46,9 +47,6 @@ using boost::container::allocator_traits; * The important difference from std::allocator_traits<Alloc>::rebind_alloc<U> is that this * trait does not require template aliases and thus is compatible with C++03. There is * boost::container::allocator_traits<Alloc>::portable_rebind_alloc<U>, but it is not present in std::allocator_traits. - * It will also attempt to instantiate the allocator type to test if it provides the nested rebind template. We don't want - * that to happen because it prohibits using std::allocator<void> in C++17 and later, which deprecated - * this allocator specialization. This standalone trait does not use the nested rebind template in this case. */ template< typename Allocator, typename U > struct rebind_alloc @@ -60,8 +58,20 @@ struct rebind_alloc #endif }; +/*! + * This specialization mostly exists to keep std::allocator<void> working. + * The default template will attempt to instantiate the allocator type to test if it provides the nested rebind template. + * We don't want that to happen because it prohibits using std::allocator<void> in C++17 and later, which deprecated + * this allocator specialization. This specialization does not use the nested rebind template in this case. + */ +template< typename T, typename U > +struct rebind_alloc< std::allocator< T >, U > +{ + typedef std::allocator< U > type; +}; + template< typename U > -struct rebind_alloc< std::allocator< void >, U > +struct rebind_alloc< use_std_allocator, U > { typedef std::allocator< U > type; }; diff --git a/include/boost/log/detail/threadsafe_queue.hpp b/include/boost/log/detail/threadsafe_queue.hpp index 3280e81c00..4015bc5f7e 100644 --- a/include/boost/log/detail/threadsafe_queue.hpp +++ b/include/boost/log/detail/threadsafe_queue.hpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -104,7 +105,7 @@ struct threadsafe_queue_node : * * The last requirement is not mandatory but is crucial for decent performance. */ -template< typename T, typename AllocatorT = std::allocator< void > > +template< typename T, typename AllocatorT = use_std_allocator > class threadsafe_queue : private boost::log::aux::rebind_alloc< AllocatorT, threadsafe_queue_node< T > >::type { diff --git a/include/boost/log/expressions/predicates/channel_severity_filter.hpp b/include/boost/log/expressions/predicates/channel_severity_filter.hpp index e8562e2a81..aca807a617 100644 --- a/include/boost/log/expressions/predicates/channel_severity_filter.hpp +++ b/include/boost/log/expressions/predicates/channel_severity_filter.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -53,7 +54,7 @@ template< typename SeverityFallbackT = fallback_to_none, typename ChannelOrderT = less, typename SeverityCompareT = greater_equal, - typename AllocatorT = std::allocator< void > + typename AllocatorT = use_std_allocator > class channel_severity_filter_terminal { @@ -227,7 +228,7 @@ template< typename SeverityFallbackT = fallback_to_none, typename ChannelOrderT = less, typename SeverityCompareT = greater_equal, - typename AllocatorT = std::allocator< void >, + typename AllocatorT = use_std_allocator, template< typename > class ActorT = phoenix::actor > class channel_severity_filter_actor : @@ -318,10 +319,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_name const //! \overload template< typename SeverityT, typename ChannelDescriptorT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_name const& severity_name) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_name) }}; return result_type(act); @@ -329,10 +330,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename ChannelT, typename SeverityDescriptorT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword) { - typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_keyword.get_name()) }}; return result_type(act); @@ -340,10 +341,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_keyword< S //! \overload template< typename ChannelDescriptorT, typename SeverityDescriptorT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_keyword.get_name()) }}; return result_type(act); @@ -351,10 +352,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename SeverityT, typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_name const& severity_name) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_name, channel_placeholder.get_fallback_policy()) }}; return result_type(act); @@ -362,10 +363,10 @@ channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT //! \overload template< typename ChannelT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_placeholder.get_name(), fallback_to_none(), severity_placeholder.get_fallback_policy()) }}; return result_type(act); @@ -373,10 +374,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_actor< Sev //! \overload template< typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, greater_equal, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, greater_equal, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, greater_equal, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, greater_equal, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_placeholder.get_name(), channel_placeholder.get_fallback_policy(), severity_placeholder.get_fallback_policy()) }}; return result_type(act); @@ -396,10 +397,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_name const //! \overload template< typename SeverityT, typename ChannelDescriptorT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_name const& severity_name, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_name, fallback_to_none(), fallback_to_none(), less(), severity_compare) }}; return result_type(act); @@ -407,10 +408,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename ChannelT, typename SeverityDescriptorT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_keyword.get_name(), fallback_to_none(), fallback_to_none(), less(), severity_compare) }}; return result_type(act); @@ -418,10 +419,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_keyword< S //! \overload template< typename ChannelDescriptorT, typename SeverityDescriptorT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_keyword.get_name(), fallback_to_none(), fallback_to_none(), less(), severity_compare) }}; return result_type(act); @@ -429,10 +430,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename SeverityT, typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_name const& severity_name, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_name, channel_placeholder.get_fallback_policy(), fallback_to_none(), less(), severity_compare) }}; return result_type(act); @@ -440,10 +441,10 @@ channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT //! \overload template< typename ChannelT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_placeholder.get_name(), fallback_to_none(), severity_placeholder.get_fallback_policy(), less(), severity_compare) }}; return result_type(act); @@ -451,10 +452,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_actor< Sev //! \overload template< typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT, typename SeverityCompareT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder, SeverityCompareT const& severity_compare) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, less, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_placeholder.get_name(), channel_placeholder.get_fallback_policy(), severity_placeholder.get_fallback_policy(), less(), severity_compare) }}; return result_type(act); @@ -474,10 +475,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_name const //! \overload template< typename SeverityT, typename ChannelDescriptorT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_name const& severity_name, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, SeverityT, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_name, fallback_to_none(), fallback_to_none(), channel_order, severity_compare) }}; return result_type(act); @@ -485,10 +486,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename ChannelT, typename SeverityDescriptorT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_keyword.get_name(), fallback_to_none(), fallback_to_none(), channel_order, severity_compare) }}; return result_type(act); @@ -496,10 +497,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_keyword< S //! \overload template< typename ChannelDescriptorT, typename SeverityDescriptorT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& channel_keyword, attribute_keyword< SeverityDescriptorT, ActorT > const& severity_keyword, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< typename ChannelDescriptorT::value_type, typename SeverityDescriptorT::value_type, fallback_to_none, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_keyword.get_name(), severity_keyword.get_name(), fallback_to_none(), fallback_to_none(), channel_order, severity_compare) }}; return result_type(act); @@ -507,10 +508,10 @@ channel_severity_filter(attribute_keyword< ChannelDescriptorT, ActorT > const& c //! \overload template< typename SeverityT, typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_name const& severity_name, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, fallback_to_none, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_name, channel_placeholder.get_fallback_policy(), fallback_to_none(), channel_order, severity_compare) }}; return result_type(act); @@ -518,10 +519,10 @@ channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT //! \overload template< typename ChannelT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_name const& channel_name, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, fallback_to_none, SeverityFallbackT, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_name, severity_placeholder.get_name(), fallback_to_none(), severity_placeholder.get_fallback_policy(), channel_order, severity_compare) }}; return result_type(act); @@ -529,10 +530,10 @@ channel_severity_filter(attribute_name const& channel_name, attribute_actor< Sev //! \overload template< typename ChannelT, typename ChannelFallbackT, typename ChannelTagT, typename SeverityT, typename SeverityFallbackT, typename SeverityTagT, template< typename > class ActorT, typename SeverityCompareT, typename ChannelOrderT > -BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > +BOOST_FORCEINLINE channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > channel_severity_filter(attribute_actor< ChannelT, ChannelFallbackT, ChannelTagT, ActorT > const& channel_placeholder, attribute_actor< SeverityT, SeverityFallbackT, SeverityTagT, ActorT > const& severity_placeholder, SeverityCompareT const& severity_compare, ChannelOrderT const& channel_order) { - typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, ChannelOrderT, SeverityCompareT, std::allocator< void >, ActorT > result_type; + typedef channel_severity_filter_actor< ChannelT, SeverityT, ChannelFallbackT, SeverityFallbackT, ChannelOrderT, SeverityCompareT, use_std_allocator, ActorT > result_type; typedef typename result_type::terminal_type terminal_type; typename result_type::base_type act = {{ terminal_type(channel_placeholder.get_name(), severity_placeholder.get_name(), channel_placeholder.get_fallback_policy(), severity_placeholder.get_fallback_policy(), channel_order, severity_compare) }}; return result_type(act); diff --git a/include/boost/log/utility/use_std_allocator.hpp b/include/boost/log/utility/use_std_allocator.hpp new file mode 100644 index 0000000000..c72912672b --- /dev/null +++ b/include/boost/log/utility/use_std_allocator.hpp @@ -0,0 +1,60 @@ +/* + * Copyright Andrey Semashev 2021. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file use_std_allocator.hpp + * \author Andrey Semashev + * \date 04.03.2021 + * + * The header defines \c use_std_allocator tag type. + */ + +#ifndef BOOST_LOG_UTILITY_USE_STD_ALLOCATOR_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_USE_STD_ALLOCATOR_HPP_INCLUDED_ + +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +#ifndef BOOST_LOG_DOXYGEN_PASS + +namespace aux { + +namespace usestdalloc_adl_block { + +struct use_std_allocator {}; + +} // namespace usestdalloc_adl_block + +} // namespace aux + +using aux::usestdalloc_adl_block::use_std_allocator; + +#else // BOOST_LOG_DOXYGEN_PASS + +/*! + * \brief Tag type that indicates that a specialization of \c std::allocator should be used for allocating memory + * + * This tag type can be used in template parameters in various components of Boost.Log. The type itself is not an allocator type. + */ +struct use_std_allocator {}; + +#endif // BOOST_LOG_DOXYGEN_PASS + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_USE_STD_ALLOCATOR_HPP_INCLUDED_ From 8a880720be5a990fdd0f864244bfff1a39a69d83 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 5 Mar 2021 14:19:34 +0300 Subject: [PATCH 126/309] Updated copyright years in the docs. --- doc/log.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/log.qbk b/doc/log.qbk index 4bfbb71995..e418ebeb52 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -2,7 +2,7 @@ [quickbook 1.5] [version v2] [authors [Semashev, Andrey]] - [copyright 2007 - 2019 Andrey Semashev] + [copyright 2007 - 2021 Andrey Semashev] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at From e50cfc3f3b13bf1b4ce9139e7848b9dd4953f678 Mon Sep 17 00:00:00 2001 From: Christoph Reiter Date: Mon, 5 Apr 2021 17:28:49 +0200 Subject: [PATCH 127/309] Stop defining __MSVCRT_VERSION__ __MSVCRT_VERSION__ is a mingw internal and shouldn't be set by the user. Setting it to something different than the toolchain provided value means the headers and crt wont match which can result in crashes and build errors. This fixes the boost build when targeting ucrt. --- include/boost/log/detail/config.hpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 7eb4d27f03..c8fce64c6e 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -17,12 +17,6 @@ #ifndef BOOST_LOG_DETAIL_CONFIG_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_CONFIG_HPP_INCLUDED_ -// This check must be before any system headers are included, or __MSVCRT_VERSION__ may get defined to 0x0600 -#if defined(__MINGW32__) && !defined(__MSVCRT_VERSION__) -// Target MinGW headers to at least MSVC 7.0 runtime by default. This will enable some useful functions. -#define __MSVCRT_VERSION__ 0x0700 -#endif - #include // Try including WinAPI config as soon as possible so that any other headers don't include Windows SDK headers From df4bc60d056a7ff37a0ec9110ddbeb364bc5c435 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 6 Apr 2021 00:59:48 +0300 Subject: [PATCH 128/309] Added a changelog entry for the removal of __MSVCRT_VERSION__. --- doc/changelog.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 249331a6dc..29140a3ad2 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -16,6 +16,7 @@ * Corrected a formal race condition in the thread-safe log record queue implementation used in the `unbounded_fifo_queue` policy of the [class_sinks_asynchronous_sink] frontend. The race could be detected by TSAN, but it was not a real problem on most current CPU architectures and compilers. ([github_issue 139]) * When copying a logger with a channel attribute (e.g. `channel_logger`), the channel attribute is now deep-copied from the original logger. This means that modifying the channel in the new logger will no longer affect the original logger. * Replaced the use of `std::allocator` in template parameters with a new tag type `boost::log::use_std_allocator` to silence libc++ warnings about the former being deprecated in C++17 and later. The tag indicates that the instantiated template should be using a specialization of `std::allocator` internally to allocate dynamic memory, so the change has no functional effect. ([github_issue 141]) +* Boost.Log no longer defines `__MSVCRT_VERSION__` macro on MinGW and MinGW-w64. This macro is used to select the target C runtime library. Defining this macro caused incompatibility with UCRT, which is available as an option in recent MinGW-w64. ([pull_request 149]) [heading 2.20, Boost 1.75] From a65c02278cbb9f3c7b98d30ee468b7cb2ba2d0e5 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 28 May 2021 19:08:12 +0300 Subject: [PATCH 129/309] Removed compile-time dependency on Boost.Locale. Use a simple code unit analysis to detect leading UTF-16 surrogates to find UTF-16 character boundaries. --- .../log/detail/attachable_sstream_buf.hpp | 30 ++++++++++--------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/include/boost/log/detail/attachable_sstream_buf.hpp b/include/boost/log/detail/attachable_sstream_buf.hpp index 1077589983..6a4fc5cb76 100644 --- a/include/boost/log/detail/attachable_sstream_buf.hpp +++ b/include/boost/log/detail/attachable_sstream_buf.hpp @@ -22,8 +22,8 @@ #include #include #include +#include #include -#include #include #include @@ -278,12 +278,12 @@ class basic_ostringstreambuf : size_type length_until_boundary(const char_type* s, size_type n, size_type max_size) const { BOOST_ASSERT(max_size <= n); - return length_until_boundary(s, n, max_size, boost::integral_constant< bool, sizeof(char_type) == 1u >()); + return length_until_boundary(s, n, max_size, boost::integral_constant< std::size_t, sizeof(char_type) >()); } private: //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size - size_type length_until_boundary(const char_type* s, size_type, size_type max_size, boost::true_type) const + size_type length_until_boundary(const char_type* s, size_type, size_type max_size, boost::integral_constant< std::size_t, 1u >) const { std::locale loc = this->getloc(); std::codecvt< wchar_t, char, std::mbstate_t > const& fac = std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc); @@ -292,29 +292,31 @@ class basic_ostringstreambuf : } //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size - static size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, boost::false_type) + static size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, boost::integral_constant< std::size_t, 2u >) { - // Note: Although it's not required to be true for wchar_t, here we assume that the string has Unicode encoding. + // Note: Although it's not required to be true for wchar_t, here we assume that the string has Unicode encoding (UTF-16 or UCS-2). // Compilers use some version of Unicode for wchar_t on all tested platforms, and std::locale doesn't offer a way // to find the character boundary for character types other than char anyway. - typedef boost::locale::utf::utf_traits< char_type > utf_traits; - size_type pos = max_size; while (pos > 0u) { --pos; - if (utf_traits::is_lead(s[pos])) - { - const char_type* p = s + pos; - boost::locale::utf::code_point cp = utf_traits::decode(p, s + n); - if (boost::locale::utf::is_valid_codepoint(cp) && p <= (s + max_size)) - return static_cast< size_type >(p - s); - } + uint_fast16_t c = static_cast< uint_fast16_t >(s[pos]); + // Check if this is a leading surrogate + if ((c & 0xFC00u) != 0xD800u) + return pos + 1u; } return 0u; } + //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size + static size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, boost::integral_constant< std::size_t, 4u >) + { + // In UTF-32 and UCS-4 one code point is encoded as one code unit + return max_size; + } + //! Copy constructor (closed) BOOST_DELETED_FUNCTION(basic_ostringstreambuf(basic_ostringstreambuf const& that)) //! Assignment (closed) From d2061419501bdd6761e9380ed5b91233f6c4e67e Mon Sep 17 00:00:00 2001 From: Fabrice Fontaine Date: Fri, 21 May 2021 21:30:04 +0200 Subject: [PATCH 130/309] src/event.cpp: fix build on riscv32 riscv32 fails to build because __NR_futex is not defined on this architecture: libs/log/src/event.cpp: In member function 'void boost::log::v2_mt_posix::aux::futex_based_event::wait()': libs/log/src/event.cpp:38:29: error: '__NR_futex' was not declared in this scope 38 | #define BOOST_LOG_SYS_FUTEX __NR_futex | ^~~~~~~~~~ Fixes: - http://autobuild.buildroot.org/results/8c8135fd7c0517c66c9b3975c494da6d7934cc1b Signed-off-by: Fabrice Fontaine --- src/event.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/event.cpp b/src/event.cpp index 5485154d72..f576648c6a 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -34,8 +34,13 @@ // Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex #if defined(SYS_futex) #define BOOST_LOG_SYS_FUTEX SYS_futex -#else +#elif defined(__NR_futex) #define BOOST_LOG_SYS_FUTEX __NR_futex +// riscv32 defines a different system call instead of __NR_futex +#elif defined(__NR_futex_time64) +#define BOOST_LOG_SYS_FUTEX __NR_futex_time64 +#else +#error "Unable to find a suitable futex" #endif #if defined(FUTEX_WAIT_PRIVATE) From d723878e72da9c0b472dfaf4442a66a496e4282c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 29 May 2021 17:10:07 +0300 Subject: [PATCH 131/309] Added release notes about fixing compilation on riscv32. (#150) Closes https://github.com/boostorg/log/pull/150. --- doc/changelog.qbk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 29140a3ad2..fcc0c467e5 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.22, Boost 1.77] + +[*Bug fixes:] + +* Fixed compilation on Linux for riscv32 target. ([pull_request 150]) + [heading 2.21, Boost 1.76] [*Bug fixes:] From affdb2132cc3749b1d1d1907fbdd2c4b5bf42f9e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 16 Jul 2021 14:47:57 +0300 Subject: [PATCH 132/309] Corrected a typo in a comment. Closes https://github.com/boostorg/log/issues/154. --- include/boost/log/trivial.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/log/trivial.hpp b/include/boost/log/trivial.hpp index 7fb896ac36..50df36d663 100644 --- a/include/boost/log/trivial.hpp +++ b/include/boost/log/trivial.hpp @@ -91,7 +91,7 @@ typedef sources::severity_logger< severity_level > logger_type; /*! * \brief Trivial logger tag * - * This tag can be used to acquire the logger that is used with lrivial logging macros. + * This tag can be used to acquire the logger that is used with trivial logging macros. * This may be useful when the logger is used with other macros which require a logger. */ struct logger From 9fe832c344e645d82a902a8d465e0b1e8ef6bc77 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 20 Jul 2021 01:03:53 +0300 Subject: [PATCH 133/309] Add ios_base::ate when ios_base::app is specified for text_file_backend. This ensures that the writing position is actual immediately after the log file is opened for appending. This fixes incorrect accounting for the initial file size with MSVC and possibly other compilers. Closes https://github.com/boostorg/log/issues/151. --- doc/changelog.qbk | 1 + src/text_file_backend.cpp | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index fcc0c467e5..d5d525ba63 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Fixed compilation on Linux for riscv32 target. ([pull_request 150]) +* Setting `std::ios_base::app` file open mode in [link log.detailed.sink_backends.text_file `text_file_backend`] now also implies `std::ios_base::ate`. This fixes incorrect accounting for the initial size of the log file opened for appending. ([github_issue 151]) [heading 2.21, Boost 1.76] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index a0688c22f5..8c03dda313 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1513,7 +1513,9 @@ BOOST_LOG_API void text_file_backend::set_open_mode(std::ios_base::openmode mode { mode |= std::ios_base::out; mode &= ~std::ios_base::in; - if ((mode & (std::ios_base::trunc | std::ios_base::app)) == 0) + if ((mode & std::ios_base::app) != 0) + mode |= std::ios_base::ate; // we need to seek to end after opening the file to obtain its size + else mode |= std::ios_base::trunc; m_pImpl->m_FileOpenMode = mode; } From 3cbc2585c3b7ff5d884a6c337a99525b57fa184b Mon Sep 17 00:00:00 2001 From: YunQiang Su Date: Thu, 22 Jul 2021 15:58:08 +0800 Subject: [PATCH 134/309] rename mips1 to mips In fact mips1 is now used for all mips revisions. --- build/log-arch-config.jam | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/log-arch-config.jam b/build/log-arch-config.jam index 2a053d5685..89ecee4051 100644 --- a/build/log-arch-config.jam +++ b/build/log-arch-config.jam @@ -56,9 +56,9 @@ rule deduce-architecture ( properties * ) { return arm ; } - else if [ configure.builds /boost/architecture//mips1 : $(properties) : mips1 ] + else if [ configure.builds /boost/architecture//mips : $(properties) : mips ] { - return mips1 ; + return mips ; } else if [ configure.builds /boost/architecture//power : $(properties) : power ] { From 783a4924e43dee42a68400693470fe69691722b1 Mon Sep 17 00:00:00 2001 From: jzmaddock Date: Thu, 19 Aug 2021 16:38:08 +0100 Subject: [PATCH 135/309] Update configuration logic to account for deprecation of . --- include/boost/log/detail/config.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index c8fce64c6e..4d3a727ac8 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -98,10 +98,12 @@ # define BOOST_LOG_BROKEN_CONSTANT_EXPRESSIONS #endif -#if defined(BOOST_NO_CXX11_HDR_CODECVT) +#if (defined(BOOST_NO_CXX11_HDR_CODECVT) && (BOOST_CXX_VERSION < 201700)) || (defined(_MSVC_STL_VERSION) && (_MSVC_STL_VERSION < 142)) // The compiler does not support std::codecvt and std::codecvt specializations. // The BOOST_NO_CXX11_HDR_CODECVT means there's no usable , which is slightly different from this macro. // But in order for to be implemented the std::codecvt specializations have to be implemented as well. + // We need to check the C++ version as well, since is deprecated from C++17 onwards which may cause + // BOOST_NO_CXX11_HDR_CODECVT to be set, even though std::codecvt in is just fine. # define BOOST_LOG_NO_CXX11_CODECVT_FACETS #endif From 13b848b47ec786bacb3194fc2afacf580b2e5093 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 20 Aug 2021 01:36:57 +0300 Subject: [PATCH 136/309] Added a release note for #159. --- doc/changelog.qbk | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index d5d525ba63..7fb65a18f7 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.23, Boost 1.78] + +[*General changes:] + +* Updated detection of `std::codecvt` specializations for `char16_t` and `char32_t` for compatibility with C++17 and later. ([pull_request 159]) + [heading 2.22, Boost 1.77] [*Bug fixes:] From d989c4778439ea1457f6ee4a9cec0a1638fe4a00 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 20 Aug 2021 11:25:02 +0300 Subject: [PATCH 137/309] Corrected C++17 version macro check. --- include/boost/log/detail/config.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 4d3a727ac8..84b194e13c 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -98,7 +98,7 @@ # define BOOST_LOG_BROKEN_CONSTANT_EXPRESSIONS #endif -#if (defined(BOOST_NO_CXX11_HDR_CODECVT) && (BOOST_CXX_VERSION < 201700)) || (defined(_MSVC_STL_VERSION) && (_MSVC_STL_VERSION < 142)) +#if (defined(BOOST_NO_CXX11_HDR_CODECVT) && BOOST_CXX_VERSION < 201703) || (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142) // The compiler does not support std::codecvt and std::codecvt specializations. // The BOOST_NO_CXX11_HDR_CODECVT means there's no usable , which is slightly different from this macro. // But in order for to be implemented the std::codecvt specializations have to be implemented as well. From 5ed0fc4b4be54b0c42071388f5d41056db3f5300 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 12 Sep 2021 20:36:19 +0300 Subject: [PATCH 138/309] Removed Travis CI config. Since Travis CI no longer runs free jobs for open source projects, we are switching to GitHub Actions instead. --- .travis.yml | 398 ---------------------------------------------------- 1 file changed, 398 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 32eab182e0..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,398 +0,0 @@ -# Copyright 2019 Andrey Semashev -# Distributed under the Boost Software License, Version 1.0. -# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) - -language: cpp - -sudo: false - -python: "2.7" - -branches: - only: - - master - - develop - - /feature\/.*/ - -env: - matrix: - - BOGUS_JOB=true - -matrix: - - exclude: - - env: BOGUS_JOB=true - - include: -# gcc, Linux - - os: linux - dist: focal - compiler: gcc - env: TOOLSET=gcc COMPILER=g++ CXXSTD=03,11 EXTRA_TESTS=1 - - - os: linux - dist: trusty - compiler: gcc-4.7 - env: TOOLSET=gcc COMPILER=g++-4.7 CXXSTD=03,11 - addons: - apt: - packages: - - g++-4.7 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-4.8 - env: TOOLSET=gcc COMPILER=g++-4.8 CXXSTD=03,11 - addons: - apt: - packages: - - g++-4.8 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-4.9 - env: TOOLSET=gcc COMPILER=g++-4.9 CXXSTD=03,11 - addons: - apt: - packages: - - g++-4.9 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-5 - env: TOOLSET=gcc COMPILER=g++-5 CXXSTD=03,11,14 - addons: - apt: - packages: - - g++-5 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-6 - env: TOOLSET=gcc COMPILER=g++-6 CXXSTD=03,11,14,1z - addons: - apt: - packages: - - g++-6 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-7 - env: TOOLSET=gcc COMPILER=g++-7 CXXSTD=03,11,14,17 - addons: - apt: - packages: - - g++-7 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: xenial - compiler: gcc-8 - env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - g++-8 - sources: - - ubuntu-toolchain-r-test - - - os: linux - dist: bionic - compiler: gcc-9 - env: TOOLSET=gcc COMPILER=g++-9 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - g++-9 - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - - os: linux - dist: bionic - compiler: gcc-10 - env: TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 - addons: - apt: - packages: - - g++-10 - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - - os: linux - dist: bionic - compiler: gcc-UBSAN - env: UBSAN=1 TOOLSET=gcc COMPILER=g++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 LINKFLAGS=-fuse-ld=gold - addons: - apt: - packages: - - g++-10 - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - -# clang, Linux - - os: linux - dist: trusty - compiler: clang-3.5 - env: TOOLSET=clang COMPILER=clang++-3.5 CXXSTD=03,11 - addons: - apt: - packages: - - clang-3.5 - - libstdc++-4.9-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.5 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: trusty - compiler: clang-3.6 - env: TOOLSET=clang COMPILER=clang++-3.6 CXXSTD=03,11 - addons: - apt: - packages: - - clang-3.6 - - libstdc++-5-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.6 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: trusty - compiler: clang-3.7 - env: TOOLSET=clang COMPILER=clang++-3.7 CXXSTD=03,11 - addons: - apt: - packages: - - clang-3.7 - - libstdc++-5-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/trusty/ llvm-toolchain-trusty-3.7 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-3.8 - env: TOOLSET=clang COMPILER=clang++-3.8 CXXSTD=03,11,14,1z - addons: - apt: - packages: - - clang-3.8 - - libstdc++-6-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.8 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-3.9 - env: TOOLSET=clang COMPILER=clang++-3.9 CXXSTD=03,11,14,1z - addons: - apt: - packages: - - clang-3.9 - - libstdc++-6-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-3.9 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-4 - env: TOOLSET=clang COMPILER=clang++-4.0 CXXSTD=03,11,14,1z - addons: - apt: - packages: - - clang-4.0 - - libstdc++-6-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-4.0 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-5 - env: TOOLSET=clang COMPILER=clang++-5.0 CXXSTD=03,11,14,1z - addons: - apt: - packages: - - clang-5.0 - - libstdc++-7-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-6 - env: TOOLSET=clang COMPILER=clang++-6.0 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - clang-6.0 - - libstdc++-8-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-7 - env: TOOLSET=clang COMPILER=clang++-7 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - clang-7 - - libstdc++-8-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: xenial - compiler: clang-8 - env: TOOLSET=clang COMPILER=clang++-8 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - clang-8 - - libstdc++-8-dev - sources: - - ubuntu-toolchain-r-test - - sourceline: "deb http://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: bionic - compiler: clang-9 - env: TOOLSET=clang COMPILER=clang++-9 CXXSTD=03,11,14,17,2a - addons: - apt: - packages: - - clang-9 - - libstdc++-9-dev - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/bionic/ llvm-toolchain-bionic-9 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: focal - compiler: clang-10 - env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 - addons: - apt: - packages: - - clang-10 - - libstdc++-9-dev - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: focal - compiler: clang-libc++ - env: TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" - addons: - apt: - packages: - - clang-10 - - libc++-10-dev - - libc++abi-10-dev - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: focal - compiler: clang-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 - addons: - apt: - packages: - - clang-10 - - libstdc++-9-dev - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - - - os: linux - dist: focal - compiler: clang-libc++-UBSAN - env: UBSAN=1 TOOLSET=clang COMPILER=clang++-10 CXXSTD=03,11,14,17,20 UBSAN_OPTIONS=print_stacktrace=1 CXXFLAGS="-stdlib=libc++" LINKFLAGS="-stdlib=libc++" - addons: - apt: - packages: - - clang-10 - - libc++-10-dev - - libc++abi-10-dev - sources: - - sourceline: "ppa:ubuntu-toolchain-r/test" - - sourceline: "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main" - key_url: "https://apt.llvm.org/llvm-snapshot.gpg.key" - -# clang, OS X -# OS X jobs time out for some reason -# - os: osx -# env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11 EXTRA_TESTS=1 -# osx_image: xcode10.1 -# -# - os: osx -# env: TOOLSET=clang COMPILER=clang++ CXXSTD=14,1z -# osx_image: xcode10.1 - -# clang, FreeBSD - - os: freebsd - env: TOOLSET=clang COMPILER=clang++ CXXSTD=03,11,14,17,2a - -install: - - GIT_FETCH_JOBS=8 - - BOOST_BRANCH=develop - - if [ "$TRAVIS_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi - - cd .. - - git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root - - cd boost-root - - git submodule init tools/boostdep - - git submodule init tools/build - - git submodule init tools/boost_install - - git submodule init libs/headers - - git submodule init libs/config - - git submodule update --jobs $GIT_FETCH_JOBS - - cp -r $TRAVIS_BUILD_DIR/* libs/log - - if [ -n "$EXTRA_TESTS" ]; then DEPINST_ARG_INCLUDE_EXAMPLES="--include example"; fi - - python tools/boostdep/depinst/depinst.py $DEPINST_ARG_INCLUDE_EXAMPLES --git_args "--jobs $GIT_FETCH_JOBS" log - - ./bootstrap.sh - - ./b2 headers - -script: - - |- - echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam - - BUILD_JOBS=`(nproc || sysctl -n hw.ncpu) 2> /dev/null` - - if [ -z "$EXTRA_TESTS" ]; then export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1; export BOOST_LOG_TEST_WITHOUT_EXAMPLES=1; fi - - ./b2 -j $BUILD_JOBS libs/log/test toolset=$TOOLSET cxxstd=$CXXSTD ${UBSAN:+cxxflags=-fsanitize=undefined cxxflags=-fno-sanitize-recover=undefined linkflags=-fsanitize=undefined define=UBSAN=1 debug-symbols=on visibility=global} ${CXXFLAGS:+cxxflags="$CXXFLAGS"} ${LINKFLAGS:+linkflags="$LINKFLAGS"} - -notifications: - email: - on_success: always From 8a25296c72e4851a38a3e2b1c994cd6c73ec6388 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 12 Sep 2021 20:37:59 +0300 Subject: [PATCH 139/309] Added GitHub Actions CI config. --- .github/workflows/ci.yml | 426 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 426 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..cf103e48c9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,426 @@ +# Copyright 2021 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) + +name: CI + +on: + pull_request: + push: + branches: + - master + - develop + - feature/** + +concurrency: + group: ${{format('{0}:{1}', github.repository, github.ref)}} + cancel-in-progress: true + +env: + GIT_FETCH_JOBS: 8 + NET_RETRY_COUNT: 5 + DEFAULT_BUILD_VARIANT: debug,release + +jobs: + posix: + defaults: + run: + shell: bash + + strategy: + fail-fast: false + matrix: + include: + # Linux, gcc + - toolset: gcc-4.4 + cxxstd: "98,0x" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - g++-4.4 + sources: + - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-4.6 + cxxstd: "03,0x" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - g++-4.6 + sources: + - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-4.7 + cxxstd: "03,11" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - g++-4.7 + - toolset: gcc-4.8 + cxxstd: "03,11" + os: ubuntu-18.04 + install: + - g++-4.8 + - toolset: gcc-4.9 + cxxstd: "03,11" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - g++-4.9 + extra_tests: 1 + - toolset: gcc-5 + cxxstd: "03,11,14,1z" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - g++-5 + - toolset: gcc-6 + cxxstd: "03,11,14,1z" + os: ubuntu-18.04 + install: + - g++-6 + - toolset: gcc-7 + cxxstd: "03,11,14,17" + os: ubuntu-18.04 + install: + - g++-7 + - toolset: gcc-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-18.04 + install: + - g++-8 + - toolset: gcc-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-18.04 + install: + - g++-9 + - toolset: gcc-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - g++-10 + - toolset: gcc-11 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - g++-11 + sources: + - "ppa:ubuntu-toolchain-r/test" + - name: UBSAN + toolset: gcc-11 + cxxstd: "03,11,14,17,20" + ubsan: 1 + build_variant: debug + os: ubuntu-20.04 + install: + - g++-11 + sources: + - "ppa:ubuntu-toolchain-r/test" + + # Linux, clang + - toolset: clang + compiler: clang++-3.5 + cxxstd: "03,11" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - clang-3.5 + - toolset: clang + compiler: clang++-3.6 + cxxstd: "03,11,14" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - clang-3.6 + - toolset: clang + compiler: clang++-3.7 + cxxstd: "03,11,14" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - clang-3.7 + - toolset: clang + compiler: clang++-3.8 + cxxstd: "03,11,14" + os: ubuntu-20.04 + container: ubuntu:16.04 + install: + - clang-3.8 + - toolset: clang + compiler: clang++-3.9 + cxxstd: "03,11,14" + os: ubuntu-18.04 + install: + - clang-3.9 + - toolset: clang + compiler: clang++-4.0 + cxxstd: "03,11,14" + os: ubuntu-18.04 + install: + - clang-4.0 + - toolset: clang + compiler: clang++-5.0 + cxxstd: "03,11,14,1z" + os: ubuntu-18.04 + install: + - clang-5.0 + - toolset: clang + compiler: clang++-6.0 + cxxstd: "03,11,14,17" + os: ubuntu-18.04 + install: + - clang-6.0 + - toolset: clang + compiler: clang++-7 + cxxstd: "03,11,14,17" + os: ubuntu-18.04 + install: + - clang-7 + # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode + - toolset: clang + compiler: clang++-8 + cxxstd: "03,11,14,17,2a" + os: ubuntu-18.04 + install: + - clang-8 + - g++-7 + gcc_toolchain: 7 + - toolset: clang + compiler: clang++-9 + cxxstd: "03,11,14,17,2a" + os: ubuntu-20.04 + install: + - clang-9 + - toolset: clang + compiler: clang++-10 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-10 + - toolset: clang + compiler: clang++-11 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-11 + - toolset: clang + compiler: clang++-12 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-12 + - toolset: clang + compiler: clang++-12 + cxxstd: "03,11,14,17,20" + os: ubuntu-20.04 + install: + - clang-12 + - libc++-12-dev + - libc++abi-12-dev + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + - name: UBSAN + toolset: clang + compiler: clang++-12 + cxxstd: "03,11,14,17,20" + cxxflags: -stdlib=libc++ + linkflags: -stdlib=libc++ + ubsan: 1 + build_variant: debug + os: ubuntu-20.04 + install: + - clang-12 + - libc++-12-dev + - libc++abi-12-dev + + - toolset: clang + cxxstd: "03,11,14,17,2a" + os: macos-10.15 + + # - name: CMake tests + # cmake_tests: 1 + # os: ubuntu-20.04 + + runs-on: ${{matrix.os}} + container: ${{matrix.container}} + + steps: + - name: Setup environment + run: | + if [ -f "/etc/debian_version" ] + then + echo "DEBIAN_FRONTEND=noninteractive" >> $GITHUB_ENV + export DEBIAN_FRONTEND=noninteractive + fi + if [ -n "${{matrix.container}}" ] + then + echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV + if [ -f "/etc/debian_version" ] + then + apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ python python3 git cmake + fi + fi + git config --global pack.threads 0 + + - uses: actions/checkout@v2 + + - name: Install packages + if: matrix.install + run: | + SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}}) + SOURCES=(${{join(matrix.sources, ' ')}}) + for key in "${SOURCE_KEYS[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + wget -O - "$key" | sudo apt-key add - && break || sleep 2 + done + done + if [ ${#SOURCES[@]} -gt 0 ] + then + APT_ADD_REPO_COMMON_ARGS=("-y") + APT_ADD_REPO_HAS_SOURCE_ARGS=0 + SOFTWARE_PROPERTIES_VERSION="$(dpkg-query --showformat='${Version}' --show software-properties-common)" + if dpkg --compare-versions "$SOFTWARE_PROPERTIES_VERSION" ge "0.96.24.20" + then + APT_ADD_REPO_COMMON_ARGS+=("-n") + fi + if dpkg --compare-versions "$SOFTWARE_PROPERTIES_VERSION" ge "0.98.10" + then + APT_ADD_REPO_HAS_SOURCE_ARGS=1 + fi + for source in "${SOURCES[@]}" + do + for i in {1..$NET_RETRY_COUNT} + do + APT_ADD_REPO_ARGS=("${APT_ADD_REPO_COMMON_ARGS[@]}") + if [ $APT_ADD_REPO_HAS_SOURCE_ARGS -ne 0 ] + then + case "$source" in + "ppa:"*) + APT_ADD_REPO_ARGS+=("-P") + ;; + "deb "*) + APT_ADD_REPO_ARGS+=("-S") + ;; + *) + APT_ADD_REPO_ARGS+=("-U") + ;; + esac + fi + APT_ADD_REPO_ARGS+=("$source") + sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 + done + done + fi + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT update + sudo apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y ${{join(matrix.install, ' ')}} + + - name: Setup GCC Toolchain + if: matrix.gcc_toolchain + run: | + GCC_TOOLCHAIN_ROOT="$HOME/gcc-toolchain" + echo "GCC_TOOLCHAIN_ROOT=\"$GCC_TOOLCHAIN_ROOT\"" >> $GITHUB_ENV + MULTIARCH_TRIPLET="$(dpkg-architecture -qDEB_HOST_MULTIARCH)" + mkdir -p "$GCC_TOOLCHAIN_ROOT" + ln -s /usr/include "$GCC_TOOLCHAIN_ROOT/include" + ln -s /usr/bin "$GCC_TOOLCHAIN_ROOT/bin" + mkdir -p "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET" + ln -s "/usr/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" "$GCC_TOOLCHAIN_ROOT/lib/gcc/$MULTIARCH_TRIPLET/${{matrix.gcc_toolchain}}" + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=() + GIT_VERSION="$(git --version | sed -e 's/git version //')" + if $(dpkg --compare-versions "$GIT_VERSION" ge 2.8.0) + then + DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") + fi + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs/$LIBRARY + cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + git submodule update --init tools/boostdep + if [ -n "${{matrix.extra_tests}}" ] + then + DEPINST_ARGS+=("--include" "example") + fi + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + if [ -z "${{matrix.cmake_tests}}" ] + then + ./bootstrap.sh + ./b2 headers + if [ -n "${{matrix.compiler}}" -o -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n "using ${{matrix.toolset}} : : ${{matrix.compiler}}" > ~/user-config.jam + if [ -n "$GCC_TOOLCHAIN_ROOT" ] + then + echo -n " : \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\" \"--gcc-toolchain=$GCC_TOOLCHAIN_ROOT\"" >> ~/user-config.jam + fi + echo " ;" >> ~/user-config.jam + fi + fi + + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root + if [ -z "${{matrix.extra_tests}}" ] + then + export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 + export BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 + fi + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.ubsan}}" ] + then + export UBSAN_OPTIONS="print_stacktrace=1" + B2_ARGS+=("cxxflags=-fsanitize=undefined -fno-sanitize-recover=undefined" "linkflags=-fsanitize=undefined -fuse-ld=gold" "define=UBSAN=1" "debug-symbols=on" "visibility=global") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + B2_ARGS+=("libs/$LIBRARY/test") + ./b2 "${B2_ARGS[@]}" + + - name: Run CMake tests + if: matrix.cmake_tests + run: | + cd ../boost-root + mkdir __build_static__ && cd __build_static__ + cmake ../libs/$LIBRARY/test/test_cmake + cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS + cd .. + mkdir __build_shared__ && cd __build_shared__ + cmake -DBUILD_SHARED_LIBS=On ../libs/$LIBRARY/test/test_cmake + cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS From f65282044a91d0d74884a02ba100a152644093e1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 12 Sep 2021 20:40:06 +0300 Subject: [PATCH 140/309] Replaced Travis CI links with GitHub Actions in README.md. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b8827baf6c..6fc4659ee9 100644 --- a/README.md +++ b/README.md @@ -22,10 +22,10 @@ Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/bo ### Build status -Branch | Travis CI | AppVeyor | Test Matrix | Dependencies | -:-------------: | --------- | -------- | ----------- | ------------ | -[`master`](https://github.com/boostorg/log/tree/master) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=master)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) -[`develop`](https://github.com/boostorg/log/tree/develop) | [![Travis CI](https://travis-ci.org/boostorg/log.svg?branch=develop)](https://travis-ci.org/boostorg/log) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) +Branch | GitHub Actions | AppVeyor | Test Matrix | Dependencies | +:-------------: | -------------- | -------- | ----------- | ------------ | +[`master`](https://github.com/boostorg/log/tree/master) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/log/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) +[`develop`](https://github.com/boostorg/log/tree/develop) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/log/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) ### License From ef7476d0064a2645e3caced701006de1ca263775 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 12 Sep 2021 23:27:02 +0300 Subject: [PATCH 141/309] Disable Boost.Xpressive tests on gcc 10+ in C++03 mode. The compiler ICEs on Boost.Xpressive code in C++03 mode. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102293 --- test/run/filt_matches_xpressive.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/run/filt_matches_xpressive.cpp b/test/run/filt_matches_xpressive.cpp index 44ee0a618c..c52d163f83 100644 --- a/test/run/filt_matches_xpressive.cpp +++ b/test/run/filt_matches_xpressive.cpp @@ -12,6 +12,12 @@ * \brief This header contains tests for the \c matches filter with Boost.Xpressive backend. */ +#include + +// gcc 10 and 11 are known to ICE on Boost.Xpressive code in C++03 mode, see: +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102293 +#if !defined(BOOST_GCC) || defined(BOOST_GCC_CXX11) || BOOST_GCC < 100000 + #define BOOST_TEST_MODULE filt_matches_xpressive #include @@ -105,3 +111,12 @@ BOOST_AUTO_TEST_CASE(composition_check) BOOST_CHECK(!f(values2)); BOOST_CHECK(f(values3)); } + +#else // !defined(BOOST_GCC) || BOOST_GCC < 100000 + +int main() +{ + return 0; +} + +#endif // !defined(BOOST_GCC) || BOOST_GCC < 100000 From 4d78a1e20163c97bf998c278fbf3cf8934b18a79 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 12 Sep 2021 23:33:00 +0300 Subject: [PATCH 142/309] Run tests in debug mode on MacOS. The tests are tunning extremely long on MacOS, so cut the time in half by disabling the release build. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index cf103e48c9..c0f3b7bc2c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -234,6 +234,7 @@ jobs: - toolset: clang cxxstd: "03,11,14,17,2a" + build_variant: debug os: macos-10.15 # - name: CMake tests From 2f058c6d8c3867471d0973b6f57127b5076a4f7f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 04:20:12 +0300 Subject: [PATCH 143/309] Disabled C++20 build on MacOS to reduce CI run time. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0f3b7bc2c..8afb35399c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,7 +233,7 @@ jobs: - libc++abi-12-dev - toolset: clang - cxxstd: "03,11,14,17,2a" + cxxstd: "03,11,14,17" build_variant: debug os: macos-10.15 From 6bbe7b90e3b4b0a3fcf5a9a097f318be850356c7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 17:56:34 +0300 Subject: [PATCH 144/309] Generate unique IPC queue name in util_ipc_reliable_mq test. This allows to run multiple instances of the test concurrently in GitHub Actions CI, e.g. debug and release. This was also reported in https://github.com/boostorg/log/issues/162. Closes https://github.com/boostorg/log/issues/162. --- test/run/util_ipc_reliable_mq.cpp | 42 ++++++++++++++++++++++++++++--- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index 3886572933..7ff619c4ae 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -24,16 +24,23 @@ #include #include #include +#include +#if defined(BOOST_WINDOWS) +#include +#else +#include +#endif #include #include #include #include +#include #include #include #include #if !defined(BOOST_LOG_NO_THREADS) #include -#include +#include #include #include #include @@ -43,12 +50,41 @@ typedef boost::log::ipc::reliable_message_queue queue_t; typedef queue_t::size_type size_type; -const boost::log::ipc::object_name ipc_queue_name(boost::log::ipc::object_name::session, "boost_log_test_ipc_reliable_mq"); +inline boost::log::ipc::object_name generate_ipc_queue_name() +{ + // Make sure IPC queue name is specific to the current process. This is useful when running + // multiple instances of the test concurrently (e.g. debug and release). + std::ostringstream strm; + strm << "boost_log_test_ipc_reliable_mq" +#if defined(BOOST_WINDOWS) + << +boost::winapi::GetCurrentProcessId(); +#else + << +getpid(); +#endif + return boost::log::ipc::object_name(boost::log::ipc::object_name::session, strm.str()); +} + +const boost::log::ipc::object_name ipc_queue_name = generate_ipc_queue_name(); const unsigned int capacity = 512; const size_type block_size = 1024; const char message1[] = "Hello, world!"; const char message2[] = "Hello, the brand new world!"; +struct queue_cleanup +{ + ~queue_cleanup() + { + try + { + queue_t::remove(ipc_queue_name); + } + catch (...) + { + } + } +} +const queue_cleanup_guard = {}; + BOOST_AUTO_TEST_CASE(basic_functionality) { // Default constructor. @@ -57,7 +93,7 @@ BOOST_AUTO_TEST_CASE(basic_functionality) BOOST_CHECK(!queue.is_open()); } - // Do a remove in case if a previous test failed + // Do a remove in case if a previous test crashed queue_t::remove(ipc_queue_name); // Opening a non-existing queue From d1aaf951a9cc1f120cbc84962657d6724d2e6d59 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 17:59:08 +0300 Subject: [PATCH 145/309] Further reduced the number of tested configs on MacOS in GHA. This is another attempt to work around the CI job hanging, as reported in https://github.com/actions/runner/issues/1326. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8afb35399c..400115f928 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -233,7 +233,7 @@ jobs: - libc++abi-12-dev - toolset: clang - cxxstd: "03,11,14,17" + cxxstd: "03,11" build_variant: debug os: macos-10.15 From 77a70b7e81027d333290808832464c3dd0b78163 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 18:02:57 +0300 Subject: [PATCH 146/309] Added a timeout for GHA jobs. --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 400115f928..7655fbbe95 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -241,6 +241,7 @@ jobs: # cmake_tests: 1 # os: ubuntu-20.04 + timeout-minutes: 180 runs-on: ${{matrix.os}} container: ${{matrix.container}} From 1ff5a815d481c7f779770b7f29696f1ec805b9c1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 18:13:24 +0300 Subject: [PATCH 147/309] Fixed include. --- test/run/util_ipc_reliable_mq.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index 7ff619c4ae..f82b163ce2 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -24,7 +24,7 @@ #include #include #include -#include +#include #if defined(BOOST_WINDOWS) #include #else From 5c6f3f9ddc8ab33c5ac6172a3b4f58dd9e6bbc68 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 19:37:21 +0300 Subject: [PATCH 148/309] Added asserts to IPC queue impl to enforce preconditions. --- src/posix/ipc_reliable_message_queue.cpp | 4 ++++ src/windows/ipc_reliable_message_queue.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index 07d61fa55f..1451b2a4f6 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -223,6 +223,7 @@ struct reliable_message_queue::implementation m_stop(false), m_name(name) { + BOOST_ASSERT(block_size >= block_header::get_header_overhead()); create_region(capacity, block_size); } @@ -244,6 +245,7 @@ struct reliable_message_queue::implementation m_stop(false), m_name(name) { + BOOST_ASSERT(block_size >= block_header::get_header_overhead()); boost::interprocess::offset_t shmem_size = 0; if (!m_shared_memory.get_size(shmem_size) || shmem_size == 0) create_region(capacity, block_size); @@ -614,6 +616,7 @@ struct reliable_message_queue::implementation const uint32_t capacity = hdr->m_capacity; const size_type block_size = hdr->m_block_size; uint32_t pos = hdr->m_put_pos; + BOOST_ASSERT(pos < capacity); block_header* block = hdr->get_block(pos); block->m_size = message_size; @@ -648,6 +651,7 @@ struct reliable_message_queue::implementation const uint32_t capacity = hdr->m_capacity; const size_type block_size = hdr->m_block_size; uint32_t pos = hdr->m_get_pos; + BOOST_ASSERT(pos < capacity); block_header* block = hdr->get_block(pos); size_type message_size = block->m_size; diff --git a/src/windows/ipc_reliable_message_queue.cpp b/src/windows/ipc_reliable_message_queue.cpp index d99d091d1f..00bc8a3f32 100644 --- a/src/windows/ipc_reliable_message_queue.cpp +++ b/src/windows/ipc_reliable_message_queue.cpp @@ -216,6 +216,7 @@ struct reliable_message_queue::implementation m_block_size_log2(0u), m_name(name) { + BOOST_ASSERT(block_size >= block_header::get_header_overhead()); const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str()); const std::size_t shmem_size = estimate_region_size(capacity, block_size); m_shared_memory.create(wname.c_str(), shmem_size, perms); @@ -239,6 +240,7 @@ struct reliable_message_queue::implementation m_block_size_log2(0u), m_name(name) { + BOOST_ASSERT(block_size >= block_header::get_header_overhead()); const std::wstring wname = boost::log::aux::utf8_to_utf16(name.c_str()); const std::size_t shmem_size = estimate_region_size(capacity, block_size); const bool created = m_shared_memory.create_or_open(wname.c_str(), shmem_size, perms); @@ -563,6 +565,7 @@ struct reliable_message_queue::implementation const uint32_t capacity = hdr->m_capacity; const size_type block_size = hdr->m_block_size; uint32_t pos = hdr->m_put_pos; + BOOST_ASSERT(pos < capacity); block_header* block = hdr->get_block(pos); block->m_size = message_size; @@ -597,6 +600,7 @@ struct reliable_message_queue::implementation const uint32_t capacity = hdr->m_capacity; const size_type block_size = hdr->m_block_size; uint32_t pos = hdr->m_get_pos; + BOOST_ASSERT(pos < capacity); block_header* block = hdr->get_block(pos); size_type message_size = block->m_size; From 0d36026a7d175e2372e4f1f790df79c0cdcb5d97 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 13 Sep 2021 19:59:40 +0300 Subject: [PATCH 149/309] Added support for std::byte to receive methods of IPC message queue. --- doc/changelog.qbk | 1 + include/boost/log/utility/ipc/reliable_message_queue.hpp | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 7fb65a18f7..0ee81c9dad 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*General changes:] * Updated detection of `std::codecvt` specializations for `char16_t` and `char32_t` for compatibility with C++17 and later. ([pull_request 159]) +* Added support for C++17 `std::byte` type to receive methods of the [link log.detailed.utilities.ipc.reliable_message_queue inter-process message queue]. [heading 2.22, Boost 1.77] diff --git a/include/boost/log/utility/ipc/reliable_message_queue.hpp b/include/boost/log/utility/ipc/reliable_message_queue.hpp index 5159d72ef6..ac8cb5077f 100644 --- a/include/boost/log/utility/ipc/reliable_message_queue.hpp +++ b/include/boost/log/utility/ipc/reliable_message_queue.hpp @@ -53,6 +53,10 @@ template< typename R > struct enable_if_byte< signed char, R > { typedef R type; }; template< typename R > struct enable_if_byte< unsigned char, R > { typedef R type; }; +#if defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603 +template< typename R > +struct enable_if_byte< std::byte, R > { typedef R type; }; +#endif } // namespace aux From eb6856327fd7daa2327fec6a9e007ce8e5339278 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 14 Sep 2021 01:04:54 +0300 Subject: [PATCH 150/309] Restored C++ versions to build on MacOS and disabled catching signals. Removing newer C++ versions from MacOS CI job didn't help with job hanging, so we're restoring the complete C++ version list. As another attempt to work around the problem, disable signal handling and debugger attaching in Boost.Test. This is in case if there is a genuine problem with a test crashing and Boost.Test preventing the process from terminating. --- .github/workflows/ci.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7655fbbe95..e3c7da0096 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,6 +21,8 @@ env: GIT_FETCH_JOBS: 8 NET_RETRY_COUNT: 5 DEFAULT_BUILD_VARIANT: debug,release + BOOST_TEST_CATCH_SYSTEM_ERRORS: 0 + BOOST_TEST_AUTO_START_DBG: 0 jobs: posix: @@ -233,7 +235,7 @@ jobs: - libc++abi-12-dev - toolset: clang - cxxstd: "03,11" + cxxstd: "03,11,14,17,2a" build_variant: debug os: macos-10.15 From 24117c7a0c2bf79527d78f70ddd89dfa4167e6e4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 15 Sep 2021 16:33:25 +0300 Subject: [PATCH 151/309] Fixed a race in reliable_message_queue::open_or_create on POSIX systems. The open_or_create implementation assumed that the created shared memory size of 0 meant that the shared memory segment was freshly created. This is not the case if multiple threads call open_or_create and check the segment size before one of them resizes it. This could result in initializing the shared memory multiple times and even corrupting it if other threads were sending or receiving messages in the mean time. While at it, converted the use of atomics in shared memory to ipc_atomic. Fixes https://github.com/boostorg/log/issues/162. --- doc/changelog.qbk | 4 + src/posix/ipc_reliable_message_queue.cpp | 250 ++++++++++++++++----- src/windows/ipc_reliable_message_queue.cpp | 12 +- 3 files changed, 204 insertions(+), 62 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 0ee81c9dad..98e7243221 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -16,6 +16,10 @@ * Updated detection of `std::codecvt` specializations for `char16_t` and `char32_t` for compatibility with C++17 and later. ([pull_request 159]) * Added support for C++17 `std::byte` type to receive methods of the [link log.detailed.utilities.ipc.reliable_message_queue inter-process message queue]. +[*Bug fixes:] + +* Fixed a race condition on POSIX systems in [link log.detailed.utilities.ipc.reliable_message_queue `reliable_message_queue::open_or_create`] or the equivalent constructor. Multiple threads or processes calling `open_or_create` concurrently with sending or receiving messages from the same queue could end up corrupting the queue contents and potentially crashing the process. ([github_issue 162]) + [heading 2.22, Boost 1.77] [*Bug fixes:] diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index 1451b2a4f6..39333834b5 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -56,11 +59,6 @@ #include "bit_tools.hpp" #include -#if BOOST_ATOMIC_INT32_LOCK_FREE != 2 -// 32-bit atomic ops are required to be able to place atomic in the process-shared memory -#error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform -#endif - namespace boost { BOOST_LOG_OPEN_NAMESPACE @@ -106,7 +104,7 @@ struct reliable_message_queue::implementation //! Padding to protect against alignment changes in Boost.Atomic. Don't use BOOST_ALIGNMENT to ensure portability. unsigned char m_padding[BOOST_LOG_CPU_CACHE_LINE_SIZE - sizeof(uint32_t)]; //! Reference counter. Also acts as a flag indicating that the queue is constructed (i.e. the queue is constructed when the counter is not 0). - boost::atomic< uint32_t > m_ref_count; + boost::ipc_atomic< uint32_t > m_ref_count; //! Number of allocation blocks in the queue. const uint32_t m_capacity; //! Size of an allocation block, in bytes. @@ -133,7 +131,7 @@ struct reliable_message_queue::implementation m_get_pos(0u) { // Must be initialized last. m_ref_count is zero-initialized initially. - m_ref_count.fetch_add(1u, boost::memory_order_release); + m_ref_count.opaque_add(1u, boost::memory_order_release); } //! Returns the header structure ABI tag @@ -199,11 +197,22 @@ struct reliable_message_queue::implementation //! The number of the bit set in block_size (i.e. log base 2 of block_size) uint32_t m_block_size_log2; //! The flag indicates that stop has been requested - bool m_stop; + boost::atomic< bool > m_stop; //! Queue shared memory object name const object_name m_name; + //! The total number of loop iterations in \c adopt_region for waiting for the region initialization to complete + static BOOST_CONSTEXPR_OR_CONST unsigned int region_init_wait_loops = 200u; + //! Threshold of the number of loop iterations in \c adopt_region for using pause instructions for yielding + static BOOST_CONSTEXPR_OR_CONST unsigned int region_init_wait_loops_pause = 16u; + //! Threshold of the number of loop iterations in \c adopt_region for using \c short_yield for yielding + static BOOST_CONSTEXPR_OR_CONST unsigned int region_init_wait_loops_short_yield = 64u; + //! Timeout, in seconds, for performing shared memory creation/opening loop + static BOOST_CONSTEXPR_OR_CONST unsigned int region_open_or_create_timeout = 60u; + //! The number of short yields to perform during the shared memory creation/opening loop + static BOOST_CONSTEXPR_OR_CONST unsigned int region_open_or_create_short_yield_loops = 64u; + public: //! The constructor creates a new shared memory segment implementation @@ -215,7 +224,7 @@ struct reliable_message_queue::implementation overflow_policy oflow_policy, permissions const& perms ) : - m_shared_memory(boost::interprocess::create_only, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), + m_shared_memory(), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), @@ -224,6 +233,25 @@ struct reliable_message_queue::implementation m_name(name) { BOOST_ASSERT(block_size >= block_header::get_header_overhead()); + + boost::interprocess::permissions ipc_perms(perms.get_native()); + while (true) + { + try + { + boost::interprocess::shared_memory_object shared_memory(boost::interprocess::create_only, name.c_str(), boost::interprocess::read_write, ipc_perms); + m_shared_memory.swap(shared_memory); + break; + } + catch (boost::interprocess::interprocess_exception& e) + { + // shared_memory_object does not handle EINTR returned from shm_open internally. + // https://github.com/boostorg/interprocess/issues/152 + if (e.get_native_error() != EINTR) + throw; + } + } + create_region(capacity, block_size); } @@ -237,7 +265,7 @@ struct reliable_message_queue::implementation overflow_policy oflow_policy, permissions const& perms ) : - m_shared_memory(boost::interprocess::open_or_create, name.c_str(), boost::interprocess::read_write, boost::interprocess::permissions(perms.get_native())), + m_shared_memory(), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), @@ -246,11 +274,74 @@ struct reliable_message_queue::implementation m_name(name) { BOOST_ASSERT(block_size >= block_header::get_header_overhead()); - boost::interprocess::offset_t shmem_size = 0; - if (!m_shared_memory.get_size(shmem_size) || shmem_size == 0) + + // We need to know for certain whether we create the shared memory segment or open an existing one. + // This is to ensure that only one thread initializes the segment and all other threads wait until completion. + // Since shared_memory_object(open_or_create) constructor does not report whether the segment was actually created, + // we have to loop trying to create or open the segment. https://github.com/boostorg/interprocess/issues/151 + boost::interprocess::permissions ipc_perms(perms.get_native()); + bool created = false; + unsigned int i = 0u; + std::time_t start_time = std::time(NULL); + while (true) + { + while (true) + { + try + { + boost::interprocess::shared_memory_object shared_memory(boost::interprocess::create_only, name.c_str(), boost::interprocess::read_write, ipc_perms); + m_shared_memory.swap(shared_memory); + created = true; + goto done; + } + catch (boost::interprocess::interprocess_exception& e) + { + if (e.get_error_code() == boost::interprocess::already_exists_error) + break; + + // shared_memory_object does not handle EINTR returned from shm_open internally. + // https://github.com/boostorg/interprocess/issues/152 + if (e.get_native_error() != EINTR) + throw; + } + } + + while (true) + { + try + { + boost::interprocess::shared_memory_object shared_memory(boost::interprocess::open_only, name.c_str(), boost::interprocess::read_write); + m_shared_memory.swap(shared_memory); + created = false; + goto done; + } + catch (boost::interprocess::interprocess_exception& e) + { + if (e.get_error_code() == boost::interprocess::not_found_error) + break; + + if (e.get_native_error() != EINTR) + throw; + } + } + + std::time_t now = std::time(NULL); + if (BOOST_UNLIKELY((now - start_time) >= region_open_or_create_timeout)) + BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be created or opened: shared memory segment failed to be created or opened until timeout (possible livelock)"); + + if (i < region_open_or_create_short_yield_loops) + short_yield(); + else + long_yield(); + + ++i; + } + + done: + if (created) create_region(capacity, block_size); else - adopt_region(shmem_size); + adopt_region(); } //! The constructor opens the existing shared memory segment @@ -260,7 +351,7 @@ struct reliable_message_queue::implementation object_name const& name, overflow_policy oflow_policy ) : - m_shared_memory(boost::interprocess::open_only, name.c_str(), boost::interprocess::read_write), + m_shared_memory(), m_region(), m_overflow_policy(oflow_policy), m_block_size_mask(0u), @@ -268,11 +359,24 @@ struct reliable_message_queue::implementation m_stop(false), m_name(name) { - boost::interprocess::offset_t shmem_size = 0; - if (!m_shared_memory.get_size(shmem_size)) - BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment not found"); + while (true) + { + try + { + boost::interprocess::shared_memory_object shared_memory(boost::interprocess::open_only, name.c_str(), boost::interprocess::read_write); + m_shared_memory.swap(shared_memory); + break; + } + catch (boost::interprocess::interprocess_exception& e) + { + // shared_memory_object does not handle EINTR returned from shm_open internally. + // https://github.com/boostorg/interprocess/issues/152 + if (e.get_native_error() != EINTR) + throw; + } + } - adopt_region(shmem_size); + adopt_region(); } ~implementation() @@ -304,7 +408,7 @@ struct reliable_message_queue::implementation if (BOOST_UNLIKELY(block_count > hdr->m_capacity)) BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity"); - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return aborted; lock_queue(); @@ -312,7 +416,7 @@ struct reliable_message_queue::implementation while (true) { - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return aborted; if ((hdr->m_capacity - hdr->m_size) >= block_count) @@ -341,13 +445,13 @@ struct reliable_message_queue::implementation if (BOOST_UNLIKELY(block_count > hdr->m_capacity)) BOOST_LOG_THROW_DESCR(logic_error, "Message size exceeds the interprocess queue capacity"); - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return false; lock_queue(); boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return false; if ((hdr->m_capacity - hdr->m_size) < block_count) @@ -360,7 +464,7 @@ struct reliable_message_queue::implementation operation_result receive(receive_handler handler, void* state) { - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return aborted; lock_queue(); @@ -369,7 +473,7 @@ struct reliable_message_queue::implementation while (true) { - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return aborted; if (hdr->m_size > 0u) @@ -385,7 +489,7 @@ struct reliable_message_queue::implementation bool try_receive(receive_handler handler, void* state) { - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return false; lock_queue(); @@ -402,14 +506,14 @@ struct reliable_message_queue::implementation void stop_local() { - if (m_stop) + if (m_stop.load(boost::memory_order_relaxed)) return; lock_queue(); header* const hdr = get_header(); boost::log::ipc::aux::interprocess_mutex::auto_unlock unlock(hdr->m_mutex); - m_stop = true; + m_stop.store(true, boost::memory_order_relaxed); hdr->m_nonempty_queue.notify_all(); hdr->m_nonfull_queue.notify_all(); @@ -417,7 +521,7 @@ struct reliable_message_queue::implementation void reset_local() { - m_stop = false; + m_stop.store(false, boost::memory_order_relaxed); } void clear() @@ -450,17 +554,48 @@ struct reliable_message_queue::implementation init_block_size(block_size); } - void adopt_region(std::size_t shmem_size) + void adopt_region() { - if (shmem_size < sizeof(header)) + std::size_t shmem_size = 0u; + unsigned int i = 0u; + std::time_t start_time = std::time(NULL); + while (true) + { + boost::interprocess::offset_t shm_size = 0; + const bool get_size_result = m_shared_memory.get_size(shm_size); + if (BOOST_LIKELY(get_size_result && shm_size > 0)) + { + shmem_size = static_cast< std::size_t >(shm_size); + break; + } + + std::time_t now = std::time(NULL); + if (BOOST_UNLIKELY((now - start_time) >= region_open_or_create_timeout)) + { + if (get_size_result) + goto shmem_size_too_small; + BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment size could not be determined until timeout"); + } + + if (i < region_open_or_create_short_yield_loops) + short_yield(); + else + long_yield(); + + ++i; + } + + if (BOOST_UNLIKELY(shmem_size < sizeof(header))) + { + shmem_size_too_small: BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment size too small"); + } - boost::interprocess::mapped_region(m_shared_memory, boost::interprocess::read_write, 0u, shmem_size).swap(m_region); + boost::interprocess::mapped_region(m_shared_memory, boost::interprocess::read_write, 0, shmem_size).swap(m_region); // Wait until the mapped region becomes initialized header* const hdr = get_header(); - BOOST_CONSTEXPR_OR_CONST unsigned int wait_loops = 200u, spin_loops = 16u, spins = 16u; - for (unsigned int i = 0; i < wait_loops; ++i) + for (i = 0u; i < region_init_wait_loops; ++i) { uint32_t ref_count = hdr->m_ref_count.load(boost::memory_order_acquire); while (ref_count > 0u) @@ -469,28 +604,12 @@ struct reliable_message_queue::implementation goto done; } - if (i < spin_loops) - { - for (unsigned int j = 0; j < spins; ++j) - { - boost::log::aux::pause(); - } - } + if (i < region_init_wait_loops_pause) + boost::log::aux::pause(); + else if (i < region_init_wait_loops_short_yield) + short_yield(); else - { -#if defined(BOOST_HAS_SCHED_YIELD) - sched_yield(); -#elif defined(BOOST_HAS_PTHREAD_YIELD) - pthread_yield(); -#elif defined(BOOST_HAS_NANOSLEEP) - timespec ts = {}; - ts.tv_sec = 0; - ts.tv_nsec = 1000; - nanosleep(&ts, NULL); -#else - usleep(1); -#endif - } + long_yield(); } BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be opened: shared memory segment is not initialized by creator for too long"); @@ -677,6 +796,29 @@ struct reliable_message_queue::implementation hdr->m_nonfull_queue.notify_all(); } + + static void short_yield() BOOST_NOEXCEPT + { +#if defined(BOOST_HAS_SCHED_YIELD) + sched_yield(); +#elif defined(BOOST_HAS_PTHREAD_YIELD) + pthread_yield(); +#else + long_yield(); +#endif + } + + static void long_yield() BOOST_NOEXCEPT + { +#if defined(BOOST_HAS_NANOSLEEP) + timespec ts = {}; + ts.tv_sec = 0; + ts.tv_nsec = 1000; + nanosleep(&ts, NULL); +#else + usleep(1); +#endif + } }; BOOST_LOG_API void reliable_message_queue::create(object_name const& name, uint32_t capacity, size_type block_size, overflow_policy oflow_policy, permissions const& perms) diff --git a/src/windows/ipc_reliable_message_queue.cpp b/src/windows/ipc_reliable_message_queue.cpp index 00bc8a3f32..aa12a68cad 100644 --- a/src/windows/ipc_reliable_message_queue.cpp +++ b/src/windows/ipc_reliable_message_queue.cpp @@ -28,7 +28,8 @@ #include #include #include -#include +#include +#include #include #include #include @@ -46,11 +47,6 @@ #include #include -#if BOOST_ATOMIC_INT32_LOCK_FREE != 2 -// 32-bit atomic ops are required to be able to place atomic in the process-shared memory -#error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform -#endif - //! A suffix used in names of interprocess objects created by the queue. //! Used as a protection against clashing with user-supplied names of interprocess queues and also to resolve conflicts between queues of different types. #define BOOST_LOG_IPC_NAMES_AUX_SUFFIX L".3010b9950926463398eee00b35b44651" @@ -100,7 +96,7 @@ struct reliable_message_queue::implementation //! Padding to protect against alignment changes in Boost.Atomic. Don't use BOOST_ALIGNMENT to ensure portability. unsigned char m_padding[BOOST_LOG_CPU_CACHE_LINE_SIZE - sizeof(uint32_t)]; //! A flag indicating that the queue is constructed (i.e. the queue is constructed when the value is not 0). - boost::atomic< uint32_t > m_initialized; + boost::ipc_atomic< uint32_t > m_initialized; //! Number of allocation blocks in the queue. const uint32_t m_capacity; //! Size of an allocation block, in bytes. @@ -125,7 +121,7 @@ struct reliable_message_queue::implementation m_get_pos(0u) { // Must be initialized last. m_initialized is zero-initialized initially. - m_initialized.fetch_add(1u, boost::memory_order_release); + m_initialized.opaque_add(1u, boost::memory_order_release); } //! Returns the header structure ABI tag From 72f462a478c46c42492c2002b8deb68f8c347348 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 15 Sep 2021 17:54:52 +0300 Subject: [PATCH 152/309] Reduced GHA job timeout to 2 hours. Also, re-enabled release builds on MacOS. --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3c7da0096..37769610d4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,14 +236,13 @@ jobs: - toolset: clang cxxstd: "03,11,14,17,2a" - build_variant: debug os: macos-10.15 # - name: CMake tests # cmake_tests: 1 # os: ubuntu-20.04 - timeout-minutes: 180 + timeout-minutes: 120 runs-on: ${{matrix.os}} container: ${{matrix.container}} From 151d89dd2f989ac907e65f70f1b1de91d5da8ee2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 15 Sep 2021 23:58:41 +0300 Subject: [PATCH 153/309] Added a workaround for MSVC 8-11 ICE in util_ipc_reliable_mq test. --- test/run/util_ipc_reliable_mq.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index f82b163ce2..aae22f2a0b 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -82,8 +82,13 @@ struct queue_cleanup { } } -} -const queue_cleanup_guard = {}; +}; +#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1800 +const queue_cleanup queue_cleanup_guard = {}; +#else +// MSVC prior to 12.0 ICEs on the aggregate initialization of the constant +const queue_cleanup queue_cleanup_guard; +#endif BOOST_AUTO_TEST_CASE(basic_functionality) { From 28822babfe4f0b16fded945689f7a4d7b9926942 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 16 Sep 2021 23:02:39 +0300 Subject: [PATCH 154/309] Ported futex-based event implementation to Boost.Atomic. This allows to reuse the futex abstraction layer from Boost.Atomic and also use futex-like APIs available on other systems. Closes https://github.com/boostorg/log/issues/161. --- include/boost/log/detail/event.hpp | 52 +++++++++--------- src/event.cpp | 84 +++++------------------------- 2 files changed, 38 insertions(+), 98 deletions(-) diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index 0168e170e7..e3da4e1068 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -21,26 +21,24 @@ #ifndef BOOST_LOG_NO_THREADS -#if defined(BOOST_THREAD_PLATFORM_PTHREAD) -# include -# if (defined(linux) || defined(__linux) || defined(__linux__)) && BOOST_ATOMIC_INT_LOCK_FREE == 2 -# include -# define BOOST_LOG_EVENT_USE_FUTEX -# elif defined(_POSIX_SEMAPHORES) && (_POSIX_SEMAPHORES + 0) > 0 && BOOST_ATOMIC_FLAG_LOCK_FREE == 2 -# include -# include -# include -# define BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE -# endif +#include + +#if BOOST_ATOMIC_HAS_NATIVE_INT32_WAIT_NOTIFY == 2 +#include +#include +#define BOOST_LOG_EVENT_USE_ATOMIC +#elif defined(BOOST_THREAD_PLATFORM_PTHREAD) && defined(_POSIX_SEMAPHORES) && _POSIX_SEMAPHORES > 0 && BOOST_ATOMIC_FLAG_LOCK_FREE == 2 +#include +#include +#include +#define BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE #elif defined(BOOST_THREAD_PLATFORM_WIN32) -# include -# define BOOST_LOG_EVENT_USE_WINAPI -#endif - -#if !defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) && !defined(BOOST_LOG_EVENT_USE_WINAPI) -# include -# include -# define BOOST_LOG_EVENT_USE_BOOST_CONDITION +#include +#define BOOST_LOG_EVENT_USE_WINAPI +#else +#include +#include +#define BOOST_LOG_EVENT_USE_BOOST_CONDITION #endif #include @@ -51,18 +49,16 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -#if defined(BOOST_LOG_EVENT_USE_FUTEX) +#if defined(BOOST_LOG_EVENT_USE_ATOMIC) -class futex_based_event +class atomic_based_event { private: - boost::atomic< int > m_state; + boost::atomic< boost::uint32_t > m_state; public: //! Default constructor - BOOST_LOG_API futex_based_event(); - //! Destructor - BOOST_LOG_API ~futex_based_event(); + atomic_based_event() : m_state(0u) {} //! Waits for the object to become signalled BOOST_LOG_API void wait(); @@ -70,11 +66,11 @@ class futex_based_event BOOST_LOG_API void set_signalled(); // Copying prohibited - BOOST_DELETED_FUNCTION(futex_based_event(futex_based_event const&)) - BOOST_DELETED_FUNCTION(futex_based_event& operator= (futex_based_event const&)) + BOOST_DELETED_FUNCTION(atomic_based_event(atomic_based_event const&)) + BOOST_DELETED_FUNCTION(atomic_based_event& operator= (atomic_based_event const&)) }; -typedef futex_based_event event; +typedef atomic_based_event event; #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) diff --git a/src/event.cpp b/src/event.cpp index f576648c6a..05060e9149 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -23,37 +23,11 @@ #include #include -#if defined(BOOST_LOG_EVENT_USE_FUTEX) +#if defined(BOOST_LOG_EVENT_USE_ATOMIC) -#include -#include -#include -#include #include - -// Some Android NDKs (Google NDK and older Crystax.NET NDK versions) don't define SYS_futex -#if defined(SYS_futex) -#define BOOST_LOG_SYS_FUTEX SYS_futex -#elif defined(__NR_futex) -#define BOOST_LOG_SYS_FUTEX __NR_futex -// riscv32 defines a different system call instead of __NR_futex -#elif defined(__NR_futex_time64) -#define BOOST_LOG_SYS_FUTEX __NR_futex_time64 -#else -#error "Unable to find a suitable futex" -#endif - -#if defined(FUTEX_WAIT_PRIVATE) -#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT_PRIVATE -#else -#define BOOST_LOG_FUTEX_WAIT FUTEX_WAIT -#endif - -#if defined(FUTEX_WAKE_PRIVATE) -#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE_PRIVATE -#else -#define BOOST_LOG_FUTEX_WAKE FUTEX_WAKE -#endif +#include +#include #elif defined(BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE) @@ -81,57 +55,27 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -#if defined(BOOST_LOG_EVENT_USE_FUTEX) - -//! Default constructor -BOOST_LOG_API futex_based_event::futex_based_event() : m_state(0) -{ -} - -//! Destructor -BOOST_LOG_API futex_based_event::~futex_based_event() -{ -} +#if defined(BOOST_LOG_EVENT_USE_ATOMIC) //! Waits for the object to become signalled -BOOST_LOG_API void futex_based_event::wait() +BOOST_LOG_API void atomic_based_event::wait() { - if (m_state.exchange(0, boost::memory_order_acq_rel) == 0) + while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) { - while (true) - { - if (::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAIT, 0, NULL, NULL, 0) == 0) - { - // Another thread has set the event while sleeping - break; - } - - const int err = errno; - if (err == EWOULDBLOCK) - { - // Another thread has set the event before sleeping - break; - } - else if (BOOST_UNLIKELY(err != EINTR)) - { - BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on the futex", (err)); - } - } - - m_state.store(0, boost::memory_order_relaxed); + m_state.wait(0u, boost::memory_order_relaxed); } } //! Sets the object to a signalled state -BOOST_LOG_API void futex_based_event::set_signalled() +BOOST_LOG_API void atomic_based_event::set_signalled() { - if (m_state.exchange(1, boost::memory_order_release) == 0) + if (m_state.load(boost::memory_order_relaxed) != 0u) { - if (BOOST_UNLIKELY(::syscall(BOOST_LOG_SYS_FUTEX, &m_state.value(), BOOST_LOG_FUTEX_WAKE, 1, NULL, NULL, 0) < 0)) - { - const int err = errno; - BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake threads blocked on the futex", (err)); - } + boost::atomic_thread_fence(boost::memory_order_release); + } + else if (m_state.exchange(1u, boost::memory_order_release) == 0u) + { + m_state.notify_one(); } } From 07c3449c4b45d26619fee79232d50cf2398eb558 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 16 Sep 2021 23:09:17 +0300 Subject: [PATCH 155/309] Renamed BOOST_LOG_EVENT_USE_BOOST_CONDITION macro. --- include/boost/log/detail/event.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index e3da4e1068..c27ca6e2e0 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -38,7 +38,7 @@ #else #include #include -#define BOOST_LOG_EVENT_USE_BOOST_CONDITION +#define BOOST_LOG_EVENT_USE_BOOST_CONDITION_VARIABLE #endif #include From a3adc2cf337a8a4da8df0d7361d15ccf245ea308 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 16 Sep 2021 23:15:48 +0300 Subject: [PATCH 156/309] Updated copyright years. --- include/boost/log/detail/event.hpp | 2 +- src/event.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index c27ca6e2e0..037c89bb7e 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/event.cpp b/src/event.cpp index 05060e9149..2b60a735e1 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) From 124abd34d704d87cbb34988e40606601e93a4f62 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 17 Sep 2021 20:45:09 +0300 Subject: [PATCH 157/309] Ported WinAPI-based event to use Boost.Atomic. --- include/boost/log/detail/event.hpp | 3 +- src/event.cpp | 64 +++++++++++++++++++++--------- 2 files changed, 48 insertions(+), 19 deletions(-) diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index 037c89bb7e..ff9951af26 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -34,6 +34,7 @@ #define BOOST_LOG_EVENT_USE_POSIX_SEMAPHORE #elif defined(BOOST_THREAD_PLATFORM_WIN32) #include +#include #define BOOST_LOG_EVENT_USE_WINAPI #else #include @@ -103,7 +104,7 @@ typedef sem_based_event event; class winapi_based_event { private: - boost::uint32_t m_state; + boost::atomic< boost::uint32_t > m_state; void* m_event; public: diff --git a/src/event.cpp b/src/event.cpp index 2b60a735e1..bbc033e7a2 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -39,7 +39,9 @@ #elif defined(BOOST_LOG_EVENT_USE_WINAPI) #include -#include +#include +#include +#include #else @@ -134,47 +136,73 @@ BOOST_LOG_API void sem_based_event::set_signalled() //! Default constructor BOOST_LOG_API winapi_based_event::winapi_based_event() : - m_state(0), - m_event(CreateEventA(NULL, false, false, NULL)) + m_state(0u), + m_event(NULL) { - if (BOOST_UNLIKELY(!m_event)) + if (!m_state.has_native_wait_notify()) { - const DWORD err = GetLastError(); - BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err)); + m_event = CreateEventA(NULL, false, false, NULL); + if (BOOST_UNLIKELY(!m_event)) + { + const DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to create Windows event", (err)); + } } } //! Destructor BOOST_LOG_API winapi_based_event::~winapi_based_event() { - BOOST_VERIFY(CloseHandle(m_event) != 0); + if (!!m_event) + { + BOOST_VERIFY(CloseHandle(m_event) != 0); + } } //! Waits for the object to become signalled BOOST_LOG_API void winapi_based_event::wait() { - // On Windows we assume that memory view is always actual (Intel x86 and x86_64 arch) - if (const_cast< volatile boost::uint32_t& >(m_state) == 0) + if (!m_event) { - if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0)) + while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) { - const DWORD err = GetLastError(); - BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err)); + m_state.wait(0u, boost::memory_order_relaxed); + } + } + else + { + while (m_state.exchange(0u, boost::memory_order_acq_rel) == 0u) + { + if (BOOST_UNLIKELY(WaitForSingleObject(m_event, INFINITE) != 0)) + { + const DWORD err = GetLastError(); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to block on Windows event", (err)); + } } } - const_cast< volatile boost::uint32_t& >(m_state) = 0; } //! Sets the object to a signalled state BOOST_LOG_API void winapi_based_event::set_signalled() { - if (BOOST_INTERLOCKED_COMPARE_EXCHANGE(reinterpret_cast< long* >(&m_state), 1, 0) == 0) + if (m_state.load(boost::memory_order_relaxed) != 0u) { - if (BOOST_UNLIKELY(SetEvent(m_event) == 0)) + boost::atomic_thread_fence(boost::memory_order_release); + } + else if (m_state.exchange(1u, boost::memory_order_release) == 0u) + { + if (!m_event) { - const DWORD err = GetLastError(); - const_cast< volatile boost::uint32_t& >(m_state) = 0; - BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); + m_state.notify_one(); + } + else + { + if (BOOST_UNLIKELY(SetEvent(m_event) == 0)) + { + const DWORD err = GetLastError(); + m_state.store(0u, boost::memory_order_relaxed); + BOOST_LOG_THROW_DESCR_PARAMS(system_error, "Failed to wake the blocked thread", (err)); + } } } } From 6d4a13cddf2331ae46eefe2bbdbc8669d40c925c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 17 Sep 2021 23:45:32 +0300 Subject: [PATCH 158/309] Added a new nt62 OS API version tag in the library version namespace. This is to indicate that the minimum target Windows version is Windows 8. This is important for Boost.Atomic as it enables using WaitOnAddress API, which further affects binary representation of the event object in Boost.Log. --- doc/changelog.qbk | 1 + doc/rationale.qbk | 2 +- include/boost/log/detail/config.hpp | 8 ++++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 98e7243221..0f4e968a40 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -15,6 +15,7 @@ * Updated detection of `std::codecvt` specializations for `char16_t` and `char32_t` for compatibility with C++17 and later. ([pull_request 159]) * Added support for C++17 `std::byte` type to receive methods of the [link log.detailed.utilities.ipc.reliable_message_queue inter-process message queue]. +* On Windows, when building the library for Windows 8 or later, the library will use `nt62` tag in the version namespace to denote the target OS ABI. For example, the version namespace could be named as `v2_mt_nt62`. This name will be part of all symbols exported by the library. Use the `BOOST_USE_WINAPI_VERSION` macro consistenly when building Boost and your code to request the minimum target Windows version. [*Bug fixes:] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 30bdb09d10..baa668085a 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -208,7 +208,7 @@ Most of the time users won't even notice the existence of this internal namespac * The `` component describes the library major version. It is currently `v2`. * The `` component tells whether the library is linked statically or dynamically. It is `s` if the library is linked statically and empty otherwise. * The `` component is `st` for single-threaded builds and `mt` for multi-threaded ones. -* The `` component describes the underlying OS API used by the library. Currently, it is only specified for multi-threaded builds. Depending on the target platform and configuration, it can be `posix`, `nt5` or `nt6`. +* The `` component describes the underlying OS API used by the library. Currently, it is only specified for multi-threaded builds. Depending on the target platform and configuration, it can be `posix`, `nt5`, `nt6` or `nt62`. As a couple quick examples, `v2s_st` corresponds to v2 static single-threaded build of the library and `v2_mt_posix` - to v2 dynamic multi-threaded build for POSIX system API. diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 84b194e13c..207258567a 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -332,7 +332,9 @@ namespace boost { # if defined(BOOST_THREAD_PLATFORM_PTHREAD) # define BOOST_LOG_VERSION_NAMESPACE v2_mt_posix # elif defined(BOOST_THREAD_PLATFORM_WIN32) -# if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +# if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN8 +# define BOOST_LOG_VERSION_NAMESPACE v2_mt_nt62 +# elif BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 # define BOOST_LOG_VERSION_NAMESPACE v2_mt_nt6 # else # define BOOST_LOG_VERSION_NAMESPACE v2_mt_nt5 @@ -348,7 +350,9 @@ namespace boost { # if defined(BOOST_THREAD_PLATFORM_PTHREAD) # define BOOST_LOG_VERSION_NAMESPACE v2s_mt_posix # elif defined(BOOST_THREAD_PLATFORM_WIN32) -# if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 +# if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN8 +# define BOOST_LOG_VERSION_NAMESPACE v2s_mt_nt62 +# elif BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 # define BOOST_LOG_VERSION_NAMESPACE v2s_mt_nt6 # else # define BOOST_LOG_VERSION_NAMESPACE v2s_mt_nt5 From 33f4b3310cfc4abbe7539ce80e175aec96a35d59 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 17 Sep 2021 23:52:37 +0300 Subject: [PATCH 159/309] Only define BOOST_USE_WINDOWS_H when building Boost.Log. This is to work around target Windows version mismatch between Boost.Log and test/examples code caused by other libraries (e.g. Boost.SmartPtr) including windows.h without using Boost.WinAPI or defining the target Windows version. Windows SDK defines its own default target version, which doesn't necessarilly match the default in Boost.WinAPI, which is used when building Boost.Log. By not using windows.h when building tests and examples we make the other libraries to provide their own definitions of WinAPI components instead of including windows.h, and therefore avoid them defining a different target Windows version. --- build/Jamfile.v2 | 6 ++++-- build/log-platform-config.jam | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index f15079d51e..bf4020e2b2 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -208,15 +208,17 @@ project boost/log multi:/boost/atomic//boost_atomic multi:/boost/thread//boost_thread + windows:BOOST_USE_WINDOWS_H windows:ws2_32 windows:mswsock windows:advapi32 + cygwin:BOOST_USE_WINDOWS_H + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + cygwin:BOOST_LOG_WITHOUT_IPC cygwin:ws2_32 cygwin:mswsock cygwin:advapi32 - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 - cygwin:BOOST_LOG_WITHOUT_IPC linux:rt diff --git a/build/log-platform-config.jam b/build/log-platform-config.jam index 16af8cb346..93b31431b4 100644 --- a/build/log-platform-config.jam +++ b/build/log-platform-config.jam @@ -38,7 +38,6 @@ rule set-platform-defines ( properties * ) result += NOMINMAX ; result += WIN32_LEAN_AND_MEAN ; result += SECURITY_WIN32 ; - result += BOOST_USE_WINDOWS_H ; if cygwin in $(properties) { From 6d4021209dba7fbb10de69331821d88428d0fba6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 18 Sep 2021 00:09:46 +0300 Subject: [PATCH 160/309] Moved is_debugger_present predicate implementation to a compiled source file. This allows to avoid including windows.h in public headers and defining an arbitraty target Windows version to make IsDebuggerPresent API available. --- build/Jamfile.v2 | 1 + .../predicates/is_debugger_present.hpp | 41 +----------------- src/windows/is_debugger_present.cpp | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+), 39 deletions(-) create mode 100644 src/windows/is_debugger_present.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index bf4020e2b2..a81fb8b274 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -344,6 +344,7 @@ rule select-platform-specific-sources ( properties * ) if windows in $(properties) { result += windows/light_rw_mutex.cpp ; + result += windows/is_debugger_present.cpp ; if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] { diff --git a/include/boost/log/expressions/predicates/is_debugger_present.hpp b/include/boost/log/expressions/predicates/is_debugger_present.hpp index 9d4960714d..2614bd71ad 100644 --- a/include/boost/log/expressions/predicates/is_debugger_present.hpp +++ b/include/boost/log/expressions/predicates/is_debugger_present.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -27,40 +27,6 @@ #include #include -#if defined(BOOST_USE_WINDOWS_H) - -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0500 -#endif - -#include - -#else // defined(BOOST_USE_WINDOWS_H) - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace expressions { - -namespace aux { - -extern "C" { - -__declspec(dllimport) int __stdcall IsDebuggerPresent(); - -} // extern "C" - -} // namespace aux - -} // namespace expressions - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#endif // BOOST_USE_WINDOWS_H - namespace boost { BOOST_LOG_OPEN_NAMESPACE @@ -73,10 +39,7 @@ struct is_debugger_present { typedef bool result_type; - result_type operator() () const - { - return IsDebuggerPresent() != 0; - } + BOOST_LOG_API result_type operator() () const; }; } // namespace aux diff --git a/src/windows/is_debugger_present.cpp b/src/windows/is_debugger_present.cpp new file mode 100644 index 0000000000..cf2b84e0c6 --- /dev/null +++ b/src/windows/is_debugger_present.cpp @@ -0,0 +1,42 @@ +/* + * Copyright Andrey Semashev 2021. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file is_debugger_present.cpp + * \author Andrey Semashev + * \date 18.09.2021 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + */ + +#include +#include +#include +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace expressions { + +namespace aux { + +BOOST_LOG_API is_debugger_present::result_type is_debugger_present::operator() () const +{ + return IsDebuggerPresent() != 0; +} + +} // namespace aux + +} // namespace expressions + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include From c9b6e2b191db2b0bff1ec632d952af9898e035b6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 18 Sep 2021 03:02:46 +0300 Subject: [PATCH 161/309] Include Boost.WinAPI config first in tests involving Boost.Regex. This is needed because Boost.Regex includes windows.h internally, which causes it to define a different target Windows version than that is used by Boost.Log, which results in linking errors. https://github.com/boostorg/regex/issues/154 --- test/run/filt_attr.cpp | 9 +++++++++ test/run/filt_matches_boost_regex.cpp | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/test/run/filt_attr.cpp b/test/run/filt_attr.cpp index 237908129f..e1858d496e 100644 --- a/test/run/filt_attr.cpp +++ b/test/run/filt_attr.cpp @@ -14,6 +14,15 @@ #define BOOST_TEST_MODULE filt_attr +#include + +// Try including WinAPI config as soon as possible so that any other headers don't include Windows SDK headers. +// This is important to select the target Windows version, as windows.h will be included by other Boost libraries, e.g. Regex. +#if defined(BOOST_OS_WINDOWS_AVAILABLE) +#define BOOST_USE_WINDOWS_H +#include +#endif + #include #include #include diff --git a/test/run/filt_matches_boost_regex.cpp b/test/run/filt_matches_boost_regex.cpp index c34fc731ec..7b3e4fddfd 100644 --- a/test/run/filt_matches_boost_regex.cpp +++ b/test/run/filt_matches_boost_regex.cpp @@ -14,6 +14,15 @@ #define BOOST_TEST_MODULE filt_matches_boost_regex +#include + +// Try including WinAPI config as soon as possible so that any other headers don't include Windows SDK headers. +// This is important to select the target Windows version, as windows.h will be included by other Boost libraries, e.g. Regex. +#if defined(BOOST_OS_WINDOWS_AVAILABLE) +#define BOOST_USE_WINDOWS_H +#include +#endif + #include #include #include From 4c54e4ca4c31f18ce2e451e8d0abf88054242d57 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 26 Sep 2021 20:41:17 +0300 Subject: [PATCH 162/309] Fixed git version check on Mac OS. --- .github/workflows/ci.yml | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 37769610d4..dd9e2e80ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -349,7 +349,30 @@ jobs: echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV DEPINST_ARGS=() GIT_VERSION="$(git --version | sed -e 's/git version //')" - if $(dpkg --compare-versions "$GIT_VERSION" ge 2.8.0) + GIT_HAS_JOBS=1 + if [ -f "/etc/debian_version" ] + then + if $(dpkg --compare-versions "$GIT_VERSION" lt 2.8.0) + then + GIT_HAS_JOBS=0 + fi + else + declare -a GIT_VER=(${GIT_VERSION//./ }) + declare -a GIT_MIN_VER=(2 8 0) + for ((i=0; i<${#GIT_VER[@]}; i++)) + do + if [ -z "${GIT_MIN_VER[i]}" ] + then + GIT_MIN_VER[i]=0 + fi + if [ "${GIT_VER[i]}" -lt "${GIT_MIN_VER[i]}" ] + then + GIT_HAS_JOBS=0 + break + fi + done + fi + if [ "$GIT_HAS_JOBS" -ne 0 ] then DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") fi From 1d6a8d9a5090dd03d3b968abc243d806170bfb33 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 24 Oct 2021 16:02:15 +0300 Subject: [PATCH 163/309] Added a dummy export from boost_log_setup if settings parsers are disabled. When settings parsers were disabled by a config macro, boost_log_setup would be empty, and MSVC linker would produce no library at all. This broke installing Boost.Log, as Boost.Build would expect a library file to be present. We're adding a dummy export from the library as a workaround, so that the library is always created, even if empty. This workaround should be considered temporary, until we can disable the library proper after a Boost.Build bug is fixed: https://github.com/bfgroup/b2/issues/104 Closes https://github.com/boostorg/log/issues/164. Closes https://github.com/boostorg/log/pull/165. --- doc/changelog.qbk | 1 + src/setup/settings_parser.cpp | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 0f4e968a40..a329069e7c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -20,6 +20,7 @@ [*Bug fixes:] * Fixed a race condition on POSIX systems in [link log.detailed.utilities.ipc.reliable_message_queue `reliable_message_queue::open_or_create`] or the equivalent constructor. Multiple threads or processes calling `open_or_create` concurrently with sending or receiving messages from the same queue could end up corrupting the queue contents and potentially crashing the process. ([github_issue 162]) +* Added a workaround for `b2 install` failing on Windows because of missing `boost_log_setup` library if `BOOST_LOG_WITHOUT_SETTINGS_PARSERS` is defined. ([github_issue 164]) [heading 2.22, Boost 1.77] diff --git a/src/setup/settings_parser.cpp b/src/setup/settings_parser.cpp index d0ebe6fede..b1e54b46d2 100644 --- a/src/setup/settings_parser.cpp +++ b/src/setup/settings_parser.cpp @@ -13,9 +13,10 @@ * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. */ +#include + #ifndef BOOST_LOG_WITHOUT_SETTINGS_PARSERS -#include #include #include #include @@ -257,4 +258,30 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include +#else // BOOST_LOG_WITHOUT_SETTINGS_PARSERS + +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +BOOST_LOG_SETUP_API void boost_log_setup_is_empty() +{ + // This dummy export exists to that boost_log_setup library is not empty and is created even if settings parsers are disabled. + // MSVC is known to not generate the library if it contains no exports (https://github.com/boostorg/log/issues/164), which breaks + // install targets as Boost.Build cannot find the library file to install. + // We use this dummy export instead of disabling building boost_log_setup in the first place because of this Boost.Build bug: + // + // https://github.com/bfgroup/b2/issues/104 + // + // After this bug is fixed, we can consider removing this dummy export and disabling building the library proper. +} + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS From 63325283f5140133f1a8fcfafd3012f6d99857ea Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 24 Oct 2021 21:18:10 +0300 Subject: [PATCH 164/309] Improved performance of SSSE3/AVX2 implementations of dump manipulator. Use byte shuffle instead of arithmetics and masking to convert half-bytes to characters. Since the new algorithm more heavilly relies on pshufb, and it is slow on some older Intel Atom CPUs, retain the old implementation and use it when we know pshufb is slow. We might drop it eventually. --- doc/changelog.qbk | 1 + src/dump.cpp | 43 ++++++- src/dump_avx2.cpp | 171 +++++++++++++-------------- src/dump_ssse3.cpp | 282 +++++++++++++++++++++++++++++++++++++++------ 4 files changed, 370 insertions(+), 127 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index a329069e7c..22b452060d 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -16,6 +16,7 @@ * Updated detection of `std::codecvt` specializations for `char16_t` and `char32_t` for compatibility with C++17 and later. ([pull_request 159]) * Added support for C++17 `std::byte` type to receive methods of the [link log.detailed.utilities.ipc.reliable_message_queue inter-process message queue]. * On Windows, when building the library for Windows 8 or later, the library will use `nt62` tag in the version namespace to denote the target OS ABI. For example, the version namespace could be named as `v2_mt_nt62`. This name will be part of all symbols exported by the library. Use the `BOOST_USE_WINAPI_VERSION` macro consistenly when building Boost and your code to request the minimum target Windows version. +* Improved performance of SSSE3 and AVX2 implementations of the [link log.detailed.utilities.manipulators.dump `dump`] stream manipulator. [*Bug fixes:] diff --git a/src/dump.cpp b/src/dump.cpp index e23cb2b43b..e66013fa30 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -38,6 +38,14 @@ extern dump_data_char16_t dump_data_char16_ssse3; #if !defined(BOOST_NO_CXX11_CHAR32_T) extern dump_data_char32_t dump_data_char32_ssse3; #endif +extern dump_data_char_t dump_data_char_ssse3_slow_pshufb; +extern dump_data_wchar_t dump_data_wchar_ssse3_slow_pshufb; +#if !defined(BOOST_NO_CXX11_CHAR16_T) +extern dump_data_char16_t dump_data_char16_ssse3_slow_pshufb; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) +extern dump_data_char32_t dump_data_char32_ssse3_slow_pshufb; +#endif #endif #if defined(BOOST_LOG_USE_AVX2) extern dump_data_char_t dump_data_char_avx2; @@ -52,7 +60,7 @@ extern dump_data_char32_t dump_data_char32_avx2; enum { stride = 256 }; -extern const char g_hex_char_table[2][16] = +extern BOOST_ALIGNMENT(16) const char g_hex_char_table[2][16] = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } @@ -129,6 +137,7 @@ struct function_pointer_initializer cpuid(eax, ebx, ecx, edx); const uint32_t max_cpuid_function = eax; + const uint32_t cpu_vendor[3u] = { ebx, edx, ecx }; if (max_cpuid_function >= 1) { eax = 1; @@ -137,7 +146,21 @@ struct function_pointer_initializer // Check for SSSE3 support if (ecx & (1u << 9)) - enable_ssse3(); + { + const uint32_t family = ((eax >> 8) & 0x0000000F) + ((eax >> 20) & 0x000000FF); + const uint32_t model = ((eax >> 4) & 0x0000000F) | ((eax >> 12) & 0x000000F0); + + // Check if the CPU has slow pshufb. Some old Intel Atoms prior to Silvermont. + if (cpu_vendor[0] == 0x756e6547 && cpu_vendor[1] == 0x49656e69 && cpu_vendor[2] == 0x6c65746e && + family == 6 && (model == 28 || model == 38 || model == 39 || model == 53 || model == 54)) + { + enable_ssse3_slow_pshufb(); + } + else + { + enable_ssse3(); + } + } #if defined(BOOST_LOG_USE_AVX2) if (max_cpuid_function >= 7) @@ -156,7 +179,7 @@ struct function_pointer_initializer : "=a" (eax), "=d" (edx) : "c" (0) ); - mmstate = (eax & 6U) == 6U; + mmstate = (eax & 6u) == 6u; #elif defined(BOOST_WINDOWS) // MSVC does not have an intrinsic for xgetbv, we have to query OS boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); @@ -179,7 +202,7 @@ struct function_pointer_initializer ebx = ecx = edx = 0; cpuid(eax, ebx, ecx, edx); - if (ebx & (1U << 5)) + if (ebx & (1u << 5)) enable_avx2(); } } @@ -233,6 +256,18 @@ struct function_pointer_initializer #endif } + static void enable_ssse3_slow_pshufb() + { + dump_data_char = &dump_data_char_ssse3_slow_pshufb; + dump_data_wchar = &dump_data_wchar_ssse3_slow_pshufb; +#if !defined(BOOST_NO_CXX11_CHAR16_T) + dump_data_char16 = &dump_data_char16_ssse3_slow_pshufb; +#endif +#if !defined(BOOST_NO_CXX11_CHAR32_T) + dump_data_char32 = &dump_data_char32_ssse3_slow_pshufb; +#endif + } + static void enable_ssse3() { dump_data_char = &dump_data_char_ssse3; diff --git a/src/dump_avx2.cpp b/src/dump_avx2.cpp index 4ab12500fa..a67d40b4fb 100644 --- a/src/dump_avx2.cpp +++ b/src/dump_avx2.cpp @@ -47,12 +47,47 @@ enum stride = packs_per_stride * 32 }; +template< typename CharT > +BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf) +{ + switch (sizeof(CharT)) + { + case 1: + _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars); + break; + + case 2: + _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi16(mm_chars)); + break; + + case 4: + { + __m128i mm = _mm_unpackhi_epi64(mm_chars, mm_chars); + _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi32(mm_chars)); + _mm256_store_si256(reinterpret_cast< __m256i* >(buf) + 1, _mm256_cvtepu8_epi32(mm)); + } + break; + } +} + +template< typename CharT > +BOOST_FORCEINLINE void store_characters_x3(__m256i mm_chars1, __m256i mm_chars2, __m256i mm_chars3, CharT* buf) +{ + store_characters(_mm256_castsi256_si128(mm_chars1), buf); + store_characters(_mm256_castsi256_si128(mm_chars2), buf + 16); + store_characters(_mm256_castsi256_si128(mm_chars3), buf + 32); + store_characters(_mm256_extracti128_si256(mm_chars1, 1), buf + 48); + store_characters(_mm256_extracti128_si256(mm_chars2, 1), buf + 64); + store_characters(_mm256_extracti128_si256(mm_chars3, 1), buf + 80); +} + union ymm_constant { uint8_t as_bytes[32]; __m256i as_mm; BOOST_FORCEINLINE operator __m256i () const { return as_mm; } + BOOST_FORCEINLINE operator __m128i () const { return _mm256_castsi256_si128(as_mm); } }; static const ymm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 0x80, 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80 }}; @@ -63,24 +98,28 @@ static const ymm_constant mm_shuffle_pattern13 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80 #if defined(BOOST_LOG_AUX_X86_64) // x86-64 architecture has more registers which we can utilize to pass constants -#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL __m256i mm_15, __m256i mm_9, __m256i mm_char_0, __m256i mm_char_space, -#define BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_15, mm_9, mm_char_0, mm_char_space, -#define BOOST_LOG_AUX_MM_CONSTANTS \ +#define BOOST_LOG_AUX_MM256_CONSTANT_ARGS_DECL __m256i mm_15, __m256i mm_char_space, +#define BOOST_LOG_AUX_MM256_CONSTANT_ARGS mm_15, mm_char_space, +#define BOOST_LOG_AUX_MM256_CONSTANTS \ const __m256i mm_15 = _mm256_set1_epi32(0x0F0F0F0F);\ - const __m256i mm_9 = _mm256_set1_epi32(0x09090909);\ - const __m256i mm_char_0 = _mm256_set1_epi32(0x30303030);\ const __m256i mm_char_space = _mm256_set1_epi32(0x20202020); +#define BOOST_LOG_AUX_MM128_CONSTANT_ARGS_DECL __m128i mm_15, __m128i mm_char_space, +#define BOOST_LOG_AUX_MM128_CONSTANT_ARGS mm_15, mm_char_space, +#define BOOST_LOG_AUX_MM128_CONSTANTS \ + const __m128i mm_15 = _mm_set1_epi32(0x0F0F0F0F);\ + const __m128i mm_char_space = _mm_set1_epi32(0x20202020); #else // MSVC in 32-bit mode is not able to pass all constants to dump_pack, and is also not able to align them on the stack, so we have to fetch them from global constants static const ymm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }}; -static const ymm_constant mm_9 = {{ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09 }}; -static const ymm_constant mm_char_0 = {{ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 }}; static const ymm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }}; -#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL -#define BOOST_LOG_AUX_MM_CONSTANT_ARGS -#define BOOST_LOG_AUX_MM_CONSTANTS +#define BOOST_LOG_AUX_MM256_CONSTANT_ARGS_DECL +#define BOOST_LOG_AUX_MM256_CONSTANT_ARGS +#define BOOST_LOG_AUX_MM256_CONSTANTS +#define BOOST_LOG_AUX_MM128_CONSTANT_ARGS_DECL +#define BOOST_LOG_AUX_MM128_CONSTANT_ARGS +#define BOOST_LOG_AUX_MM128_CONSTANTS #endif @@ -91,8 +130,8 @@ static const ymm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, */ static BOOST_FORCEINLINE void dump_pack ( - BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL - __m256i mm_char_10_to_a, __m256i mm_input, + BOOST_LOG_AUX_MM256_CONSTANT_ARGS_DECL + __m256i mm_char_table, __m256i mm_input, __m256i& mm_output1, __m256i& mm_output2, __m256i& mm_output3 ) { @@ -101,16 +140,8 @@ static BOOST_FORCEINLINE void dump_pack __m256i mm_input_lo = _mm256_and_si256(mm_input, mm_15); // Stringize each of the halves - __m256i mm_addend_hi = _mm256_cmpgt_epi8(mm_input_hi, mm_9); - __m256i mm_addend_lo = _mm256_cmpgt_epi8(mm_input_lo, mm_9); - mm_addend_hi = _mm256_and_si256(mm_char_10_to_a, mm_addend_hi); - mm_addend_lo = _mm256_and_si256(mm_char_10_to_a, mm_addend_lo); - - mm_input_hi = _mm256_add_epi8(mm_input_hi, mm_char_0); - mm_input_lo = _mm256_add_epi8(mm_input_lo, mm_char_0); - - mm_input_hi = _mm256_add_epi8(mm_input_hi, mm_addend_hi); - mm_input_lo = _mm256_add_epi8(mm_input_lo, mm_addend_lo); + mm_input_hi = _mm256_shuffle_epi8(mm_char_table, mm_input_hi); + mm_input_lo = _mm256_shuffle_epi8(mm_char_table, mm_input_lo); // Join them back together __m256i mm_1 = _mm256_unpacklo_epi8(mm_input_hi, mm_input_lo); @@ -131,65 +162,33 @@ static BOOST_FORCEINLINE void dump_pack //! Dumps a pack of input data into a string of 8 bit ASCII characters static BOOST_FORCEINLINE void dump_pack ( - BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL - __m256i mm_char_10_to_a, __m128i mm_input, + BOOST_LOG_AUX_MM128_CONSTANT_ARGS_DECL + __m128i mm_char_table, __m128i mm_input, __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3 ) { // Split half-bytes - __m128i mm_input_hi = _mm_srli_epi16(mm_input, 4); - __m256i mm = _mm256_inserti128_si256(_mm256_castsi128_si256(_mm_unpacklo_epi8(mm_input_hi, mm_input)), _mm_unpackhi_epi8(mm_input_hi, mm_input), 1); - mm = _mm256_and_si256(mm, mm_15); + __m128i mm_input_hi = _mm_and_si128(_mm_srli_epi16(mm_input, 4), mm_15); + __m128i mm_input_lo = _mm_and_si128(mm_input, mm_15); - // Stringize the halves - __m256i mm_addend = _mm256_cmpgt_epi8(mm, mm_9); - mm_addend = _mm256_and_si256(mm_char_10_to_a, mm_addend); + // Stringize each of the halves + mm_input_hi = _mm_shuffle_epi8(mm_char_table, mm_input_hi); + mm_input_lo = _mm_shuffle_epi8(mm_char_table, mm_input_lo); - mm = _mm256_add_epi8(mm, mm_char_0); - mm = _mm256_add_epi8(mm, mm_addend); + // Join them back together + __m128i mm_1 = _mm_unpacklo_epi8(mm_input_hi, mm_input_lo); + __m128i mm_2 = _mm_unpackhi_epi8(mm_input_hi, mm_input_lo); // Insert spaces between stringized bytes: - __m256i mm_out13 = _mm256_shuffle_epi8(mm, mm_shuffle_pattern13.as_mm); - __m128i mm_out2 = _mm_shuffle_epi8(_mm_alignr_epi8(_mm256_extracti128_si256(mm, 1), _mm256_castsi256_si128(mm), 10), _mm256_castsi256_si128(mm_shuffle_pattern2.as_mm)); - - mm_out13 = _mm256_max_epu8(mm_out13, mm_char_space); - mm_output2 = _mm_max_epu8(mm_out2, _mm256_castsi256_si128(mm_char_space)); - mm_output1 = _mm256_castsi256_si128(mm_out13); - mm_output3 = _mm256_extracti128_si256(mm_out13, 1); -} - -template< typename CharT > -BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf) -{ - switch (sizeof(CharT)) - { - case 1: - _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars); - break; - - case 2: - _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi16(mm_chars)); - break; - - case 4: - { - __m128i mm = _mm_unpackhi_epi64(mm_chars, mm_chars); - _mm256_store_si256(reinterpret_cast< __m256i* >(buf), _mm256_cvtepu8_epi32(mm_chars)); - _mm256_store_si256(reinterpret_cast< __m256i* >(buf) + 1, _mm256_cvtepu8_epi32(mm)); - } - break; - } -} + // |0123456789abcdef|0123456789abcdef| + // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef| + mm_output1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1); + mm_output2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2); + mm_output3 = _mm_shuffle_epi8(mm_2, mm_shuffle_pattern3); -template< typename CharT > -BOOST_FORCEINLINE void store_characters_x3(__m256i mm_chars1, __m256i mm_chars2, __m256i mm_chars3, CharT* buf) -{ - store_characters(_mm256_castsi256_si128(mm_chars1), buf); - store_characters(_mm256_castsi256_si128(mm_chars2), buf + 16); - store_characters(_mm256_castsi256_si128(mm_chars3), buf + 32); - store_characters(_mm256_extracti128_si256(mm_chars1, 1), buf + 48); - store_characters(_mm256_extracti128_si256(mm_chars2, 1), buf + 64); - store_characters(_mm256_extracti128_si256(mm_chars3, 1), buf + 80); + mm_output1 = _mm_max_epu8(mm_output1, mm_char_space); + mm_output2 = _mm_max_epu8(mm_output2, mm_char_space); + mm_output3 = _mm_max_epu8(mm_output3, mm_char_space); } template< typename CharT > @@ -203,11 +202,8 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b char_type* buf_begin = buf + 1u; // skip the first space of the first chunk char_type* buf_end = buf + stride * 3u; - __m256i mm_char_10_to_a; - if (strm.flags() & std::ios_base::uppercase) - mm_char_10_to_a = _mm256_set1_epi32(0x07070707); // '9' is 0x39 and 'A' is 0x41 in ASCII, so we have to add 0x07 to 0x3A to get uppercase letters - else - mm_char_10_to_a = _mm256_set1_epi32(0x27272727); // ...and 'a' is 0x61, which means we have to add 0x27 to 0x3A to get lowercase letters + const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; + const __m256i mm_char_table = _mm256_broadcastsi128_si256(_mm_loadu_si128(reinterpret_cast< const __m128i* >(char_table))); // First, check the input alignment. Also, if we can dump the whole data in one go, do it right away. It turns out to be faster than splitting // the work between prealign and tail part. It is also a fairly common case since on most platforms memory is not aligned to 32 bytes (i.e. prealign is often needed). @@ -215,11 +211,11 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b const std::size_t prealign_size = size == 32u ? static_cast< std::size_t >(32u) : static_cast< std::size_t >((32u - ((uintptr_t)p & 31u)) & 31u); if (prealign_size) { - __m256i mm_input = _mm256_lddqu_si256(reinterpret_cast< const __m256i* >(p)); - BOOST_LOG_AUX_MM_CONSTANTS + __m256i mm_input = _mm256_loadu_si256(reinterpret_cast< const __m256i* >(p)); + BOOST_LOG_AUX_MM256_CONSTANTS __m256i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack(BOOST_LOG_AUX_MM256_CONSTANT_ARGS mm_char_table, mm_input, mm_output1, mm_output2, mm_output3); store_characters_x3(mm_output1, mm_output2, mm_output3, buf); @@ -236,13 +232,13 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b for (std::size_t i = 0; i < stride_count; ++i) { char_type* b = buf; - BOOST_LOG_AUX_MM_CONSTANTS + BOOST_LOG_AUX_MM256_CONSTANTS for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 32u, p += 32u) { __m256i mm_input = _mm256_load_si256(reinterpret_cast< const __m256i* >(p)); __m256i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack(BOOST_LOG_AUX_MM256_CONSTANT_ARGS mm_char_table, mm_input, mm_output1, mm_output2, mm_output3); store_characters_x3(mm_output1, mm_output2, mm_output3, b); } @@ -258,10 +254,10 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b while (tail_size >= 16u) { __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p)); - BOOST_LOG_AUX_MM_CONSTANTS + BOOST_LOG_AUX_MM128_CONSTANTS __m128i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack(BOOST_LOG_AUX_MM128_CONSTANT_ARGS _mm256_castsi256_si128(mm_char_table), mm_input, mm_output1, mm_output2, mm_output3); store_characters(mm_output1, b); store_characters(mm_output2, b + 16u); @@ -273,7 +269,6 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b } _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call - const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u) { uint32_t n = *p; @@ -286,6 +281,12 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b } } +#undef BOOST_LOG_AUX_MM256_CONSTANT_ARGS_DECL +#undef BOOST_LOG_AUX_MM256_CONSTANT_ARGS +#undef BOOST_LOG_AUX_MM256_CONSTANTS +#undef BOOST_LOG_AUX_MM128_CONSTANT_ARGS_DECL +#undef BOOST_LOG_AUX_MM128_CONSTANT_ARGS + } // namespace void dump_data_char_avx2(const void* data, std::size_t size, std::basic_ostream< char >& strm) diff --git a/src/dump_ssse3.cpp b/src/dump_ssse3.cpp index 1325b49c04..c19170655f 100644 --- a/src/dump_ssse3.cpp +++ b/src/dump_ssse3.cpp @@ -47,6 +47,37 @@ enum stride = packs_per_stride * 16 }; +template< typename CharT > +BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf) +{ + switch (sizeof(CharT)) + { + case 1: + _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars); + break; + + case 2: + { + __m128i mm_0 = _mm_setzero_si128(); + _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi8(mm_chars, mm_0)); + _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi8(mm_chars, mm_0)); + } + break; + + case 4: + { + __m128i mm_0 = _mm_setzero_si128(); + __m128i mm = _mm_unpacklo_epi8(mm_chars, mm_0); + _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi16(mm, mm_0)); + _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi16(mm, mm_0)); + mm = _mm_unpackhi_epi8(mm_chars, mm_0); + _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 2, _mm_unpacklo_epi16(mm, mm_0)); + _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 3, _mm_unpackhi_epi16(mm, mm_0)); + } + break; + } +} + union xmm_constant { uint8_t as_bytes[16]; @@ -59,6 +90,158 @@ static const xmm_constant mm_shuffle_pattern1 = {{ 0x80, 0, 1, 0x80, 2, 3, 0x80, static const xmm_constant mm_shuffle_pattern2 = {{ 0, 1, 0x80, 2, 3, 0x80, 4, 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10 }}; static const xmm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x80, 10, 11, 0x80, 12, 13, 0x80, 14, 15 }}; +#if defined(BOOST_LOG_AUX_X86_64) + +// x86-64 architecture has more registers which we can utilize to pass constants +#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL __m128i mm_15, __m128i mm_char_space, +#define BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_15, mm_char_space, +#define BOOST_LOG_AUX_MM_CONSTANTS \ + const __m128i mm_15 = _mm_set1_epi32(0x0F0F0F0F);\ + const __m128i mm_char_space = _mm_set1_epi32(0x20202020); + +#else + +// MSVC in 32-bit mode is not able to pass all constants to dump_pack, and is also not able to align them on the stack, so we have to fetch them from global constants +static const xmm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }}; +static const xmm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }}; +#define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL +#define BOOST_LOG_AUX_MM_CONSTANT_ARGS +#define BOOST_LOG_AUX_MM_CONSTANTS + +#endif + +//! Dumps a pack of input data into a string of 8 bit ASCII characters +static BOOST_FORCEINLINE void dump_pack +( + BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL + __m128i mm_char_table, __m128i mm_input, + __m128i& mm_output1, __m128i& mm_output2, __m128i& mm_output3 +) +{ + // Split half-bytes + __m128i mm_input_hi = _mm_and_si128(_mm_srli_epi16(mm_input, 4), mm_15); + __m128i mm_input_lo = _mm_and_si128(mm_input, mm_15); + + // Stringize each of the halves + mm_input_hi = _mm_shuffle_epi8(mm_char_table, mm_input_hi); + mm_input_lo = _mm_shuffle_epi8(mm_char_table, mm_input_lo); + + // Join them back together + __m128i mm_1 = _mm_unpacklo_epi8(mm_input_hi, mm_input_lo); + __m128i mm_2 = _mm_unpackhi_epi8(mm_input_hi, mm_input_lo); + + // Insert spaces between stringized bytes: + // |0123456789abcdef|0123456789abcdef| + // | 01 23 45 67 89 |ab cd ef 01 23 4|5 67 89 ab cd ef| + mm_output1 = _mm_shuffle_epi8(mm_1, mm_shuffle_pattern1.as_mm); + mm_output2 = _mm_shuffle_epi8(_mm_alignr_epi8(mm_2, mm_1, 10), mm_shuffle_pattern2.as_mm); + mm_output3 = _mm_shuffle_epi8(mm_2, mm_shuffle_pattern3.as_mm); + + mm_output1 = _mm_max_epu8(mm_output1, mm_char_space); + mm_output2 = _mm_max_epu8(mm_output2, mm_char_space); + mm_output3 = _mm_max_epu8(mm_output3, mm_char_space); +} + +template< typename CharT > +BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std::basic_ostream< CharT >& strm) +{ + typedef CharT char_type; + + char_type buf_storage[stride * 3u + 16u]; + // Align the temporary buffer at 16 bytes + char_type* const buf = reinterpret_cast< char_type* >((uint8_t*)buf_storage + (16u - (((uintptr_t)(char_type*)buf_storage) & 15u))); + char_type* buf_begin = buf + 1u; // skip the first space of the first chunk + char_type* buf_end = buf + stride * 3u; + + const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; + const __m128i mm_char_table = +#if !defined(BOOST_NO_ALIGNMENT) + _mm_load_si128(reinterpret_cast< const __m128i* >(char_table)); +#else + _mm_lddqu_si128(reinterpret_cast< const __m128i* >(char_table)); +#endif + + // First, check the input alignment + const uint8_t* p = static_cast< const uint8_t* >(data); + const std::size_t prealign_size = ((16u - ((uintptr_t)p & 15u)) & 15u); + if (BOOST_UNLIKELY(prealign_size > 0)) + { + __m128i mm_input = _mm_lddqu_si128(reinterpret_cast< const __m128i* >(p)); + BOOST_LOG_AUX_MM_CONSTANTS + + __m128i mm_output1, mm_output2, mm_output3; + dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_table, mm_input, mm_output1, mm_output2, mm_output3); + + store_characters(mm_output1, buf); + store_characters(mm_output2, buf + 16u); + store_characters(mm_output3, buf + 32u); + + strm.write(buf_begin, prealign_size * 3u - 1u); + + buf_begin = buf; + size -= prealign_size; + p += prealign_size; + } + + const std::size_t stride_count = size / stride; + std::size_t tail_size = size % stride; + for (std::size_t i = 0; i < stride_count; ++i) + { + char_type* b = buf; + BOOST_LOG_AUX_MM_CONSTANTS + + for (unsigned int j = 0; j < packs_per_stride; ++j, b += 3u * 16u, p += 16u) + { + __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p)); + __m128i mm_output1, mm_output2, mm_output3; + dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_table, mm_input, mm_output1, mm_output2, mm_output3); + + store_characters(mm_output1, b); + store_characters(mm_output2, b + 16u); + store_characters(mm_output3, b + 32u); + } + + strm.write(buf_begin, buf_end - buf_begin); + buf_begin = buf; + } + + if (BOOST_UNLIKELY(tail_size > 0)) + { + char_type* b = buf; + while (tail_size >= 16u) + { + __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p)); + BOOST_LOG_AUX_MM_CONSTANTS + + __m128i mm_output1, mm_output2, mm_output3; + dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_table, mm_input, mm_output1, mm_output2, mm_output3); + + store_characters(mm_output1, b); + store_characters(mm_output2, b + 16u); + store_characters(mm_output3, b + 32u); + + b += 3u * 16u; + p += 16u; + tail_size -= 16u; + } + + for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u) + { + uint32_t n = *p; + b[0] = static_cast< char_type >(' '); + b[1] = static_cast< char_type >(char_table[n >> 4]); + b[2] = static_cast< char_type >(char_table[n & 0x0F]); + } + + strm.write(buf_begin, b - buf_begin); + } +} + +#undef BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL +#undef BOOST_LOG_AUX_MM_CONSTANT_ARGS +#undef BOOST_LOG_AUX_MM_CONSTANTS + + #if defined(BOOST_LOG_AUX_X86_64) // x86-64 architecture has more registers which we can utilize to pass constants @@ -73,10 +256,8 @@ static const xmm_constant mm_shuffle_pattern3 = {{ 5, 0x80, 6, 7, 0x80, 8, 9, 0x #else // MSVC in 32-bit mode is not able to pass all constants to dump_pack, and is also not able to align them on the stack, so we have to fetch them from global constants -static const xmm_constant mm_15 = {{ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F }}; static const xmm_constant mm_9 = {{ 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09, 0x09 }}; static const xmm_constant mm_char_0 = {{ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30 }}; -static const xmm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20 }}; #define BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL #define BOOST_LOG_AUX_MM_CONSTANT_ARGS #define BOOST_LOG_AUX_MM_CONSTANTS @@ -84,7 +265,7 @@ static const xmm_constant mm_char_space = {{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, #endif //! Dumps a pack of input data into a string of 8 bit ASCII characters -static BOOST_FORCEINLINE void dump_pack +static BOOST_FORCEINLINE void dump_pack_slow_pshufb ( BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL __m128i mm_char_10_to_a, __m128i mm_input, @@ -124,38 +305,7 @@ static BOOST_FORCEINLINE void dump_pack } template< typename CharT > -BOOST_FORCEINLINE void store_characters(__m128i mm_chars, CharT* buf) -{ - switch (sizeof(CharT)) - { - case 1: - _mm_store_si128(reinterpret_cast< __m128i* >(buf), mm_chars); - break; - - case 2: - { - __m128i mm_0 = _mm_setzero_si128(); - _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi8(mm_chars, mm_0)); - _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi8(mm_chars, mm_0)); - } - break; - - case 4: - { - __m128i mm_0 = _mm_setzero_si128(); - __m128i mm = _mm_unpacklo_epi8(mm_chars, mm_0); - _mm_store_si128(reinterpret_cast< __m128i* >(buf), _mm_unpacklo_epi16(mm, mm_0)); - _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 1, _mm_unpackhi_epi16(mm, mm_0)); - mm = _mm_unpackhi_epi8(mm_chars, mm_0); - _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 2, _mm_unpacklo_epi16(mm, mm_0)); - _mm_store_si128(reinterpret_cast< __m128i* >(buf) + 3, _mm_unpackhi_epi16(mm, mm_0)); - } - break; - } -} - -template< typename CharT > -BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std::basic_ostream< CharT >& strm) +BOOST_FORCEINLINE void dump_data_ssse3_slow_pshufb(const void* data, std::size_t size, std::basic_ostream< CharT >& strm) { typedef CharT char_type; @@ -180,7 +330,7 @@ BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std:: BOOST_LOG_AUX_MM_CONSTANTS __m128i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack_slow_pshufb(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); store_characters(mm_output1, buf); store_characters(mm_output2, buf + 16u); @@ -204,7 +354,7 @@ BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std:: { __m128i mm_input = _mm_load_si128(reinterpret_cast< const __m128i* >(p)); __m128i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack_slow_pshufb(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); store_characters(mm_output1, b); store_characters(mm_output2, b + 16u); @@ -224,7 +374,7 @@ BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std:: BOOST_LOG_AUX_MM_CONSTANTS __m128i mm_output1, mm_output2, mm_output3; - dump_pack(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); + dump_pack_slow_pshufb(BOOST_LOG_AUX_MM_CONSTANT_ARGS mm_char_10_to_a, mm_input, mm_output1, mm_output2, mm_output3); store_characters(mm_output1, b); store_characters(mm_output2, b + 16u); @@ -248,6 +398,10 @@ BOOST_FORCEINLINE void dump_data_ssse3(const void* data, std::size_t size, std:: } } +#undef BOOST_LOG_AUX_MM_CONSTANT_ARGS_DECL +#undef BOOST_LOG_AUX_MM_CONSTANT_ARGS +#undef BOOST_LOG_AUX_MM_CONSTANTS + } // namespace void dump_data_char_ssse3(const void* data, std::size_t size, std::basic_ostream< char >& strm) @@ -302,6 +456,58 @@ void dump_data_char32_ssse3(const void* data, std::size_t size, std::basic_ostre } #endif +void dump_data_char_ssse3_slow_pshufb(const void* data, std::size_t size, std::basic_ostream< char >& strm) +{ + if (size >= 16) + { + dump_data_ssse3_slow_pshufb(data, size, strm); + } + else + { + dump_data_generic(data, size, strm); + } +} + +void dump_data_wchar_ssse3_slow_pshufb(const void* data, std::size_t size, std::basic_ostream< wchar_t >& strm) +{ + if (size >= 16) + { + dump_data_ssse3_slow_pshufb(data, size, strm); + } + else + { + dump_data_generic(data, size, strm); + } +} + +#if !defined(BOOST_NO_CXX11_CHAR16_T) +void dump_data_char16_ssse3_slow_pshufb(const void* data, std::size_t size, std::basic_ostream< char16_t >& strm) +{ + if (size >= 16) + { + dump_data_ssse3_slow_pshufb(data, size, strm); + } + else + { + dump_data_generic(data, size, strm); + } +} +#endif + +#if !defined(BOOST_NO_CXX11_CHAR32_T) +void dump_data_char32_ssse3_slow_pshufb(const void* data, std::size_t size, std::basic_ostream< char32_t >& strm) +{ + if (size >= 16) + { + dump_data_ssse3_slow_pshufb(data, size, strm); + } + else + { + dump_data_generic(data, size, strm); + } +} +#endif + } // namespace aux BOOST_LOG_CLOSE_NAMESPACE // namespace log From b15d02ab3b14bfbae1be4290eb24d57d0ef0e376 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 25 Oct 2021 01:34:56 +0300 Subject: [PATCH 165/309] Added workarounds of older gcc and clang for AVX2 dump implementation. Use inline asm instead of _mm256_broadcastsi128_si256 to work around issues: - gcc 4.7 is missing _mm256_broadcastsi128_si256 declaration in immintrin.h. - gcc 4.8 generates vmovdqu+vinserti128 instead of a single vbroadcasti128. - clang up until 4.0 generates vmovdqu+vinserti128 or worse. --- src/dump_avx2.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/dump_avx2.cpp b/src/dump_avx2.cpp index a67d40b4fb..b3ac4962d1 100644 --- a/src/dump_avx2.cpp +++ b/src/dump_avx2.cpp @@ -203,7 +203,15 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b char_type* buf_end = buf + stride * 3u; const char* const char_table = g_hex_char_table[(strm.flags() & std::ios_base::uppercase) != 0]; +#if defined(__GNUC__) && ((defined(BOOST_GCC) && BOOST_GCC < 40900) || (defined(BOOST_CLANG) && BOOST_CLANG_VERSION < 40000)) + // gcc 4.7 is missing _mm256_broadcastsi128_si256 declaration in immintrin.h. + // gcc 4.8 generates vmovdqu+vinserti128 instead of a single vbroadcasti128. + // clang up until 4.0 generates vmovdqu+vinserti128 or worse. + __m256i mm_char_table; + __asm__("vbroadcasti128 %1, %0" : "=x" (mm_char_table) : "m" (*reinterpret_cast< const __m128i* >(char_table))); +#else const __m256i mm_char_table = _mm256_broadcastsi128_si256(_mm_loadu_si128(reinterpret_cast< const __m128i* >(char_table))); +#endif // First, check the input alignment. Also, if we can dump the whole data in one go, do it right away. It turns out to be faster than splitting // the work between prealign and tail part. It is also a fairly common case since on most platforms memory is not aligned to 32 bytes (i.e. prealign is often needed). From 9238377f1f92ea689d45f51d934246f41e98d0ec Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 25 Oct 2021 01:51:17 +0300 Subject: [PATCH 166/309] Corrected placement of alignas. --- src/dump.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dump.cpp b/src/dump.cpp index e66013fa30..bd6375000a 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -60,7 +60,7 @@ extern dump_data_char32_t dump_data_char32_avx2; enum { stride = 256 }; -extern BOOST_ALIGNMENT(16) const char g_hex_char_table[2][16] = +BOOST_ALIGNMENT(16) extern const char g_hex_char_table[2][16] = { { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' }, { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' } From 6c9d326e5b229684a78bfcb3f8a6251a04c06047 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 25 Oct 2021 01:58:04 +0300 Subject: [PATCH 167/309] Updated copyright years. --- src/dump.cpp | 2 +- src/dump_avx2.cpp | 2 +- src/dump_ssse3.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index bd6375000a..812687931a 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/dump_avx2.cpp b/src/dump_avx2.cpp index b3ac4962d1..a6745046db 100644 --- a/src/dump_avx2.cpp +++ b/src/dump_avx2.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) diff --git a/src/dump_ssse3.cpp b/src/dump_ssse3.cpp index c19170655f..84ef2054ad 100644 --- a/src/dump_ssse3.cpp +++ b/src/dump_ssse3.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2021. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) From 832979ebd27fdb87bfc622c46a9285c50a55b0d6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 25 Oct 2021 01:58:30 +0300 Subject: [PATCH 168/309] Added clang-win jobs to AppVeyor CI. --- appveyor.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 09b4c1248d..7b1c92fc79 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -56,6 +56,11 @@ environment: CXXSTD: 03,11,14,17 ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: clang-win + ADDRESS_MODEL: 64 + CXXSTD: 14,17 + ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: msvc-9.0 ADDRESS_MODEL: 32 @@ -95,6 +100,11 @@ environment: CXXSTD: 03,11,14 ADDPATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + - TOOLSET: clang-win + ADDRESS_MODEL: 32 + CXXSTD: 14,17 + ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 install: - set GIT_FETCH_JOBS=8 @@ -113,12 +123,13 @@ install: - if not "%EXTRA_TESTS%" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include=example" - python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" log - cmd /c bootstrap - - b2 headers + - b2 -d0 headers build: off test_script: - PATH=%ADDPATH%;%PATH% + - if not "%ENV_SCRIPT%" == "" call "%ENV_SCRIPT%" - if "%EXTRA_TESTS%" == "" set BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 & set BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - b2 -j %NUMBER_OF_PROCESSORS% libs/log/test variant=release toolset=%TOOLSET% address-model=%ADDRESS_MODEL% %CXXSTD% %B2_ARGS% From e957369c806e9c6c08e5e8e5a6a979fcee9bda9e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 26 Oct 2021 00:56:17 +0300 Subject: [PATCH 169/309] Explicitly specify attribute value type for make_attr_ordering in examples. C++20 removed argument type typedefs in standard function objects, which made it impossible to deduce the attribute value type from the standard function objects. This caused compilation errors with VS2022 in C++20 mode. --- example/bounded_async_log/main.cpp | 2 +- example/doc/sinks_async_ordering.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/example/bounded_async_log/main.cpp b/example/bounded_async_log/main.cpp index 14dee2f5ee..50e347d328 100644 --- a/example/bounded_async_log/main.cpp +++ b/example/bounded_async_log/main.cpp @@ -88,7 +88,7 @@ int main(int argc, char* argv[]) shared_ptr< sink_t > sink(new sink_t( boost::make_shared< backend_t >(), // We'll apply record ordering to ensure that records from different threads go sequentially in the file - keywords::order = logging::make_attr_ordering("RecordID", std::less< unsigned int >()))); + keywords::order = logging::make_attr_ordering< unsigned int >("RecordID", std::less< unsigned int >()))); sink->locked_backend()->add_stream(strm); diff --git a/example/doc/sinks_async_ordering.cpp b/example/doc/sinks_async_ordering.cpp index b642b5b6ac..3f72ee8499 100644 --- a/example/doc/sinks_async_ordering.cpp +++ b/example/doc/sinks_async_ordering.cpp @@ -60,8 +60,8 @@ boost::shared_ptr< sink_t > init_logging() // Wrap it into the frontend and register in the core boost::shared_ptr< sink_t > sink(new sink_t( backend, /*< pointer to the pre-initialized backend >*/ - keywords::order = - logging::make_attr_ordering("LineID", std::less< unsigned int >()), /*< log record ordering predicate >*/ + keywords::order = logging::make_attr_ordering< unsigned int >( /*< log record ordering predicate >*/ + "LineID", std::less< unsigned int >()), keywords::ordering_window = boost::posix_time::seconds(1) /*< latency of log record processing >*/ )); core->add_sink(sink); From dd164ac8d0205c6ddcca9d74b106361eda5d5b88 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 29 Oct 2021 04:14:58 +0300 Subject: [PATCH 170/309] Changed SSSE3/AVX2 checks to be linkable into an executable. --- config/x86-ext/avx2.cpp | 7 +++---- config/x86-ext/ssse3.cpp | 7 +++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/config/x86-ext/avx2.cpp b/config/x86-ext/avx2.cpp index 3ee051f173..56111d90dd 100644 --- a/config/x86-ext/avx2.cpp +++ b/config/x86-ext/avx2.cpp @@ -6,15 +6,14 @@ */ #include - -void pretend_used(__m256i*); +#include int main(int, char*[]) { __m256i mm = _mm256_setzero_si256(); - pretend_used(&mm); + fread(&mm, 1u, sizeof(mm), stdin); mm = _mm256_shuffle_epi8(_mm256_alignr_epi8(mm, mm, 10), mm); - pretend_used(&mm); + fwrite(&mm, 1u, sizeof(mm), stdout); _mm256_zeroupper(); return 0; } diff --git a/config/x86-ext/ssse3.cpp b/config/x86-ext/ssse3.cpp index 4bcfe2bc75..f577f4e060 100644 --- a/config/x86-ext/ssse3.cpp +++ b/config/x86-ext/ssse3.cpp @@ -6,14 +6,13 @@ */ #include - -void pretend_used(__m128i*); +#include int main(int, char*[]) { __m128i mm = _mm_setzero_si128(); - pretend_used(&mm); + fread(&mm, 1u, sizeof(mm), stdin); mm = _mm_shuffle_epi8(_mm_alignr_epi8(mm, mm, 10), mm); - pretend_used(&mm); + fwrite(&mm, 1u, sizeof(mm), stdout); return 0; } From 1303a7a92c210c5c0b072be69ec499b157aa2268 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 30 Oct 2021 00:10:08 +0300 Subject: [PATCH 171/309] Suppress MSVC warning about possible loss of data. --- src/code_conversion.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/code_conversion.cpp b/src/code_conversion.cpp index d75d2a61ae..b0820ee93c 100644 --- a/src/code_conversion.cpp +++ b/src/code_conversion.cpp @@ -65,6 +65,14 @@ inline std::codecvt_base::result convert( } // namespace +#if defined(BOOST_MSVC) +#pragma warning(push) +// conversion from 'X' to 'Y', possible loss of data +// This warning is triggered for the noconv case below, where we convert wchar_t to char if the locale facet +// reports that no code conversion is needed. In such a case, no data loss will happen. +#pragma warning(disable: 4244) +#endif + template< typename SourceCharT, typename TargetCharT, typename FacetT > inline std::size_t code_convert(const SourceCharT* begin, const SourceCharT* end, std::basic_string< TargetCharT >& converted, std::size_t max_size, FacetT const& fac) { @@ -138,6 +146,10 @@ inline std::size_t code_convert(const SourceCharT* begin, const SourceCharT* end return static_cast< std::size_t >(begin - original_begin); } +#if defined(BOOST_MSVC) +#pragma warning(pop) +#endif + //! The function converts one string to the character type of another BOOST_LOG_API bool code_convert_impl(const wchar_t* str1, std::size_t len, std::string& str2, std::size_t max_size, std::locale const& loc) { From 2985dfecc02623a554a2ff4622b3f754bd33d817 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 29 Oct 2021 04:32:24 +0300 Subject: [PATCH 172/309] Added CMake build script and test. --- .github/workflows/ci.yml | 8 +- CMakeLists.txt | 661 +++++++++++++++++++++++++++++ appveyor.yml | 24 +- test/test_cmake/CMakeLists.txt | 27 ++ test/test_cmake/log_setup_test.cpp | 16 + test/test_cmake/log_test.cpp | 19 + 6 files changed, 751 insertions(+), 4 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 test/test_cmake/CMakeLists.txt create mode 100644 test/test_cmake/log_setup_test.cpp create mode 100644 test/test_cmake/log_test.cpp diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dd9e2e80ba..1d0ca41258 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -238,9 +238,9 @@ jobs: cxxstd: "03,11,14,17,2a" os: macos-10.15 - # - name: CMake tests - # cmake_tests: 1 - # os: ubuntu-20.04 + - name: CMake tests + cmake_tests: 1 + os: ubuntu-20.04 timeout-minutes: 120 runs-on: ${{matrix.os}} @@ -446,7 +446,9 @@ jobs: mkdir __build_static__ && cd __build_static__ cmake ../libs/$LIBRARY/test/test_cmake cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS + cmake --build . --target boost_${LIBRARY}_setup_cmake_self_test -j $BUILD_JOBS cd .. mkdir __build_shared__ && cd __build_shared__ cmake -DBUILD_SHARED_LIBS=On ../libs/$LIBRARY/test/test_cmake cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS + cmake --build . --target boost_${LIBRARY}_setup_cmake_self_test -j $BUILD_JOBS diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..910fab2d81 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,661 @@ +# Copyright 2021 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt + +cmake_minimum_required(VERSION 3.5) +project(BoostLog VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) + +include(CheckCXXSourceCompiles) + +set(BOOST_LOG_NO_THREADS OFF CACHE BOOL "Disable multithreading support in Boost.Log") +set(BOOST_LOG_WITHOUT_CHAR OFF CACHE BOOL "Disable support for narrow character logging in Boost.Log") +set(BOOST_LOG_WITHOUT_WCHAR_T OFF CACHE BOOL "Disable support for wide character logging in Boost.Log") +set(BOOST_LOG_WITHOUT_DEFAULT_FACTORIES OFF CACHE BOOL "Disable default factories for filters and formatters in Boost.Log") +set(BOOST_LOG_WITHOUT_SETTINGS_PARSERS OFF CACHE BOOL "Disable settings, filter and formatter parsers in Boost.Log") +if (WIN32) + set(BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER OFF CACHE BOOL "Disable using QueryPerformanceCounter API on Windows in Boost.Log") + set(BOOST_LOG_WITHOUT_DEBUG_OUTPUT OFF CACHE BOOL "Disable support for debugger output on Windows in Boost.Log") + set(BOOST_LOG_WITHOUT_EVENT_LOG OFF CACHE BOOL "Disable support for event log on Windows in Boost.Log") +endif() +set(BOOST_LOG_WITHOUT_IPC OFF CACHE BOOL "Disable support for inter-process communication in Boost.Log") +set(BOOST_LOG_WITHOUT_SYSLOG OFF CACHE BOOL "Disable support for syslog API in Boost.Log") +set(BOOST_LOG_USE_NATIVE_SYSLOG OFF CACHE BOOL "Force-enable using native syslog API in Boost.Log") +set(BOOST_LOG_USE_COMPILER_TLS OFF CACHE BOOL "Enable using compiler-specific intrinsics for thread-local storage in Boost.Log") + +set(BOOST_LOG_REGEX_BACKENDS "std::regex" "Boost.Regex" "Boost.Xpressive") +set(BOOST_LOG_USE_REGEX_BACKEND "Boost.Regex" CACHE STRING "Regular expressions backend to use in Boost.Log") +set_property(CACHE BOOST_LOG_USE_REGEX_BACKEND PROPERTY STRINGS ${BOOST_LOG_REGEX_BACKENDS}) +if (NOT BOOST_LOG_USE_REGEX_BACKEND IN_LIST BOOST_LOG_REGEX_BACKENDS) + message(FATAL_ERROR "BOOST_LOG_USE_REGEX_BACKEND must be one of: ${BOOST_LOG_REGEX_BACKENDS}") +endif() + +if (NOT BOOST_LOG_NO_THREADS) + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) +endif() + +# Generates a list of include paths for all Boost libraries in \a result variable. Uses unified Boost include tree, if available. +function(generate_boost_include_paths result) + if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../boost" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../boost/version.hpp") + set(${result} "${CMAKE_CURRENT_SOURCE_DIR}/../.." PARENT_SCOPE) + return() + endif() + file(GLOB path_list LIST_DIRECTORIES True "${CMAKE_CURRENT_SOURCE_DIR}/../*") + foreach(path IN LISTS path_list) + if (IS_DIRECTORY "${path}/include") + list(APPEND include_list "${path}/include") + endif() + endforeach() + set(${result} ${include_list} PARENT_SCOPE) +endfunction() + +# Note: We can't use the Boost::library targets in the configure checks as they may not yet be included +# by the superproject when this CMakeLists.txt is included. We also don't want to hardcode include paths +# of the needed libraries and their dependencies, recursively, as this is too fragile and requires maintenance. +# Instead, we collect include paths of all libraries and use them in the configure checks. This works faster +# if there is a unified Boost include tree in the filesystem (i.e. if `b2 headers` was run or we're in the +# official monolithic Boost distribution tree). +generate_boost_include_paths(BOOST_LIBRARY_INCLUDES) + +set(CMAKE_REQUIRED_INCLUDES ${BOOST_LIBRARY_INCLUDES}) + +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/../config/checks/architecture/x86.cpp>\nint main() {}" BOOST_LOG_TARGET_X86) + +set(CMAKE_REQUIRED_DEFINITIONS "-DBOOST_ALL_NO_LIB") +check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/atomic-int32/atomic_int32.cpp>" BOOST_LOG_HAS_LOCK_FREE_ATOMIC_INT32) +unset(CMAKE_REQUIRED_DEFINITIONS) + +if (BOOST_LOG_TARGET_X86) + if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + if (CMAKE_SIZEOF_VOID_P EQUAL 4) + set(boost_log_ssse3_cflags "/arch:SSE2") + set(boost_log_avx2_cflags "/arch:AVX") + endif() + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + if (WIN32) + set(boost_log_ssse3_cflags "/QxSSSE3") + set(boost_log_avx2_cflags "/arch:CORE-AVX2") + else() + set(boost_log_ssse3_cflags "-xSSSE3") + set(boost_log_avx2_cflags "-xCORE-AVX2 -fabi-version=0") + endif() + else() + set(boost_log_ssse3_cflags "-msse -msse2 -msse3 -mssse3") + set(boost_log_avx2_cflags "-mavx -mavx2") + if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + string(APPEND boost_log_avx2_cflags " -fabi-version=0") + endif() + endif() + + set(CMAKE_REQUIRED_FLAGS "${boost_log_ssse3_cflags}") + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/x86-ext/ssse3.cpp>" BOOST_LOG_COMPILER_HAS_SSSE3) + unset(CMAKE_REQUIRED_FLAGS) + set(CMAKE_REQUIRED_FLAGS "${boost_log_avx2_cflags}") + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/x86-ext/avx2.cpp>" BOOST_LOG_COMPILER_HAS_AVX2) + unset(CMAKE_REQUIRED_FLAGS) +endif() + +if (NOT BOOST_LOG_WITHOUT_SYSLOG AND NOT BOOST_LOG_USE_NATIVE_SYSLOG) + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/native-syslog/native_syslog.cpp>" BOOST_LOG_HAS_NATIVE_SYSLOG) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + # Solaris headers are broken and cannot be included in C++03 when _XOPEN_SOURCE=600. At the same time, they cannot be included with _XOPEN_SOURCE=500 in C++11 and later. + # This is because the system headers check the C language version and error out if the version does not match. We have to test if we can request _XOPEN_SOURCE=600. + check_cxx_source_compiles("#include <${CMAKE_CURRENT_SOURCE_DIR}/config/xopen-source-600/xopen_source_600.cpp>" BOOST_LOG_HAS_XOPEN_SOURCE_600) +endif() + +unset(CMAKE_REQUIRED_INCLUDES) + +set(boost_log_common_public_defines + # NOTE: + # We deactivate autolinking, because cmake based builds don't need it + # and we don't implement name mangling for the library file anyway. + # Ususally the parent CMakeLists.txt file should already have globally defined BOOST_ALL_NO_LIB + BOOST_LOG_NO_LIB +) + +set(boost_log_common_private_defines + __STDC_CONSTANT_MACROS + BOOST_SPIRIT_USE_PHOENIX_V3=1 + BOOST_THREAD_DONT_USE_CHRONO=1 # Don't introduce false dependency on Boost.Chrono +) + +set(boost_log_private_defines + BOOST_LOG_BUILDING_THE_LIB +) + +set(boost_log_setup_private_defines + BOOST_LOG_SETUP_BUILDING_THE_LIB +) + +if (BUILD_SHARED_LIBS) + list(APPEND boost_log_common_public_defines BOOST_LOG_DYN_LINK) + list(APPEND boost_log_private_defines BOOST_LOG_DLL) + list(APPEND boost_log_setup_private_defines BOOST_LOG_SETUP_DLL) +else() + list(APPEND boost_log_common_public_defines BOOST_LOG_STATIC_LINK) +endif() + +set(boost_log_sources + src/alignment_gap_between.hpp + src/attribute_name.cpp + src/attribute_set_impl.hpp + src/attribute_set.cpp + src/attribute_value_set.cpp + src/bit_tools.hpp + src/code_conversion.cpp + src/stateless_allocator.hpp + src/unique_ptr.hpp + src/core.cpp + src/record_ostream.cpp + src/severity_level.cpp + src/global_logger_storage.cpp + src/named_scope.cpp + src/process_name.cpp + src/process_id.cpp + src/thread_id.cpp + src/id_formatting.hpp + src/murmur3.hpp + src/timer.cpp + src/exceptions.cpp + src/default_attribute_names.cpp + src/default_sink.hpp + src/default_sink.cpp + src/text_ostream_backend.cpp + src/text_file_backend.cpp + src/text_multifile_backend.cpp + src/thread_specific.cpp + src/once_block.cpp + src/timestamp.cpp + src/threadsafe_queue.cpp + src/event.cpp + src/trivial.cpp + src/spirit_encoding.hpp + src/spirit_encoding.cpp + src/format_parser.cpp + src/date_time_format_parser.cpp + src/named_scope_format_parser.cpp + src/permissions.cpp + src/dump.cpp +) + +if (BOOST_LOG_COMPILER_HAS_SSSE3) + set(boost_log_sources_ssse3 src/dump_ssse3.cpp) + set_source_files_properties(${boost_log_sources_ssse3} PROPERTIES COMPILE_FLAGS "${boost_log_ssse3_cflags}") + list(APPEND boost_log_private_defines BOOST_LOG_USE_SSSE3) +endif() +if (BOOST_LOG_COMPILER_HAS_AVX2) + set(boost_log_sources_avx2 src/dump_avx2.cpp) + set_source_files_properties(${boost_log_sources_avx2} PROPERTIES COMPILE_FLAGS "${boost_log_avx2_cflags}") + list(APPEND boost_log_private_defines BOOST_LOG_USE_AVX2) +endif() + +if (NOT BOOST_LOG_WITHOUT_SYSLOG) + list(APPEND boost_log_sources src/syslog_backend.cpp) + if (BOOST_LOG_USE_NATIVE_SYSLOG OR BOOST_LOG_HAS_NATIVE_SYSLOG) + list(APPEND boost_log_common_private_defines BOOST_LOG_USE_NATIVE_SYSLOG) + endif() +endif() + +if (WIN32) + list(APPEND boost_log_sources + src/windows/light_rw_mutex.cpp + src/windows/is_debugger_present.cpp + ) + list(APPEND boost_log_common_private_defines + # Disable warnings about using 'insecure' standard C functions. + # These affect MSVC C/C++ library headers, which are used by various compilers. + _SCL_SECURE_NO_WARNINGS + _SCL_SECURE_NO_DEPRECATE + _CRT_SECURE_NO_WARNINGS + _CRT_SECURE_NO_DEPRECATE + ) + + if (NOT BOOST_LOG_WITHOUT_DEBUG_OUTPUT) + list(APPEND boost_log_sources src/windows/debug_output_backend.cpp) + endif() + + if (NOT BOOST_LOG_WITHOUT_IPC) + list(APPEND boost_log_sources + src/windows/auto_handle.hpp + src/windows/object_name.cpp + src/windows/utf_code_conversion.hpp + src/windows/mapped_shared_memory.hpp + src/windows/mapped_shared_memory.cpp + src/windows/ipc_sync_wrappers.hpp + src/windows/ipc_sync_wrappers.cpp + src/windows/ipc_reliable_message_queue.cpp + ) + list(APPEND boost_log_private_libs + secur32 + ) + endif() + + if (NOT BOOST_LOG_WITHOUT_EVENT_LOG) + # Find message compiler (mc) + if (NOT CMAKE_MC_COMPILER AND DEFINED ENV{MC} AND EXISTS "$ENV{MC}" AND NOT IS_DIRECTORY "$ENV{MC}") + set(CMAKE_MC_COMPILER "$ENV{MC}") + endif() + if (NOT CMAKE_MC_COMPILER) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(mc_executable "windmc.exe") + else() + set(mc_executable "mc.exe") + endif() + if (CMAKE_RC_COMPILER) + # Use resource compiler directory as a hint. CMake will initialize CMAKE_RC_COMPILER + # automatically based on environment variables, and message compiler typically resides + # in the same directory in the Windows SDK installation. Reusing resource compiler + # directory also provides user's choice of Windows SDK version and host and target + # architecture. + get_filename_component(rc_compiler_path "${CMAKE_RC_COMPILER}" DIRECTORY) + list(APPEND mc_search_hints "${rc_compiler_path}") + endif() + if (CMAKE_CXX_COMPILER) + # Message compiler can be located next to the compiler, e.g. on MinGW installations. + get_filename_component(cxx_compiler_path "${CMAKE_CXX_COMPILER}" DIRECTORY) + list(APPEND mc_search_hints "${cxx_compiler_path}") + endif() + message(DEBUG "Boost.Log: ${mc_executable} search hints: ${mc_search_hints}") + find_program(CMAKE_MC_COMPILER "${mc_executable}" HINTS "${mc_search_hints}") + if (CMAKE_MC_COMPILER STREQUAL "CMAKE_MC_COMPILER-NOTFOUND") + message(STATUS "Boost.Log: Message compiler ${mc_executable} not found, event log support will be disabled.") + unset(CMAKE_MC_COMPILER) + else() + message(STATUS "Boost.Log: Message compiler found: ${CMAKE_MC_COMPILER}") + endif() + endif() + + if (CMAKE_MC_COMPILER) + add_custom_command( + OUTPUT + "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" + "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" + COMMAND "${CMAKE_MC_COMPILER}" + ARGS + -h "${CMAKE_CURRENT_BINARY_DIR}/src/windows" + -r "${CMAKE_CURRENT_BINARY_DIR}/src/windows" + "${CMAKE_CURRENT_SOURCE_DIR}/src/windows/simple_event_log.mc" + MAIN_DEPENDENCY + "${CMAKE_CURRENT_SOURCE_DIR}/src/windows/simple_event_log.mc" + COMMENT + "Building src/windows/simple_event_log.mc" + VERBATIM + ) + set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" PROPERTIES GENERATED TRUE) + set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" PROPERTIES GENERATED TRUE) + + list(APPEND boost_log_sources + "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" + "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" + src/windows/event_log_registry.hpp + src/windows/event_log_backend.cpp + ) + list(APPEND boost_log_private_libs + psapi + ) + else() + set(BOOST_LOG_WITHOUT_EVENT_LOG ON) + endif() + endif() +else() + if (NOT BOOST_LOG_WITHOUT_IPC) + list(APPEND boost_log_sources + src/posix/object_name.cpp + src/posix/ipc_sync_wrappers.hpp + src/posix/ipc_reliable_message_queue.cpp + ) + endif() +endif() + +if (CYGWIN) + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + set(BOOST_LOG_WITHOUT_IPC ON) + list(APPEND boost_log_common_private_defines + __USE_W32_SOCKETS + _XOPEN_SOURCE=600 + ) +endif() + +if (WIN32 OR CYGWIN) + list(APPEND boost_log_common_private_defines + BOOST_USE_WINDOWS_H + WIN32_LEAN_AND_MEAN + NOMINMAX + SECURITY_WIN32 + ) + list(APPEND boost_log_private_libs + ws2_32 + mswsock + advapi32 + ) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "Linux") + list(APPEND boost_log_common_private_defines _XOPEN_SOURCE=600) + list(APPEND boost_log_private_libs rt) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "FreeBSD") + list(APPEND boost_log_private_libs rt) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "HP-UX") + list(APPEND boost_log_common_private_defines _XOPEN_SOURCE=600) + list(APPEND boost_log_private_libs ipv6) +endif() + +if (CMAKE_SYSTEM_NAME STREQUAL "SunOS") + if (BOOST_LOG_HAS_XOPEN_SOURCE_600) + list(APPEND boost_log_common_private_defines _XOPEN_SOURCE=600) + else() + list(APPEND boost_log_common_private_defines _XOPEN_SOURCE=500) + endif() + list(APPEND boost_log_common_private_defines __EXTENSIONS__) + list(APPEND boost_log_private_libs + socket + nsl + ) +endif() + +if (BOOST_LOG_USE_REGEX_BACKEND STREQUAL "Boost.Regex") + set(boost_log_regex_backend_private_libs Boost::regex) + list(APPEND boost_log_common_private_defines BOOST_LOG_USE_BOOST_REGEX) +elseif (BOOST_LOG_USE_REGEX_BACKEND STREQUAL "Boost.Xpressive") + set(boost_log_regex_backend_private_libs Boost::xpressive) + list(APPEND boost_log_common_private_defines BOOST_LOG_USE_BOOST_XPRESSIVE) +else() + list(APPEND boost_log_common_private_defines BOOST_LOG_USE_STD_REGEX) +endif() + + +if (BOOST_LOG_NO_THREADS) + list(APPEND boost_log_common_public_defines BOOST_LOG_NO_THREADS) +endif() +if (BOOST_LOG_WITHOUT_CHAR) + list(APPEND boost_log_common_public_defines BOOST_LOG_WITHOUT_CHAR) +endif() +if (BOOST_LOG_WITHOUT_WCHAR_T) + list(APPEND boost_log_common_public_defines BOOST_LOG_WITHOUT_WCHAR_T) +endif() +if (BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + list(APPEND boost_log_setup_private_defines BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) +endif() +if (BOOST_LOG_WITHOUT_SETTINGS_PARSERS) + list(APPEND boost_log_setup_private_defines BOOST_LOG_WITHOUT_SETTINGS_PARSERS) +endif() +if (BOOST_LOG_WITHOUT_SYSLOG) + list(APPEND boost_log_common_private_defines BOOST_LOG_WITHOUT_SYSLOG) +endif() +if (BOOST_LOG_WITHOUT_IPC) + list(APPEND boost_log_common_private_defines BOOST_LOG_WITHOUT_IPC) +endif() +if (WIN32) + if (BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER) + list(APPEND boost_log_common_private_defines BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER) + endif() + if (BOOST_LOG_WITHOUT_DEBUG_OUTPUT) + list(APPEND boost_log_common_private_defines BOOST_LOG_WITHOUT_DEBUG_OUTPUT) + endif() + if (BOOST_LOG_WITHOUT_EVENT_LOG) + list(APPEND boost_log_common_private_defines BOOST_LOG_WITHOUT_EVENT_LOG) + endif() +endif() + + +if (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + list(APPEND boost_log_common_private_cxxflags + /bigobj + /wd4503 # decorated name length exceeded, name was truncated + /wd4456 # declaration of 'A' hides previous local declaration + /wd4459 # declaration of 'A' hides global declaration + /wd4003 # not enough actual parameters for macro 'X' - caused by BOOST_PP_IS_EMPTY and BOOST_PP_IS_BEGIN_PARENS which are used by Fusion + ) +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + # Disable Intel warnings: + # warning #177: function "X" was declared but never referenced + # warning #780: using-declaration ignored -- it refers to the current namespace + # warning #2196: routine is both "inline" and "noinline" + # remark #1782: #pragma once is obsolete. Use #ifndef guard instead. + # remark #193: zero used for undefined preprocessing identifier "X" + # remark #304: access control not specified ("public" by default) + # remark #981: operands are evaluated in unspecified order + # remark #1418: external function definition with no prior declaration + # Mostly comes from Boost.Phoenix: warning #411: class "X" defines no constructor to initialize the following: reference member "Y"... + # warning #734: "X" (declared at line N of "file.hpp"), required for copy that was eliminated, is inaccessible + # warning #279: controlling expression is constant + if (WIN32) + list(APPEND boost_log_common_private_cxxflags + "/Qwd177,780,2196,1782,193,304,981,1418,411,734,279" + ) + else() + list(APPEND boost_log_common_private_cxxflags + "-wd177,780,2196,1782,193,304,981,1418,411,734,279" + ) + endif() +endif() + +if ((WIN32 OR CYGWIN) AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + list(APPEND boost_log_common_private_linkflags + -Wl,--enable-auto-import + ) +endif() + + +add_library(boost_log + ${boost_log_sources} + ${boost_log_sources_ssse3} + ${boost_log_sources_avx2} +) +if (BOOST_SUPERPROJECT_VERSION) + set_target_properties(boost_log PROPERTIES VERSION "${BOOST_SUPERPROJECT_VERSION}") +endif() +set(boost_log_install_targets boost_log) +add_library(Boost::log ALIAS boost_log) + +target_include_directories(boost_log + PUBLIC + include + PRIVATE + src + "${CMAKE_CURRENT_BINARY_DIR}/src" +) + +target_link_libraries(boost_log + PUBLIC + Boost::array + Boost::assert + Boost::config + Boost::container + Boost::core + Boost::date_time + Boost::filesystem + Boost::function_types + Boost::fusion + Boost::intrusive + Boost::move + Boost::mpl + Boost::parameter + Boost::phoenix + Boost::predef + Boost::preprocessor + Boost::proto + Boost::range + Boost::smart_ptr + Boost::static_assert + Boost::system + Boost::throw_exception + Boost::type_index + Boost::type_traits + Boost::utility + Boost::winapi + + PRIVATE + Boost::align + Boost::asio + Boost::bind + Boost::exception + Boost::interprocess + Boost::lexical_cast + Boost::optional + Boost::random + Boost::spirit + ${boost_log_regex_backend_private_libs} +) + +if (NOT BOOST_LOG_NO_THREADS) + target_link_libraries(boost_log + PUBLIC + Boost::atomic + Boost::thread + ) +endif() + +target_compile_definitions(boost_log + PUBLIC + ${boost_log_common_public_defines} + ${boost_log_public_defines} + PRIVATE + ${boost_log_common_private_defines} + ${boost_log_private_defines} +) + +target_compile_options(boost_log + PRIVATE + ${boost_log_common_private_cxxflags} +) + +target_link_libraries(boost_log + PUBLIC + ${boost_log_public_libs} + PRIVATE + ${boost_log_private_libs} + ${boost_log_common_private_linkflags} +) + +# An alias target for Boost::log but with all optional dependencies (i.e. for support headers) +add_library(boost_log_with_support INTERFACE) +add_library(Boost::log_with_support ALIAS boost_log_with_support) + +target_link_libraries(boost_log_with_support + INTERFACE + Boost::log + + Boost::exception + Boost::regex + Boost::spirit + Boost::xpressive +) + + +set(boost_log_setup_public_deps + Boost::log + + Boost::assert + Boost::config + Boost::core + Boost::iterator + Boost::lexical_cast + Boost::move + Boost::optional + Boost::parameter + Boost::phoenix + Boost::preprocessor + Boost::property_tree + Boost::smart_ptr + Boost::type_traits +) + +if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) + set(boost_log_setup_sources + src/setup/parser_utils.hpp + src/setup/parser_utils.cpp + src/setup/init_from_stream.cpp + src/setup/init_from_settings.cpp + src/setup/settings_parser.cpp + src/setup/filter_parser.cpp + src/setup/formatter_parser.cpp + ) + + if (NOT BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + list(APPEND boost_log_setup_sources + src/setup/default_filter_factory.hpp + src/setup/default_filter_factory.cpp + src/setup/matches_relation_factory.cpp + src/setup/default_formatter_factory.hpp + src/setup/default_formatter_factory.cpp + ) + endif() + + add_library(boost_log_setup ${boost_log_setup_sources}) + if (BOOST_SUPERPROJECT_VERSION) + set_target_properties(boost_log_setup PROPERTIES VERSION "${BOOST_SUPERPROJECT_VERSION}") + endif() + list(APPEND boost_log_install_targets boost_log_setup) + + target_include_directories(boost_log_setup + PUBLIC + include + PRIVATE + src + ) + + target_link_libraries(boost_log_setup + PUBLIC + ${boost_log_setup_public_deps} + + PRIVATE + Boost::align # A missing dependency of Boost.ASIO, see https://github.com/boostorg/asio/pull/384 + Boost::asio + Boost::bind + Boost::date_time + Boost::exception + Boost::filesystem + Boost::io + Boost::spirit + Boost::throw_exception + Boost::utility + ) + + if (NOT BOOST_LOG_WITHOUT_DEFAULT_FACTORIES) + target_link_libraries(boost_log_setup + PRIVATE + Boost::fusion + Boost::mpl + ${boost_log_regex_backend_private_libs} + ) + endif() + + target_compile_definitions(boost_log_setup + PUBLIC + ${boost_log_common_public_defines} + PRIVATE + ${boost_log_common_private_defines} + ${boost_log_setup_private_defines} + ) + + target_compile_options(boost_log_setup + PRIVATE + ${boost_log_common_private_cxxflags} + ) + + target_link_libraries(boost_log_setup + PRIVATE + ${boost_log_common_private_linkflags} + ) +else() + add_library(boost_log_setup INTERFACE) + target_include_directories(boost_log_setup INTERFACE include) + target_compile_definitions(boost_log_setup INTERFACE ${boost_log_common_public_defines}) + target_link_libraries(boost_log_setup INTERFACE ${boost_log_setup_public_deps}) +endif() + +add_library(Boost::log_setup ALIAS boost_log_setup) + +if (BOOST_SUPERPROJECT_VERSION AND NOT CMAKE_VERSION VERSION_LESS 3.13) + boost_install(TARGETS ${boost_log_install_targets} VERSION "${BOOST_SUPERPROJECT_VERSION}" HEADER_DIRECTORY include) +endif() diff --git a/appveyor.yml b/appveyor.yml index 7b1c92fc79..05ae1b220d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# Copyright 2019 Andrey Semashev +# Copyright 2019 - 2021 Andrey Semashev # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -106,6 +106,10 @@ environment: ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - TEST_CMAKE: 1 + ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + install: - set GIT_FETCH_JOBS=8 - set BOOST_BRANCH=develop @@ -133,3 +137,21 @@ test_script: - if "%EXTRA_TESTS%" == "" set BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 & set BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 - if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD% - b2 -j %NUMBER_OF_PROCESSORS% libs/log/test variant=release toolset=%TOOLSET% address-model=%ADDRESS_MODEL% %CXXSTD% %B2_ARGS% + +for: + - matrix: + only: [TEST_CMAKE: 1] + test_script: + - PATH=%ADDPATH%;%PATH% + - if not "%ENV_SCRIPT%" == "" call "%ENV_SCRIPT%" + - mkdir __build_static__ + - cd __build_static__ + - cmake ../libs/log/test/test_cmake + - cmake --build . --target boost_log_cmake_self_test -j %NUMBER_OF_PROCESSORS% + - cmake --build . --target boost_log_setup_cmake_self_test -j %NUMBER_OF_PROCESSORS% + - cd .. + - mkdir __build_shared__ + - cd __build_shared__ + - cmake -DBUILD_SHARED_LIBS=On ../libs/log/test/test_cmake + - cmake --build . --target boost_log_cmake_self_test -j %NUMBER_OF_PROCESSORS% + - cmake --build . --target boost_log_setup_cmake_self_test -j %NUMBER_OF_PROCESSORS% diff --git a/test/test_cmake/CMakeLists.txt b/test/test_cmake/CMakeLists.txt new file mode 100644 index 0000000000..bc9555f16d --- /dev/null +++ b/test/test_cmake/CMakeLists.txt @@ -0,0 +1,27 @@ +# Copyright 2021 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt +# +# NOTE: This does NOT run the unit tests for Boost.Log. +# It only tests if the CMakeLists.txt file in its root works as expected + +cmake_minimum_required(VERSION 3.5) + +project(BoostLogCMakeSelfTest) + +# Use experimental superproject to pull library dependencies recursively +set(BOOST_ENABLE_CMAKE 1) +add_subdirectory(../../../.. "${CMAKE_CURRENT_BINARY_DIR}/boost_superproject") + +add_definitions(-DBOOST_ALL_NO_LIB) + +if (BOOST_LOG_WITHOUT_SETTINGS_PARSERS) + add_definitions(-DBOOST_LOG_WITHOUT_SETTINGS_PARSERS) +endif() + +add_executable(boost_log_cmake_self_test log_test.cpp) +target_link_libraries(boost_log_cmake_self_test Boost::log) + +add_executable(boost_log_setup_cmake_self_test log_setup_test.cpp) +target_link_libraries(boost_log_setup_cmake_self_test Boost::log_setup) diff --git a/test/test_cmake/log_setup_test.cpp b/test/test_cmake/log_setup_test.cpp new file mode 100644 index 0000000000..6229ed0f61 --- /dev/null +++ b/test/test_cmake/log_setup_test.cpp @@ -0,0 +1,16 @@ +// Copyright (c) 2021 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include +#include + +int main() +{ +#if !defined(BOOST_LOG_WITHOUT_SETTINGS_PARSERS) + std::istringstream strm; + boost::log::init_from_stream(strm); +#endif +} diff --git a/test/test_cmake/log_test.cpp b/test/test_cmake/log_test.cpp new file mode 100644 index 0000000000..0ee5305659 --- /dev/null +++ b/test/test_cmake/log_test.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2021 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// https://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include +#include +#include +#include +#include +#include + +int main() +{ + BOOST_LOG_TRIVIAL(info) << "Hello world!"; +} From e90d4b7a8d9ceee8c3ab6aad1d70c1ca5251356e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 30 Oct 2021 20:42:35 +0300 Subject: [PATCH 173/309] Added a release note for added support for CMake. --- doc/changelog.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 22b452060d..6deac45eb3 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -17,6 +17,7 @@ * Added support for C++17 `std::byte` type to receive methods of the [link log.detailed.utilities.ipc.reliable_message_queue inter-process message queue]. * On Windows, when building the library for Windows 8 or later, the library will use `nt62` tag in the version namespace to denote the target OS ABI. For example, the version namespace could be named as `v2_mt_nt62`. This name will be part of all symbols exported by the library. Use the `BOOST_USE_WINAPI_VERSION` macro consistenly when building Boost and your code to request the minimum target Windows version. * Improved performance of SSSE3 and AVX2 implementations of the [link log.detailed.utilities.manipulators.dump `dump`] stream manipulator. +* Added support for CMake build system. Only library build is supported at this moment, Boost.Build is still used for running tests. [*Bug fixes:] From d55f122f741b441e64b7f88bf1c3c4ed1d5d1feb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 31 Oct 2021 03:18:12 +0300 Subject: [PATCH 174/309] Added notes for CMake users in the docs. --- doc/log.qbk | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/doc/log.qbk b/doc/log.qbk index e418ebeb52..3f7e17d06e 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -212,24 +212,24 @@ The library has a separately compiled part which should be built as described in The library supports a number of configuration macros: [table Configuration macros - [[Macro name] [Effect]] - [[`BOOST_LOG_DYN_LINK`] [If defined in user code, the library will assume the binary is built as a dynamically loaded library ("dll" or "so"). Otherwise it is assumed that the library is built in static mode. This macro must be either defined or not defined for all translation units of user application that uses logging. This macro can help with auto-linking on platforms that support it.]] - [[`BOOST_ALL_DYN_LINK`] [Same as `BOOST_LOG_DYN_LINK` but also affects other Boost libraries the same way.]] - [[`BOOST_USE_WINAPI_VERSION`] [Affects compilation of both the library and user's code. This macro is Windows-specific. Selects the target Windows version for various Boost libraries, including Boost.Log. Code compiled for a particular Windows version will likely fail to run on the older Windows versions, but may improve performance because of using newer OS features. The macro is expected to have an integer value equivalent to [@https://msdn.microsoft.com/en-us/library/6sehtctf.aspx `_WIN32_WINNT`].]] - [[`BOOST_LOG_NO_THREADS`] [If defined, disables multithreading support. Affects the compilation of both the library and users' code. The macro is automatically defined if no threading support is detected.]] - [[`BOOST_LOG_WITHOUT_CHAR`] [If defined, disables support for narrow character logging. Affects the compilation of both the library and users' code.]] - [[`BOOST_LOG_WITHOUT_WCHAR_T`] [If defined, disables support for wide character logging. Affects the compilation of both the library and users' code.]] - [[`BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER`] [This macro is only useful on Windows. It affects the compilation of both the library and users' code. If defined, disables support for the `QueryPerformanceCounter` API in the `timer` attribute. This will result in significantly less accurate time readings. The macro is intended to solve possible problems with earlier revisions of AMD Athlon CPU, described [@http://support.microsoft.com/?scid=kb;en-us;895980 here] and [@http://support.microsoft.com/?id=896256 here]. There are also known chipset hardware failures that may prevent this API from functioning properly (see [@http://support.microsoft.com/kb/274323 here]).]] - [[`BOOST_LOG_USE_NATIVE_SYSLOG`] [Affects only compilation of the library. If for some reason support for the native SysLog API is not detected automatically, define this macro to forcibly enable it.]] - [[`BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`] [Affects only compilation of the library. If defined, the parsers for settings will be built without any default factories for filters and formatters. The user will have to register all attributes in the library before parsing any filters or formatters from strings. This can substantially reduce the binary size.]] - [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.]] - [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only compilation of the library. If defined, the support for debugger output on Windows will not be built.]] - [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.]] - [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for syslog backend will not be built.]] - [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for interprocess queues will not be built.]] - [[`BOOST_LOG_NO_SHORTHAND_NAMES`] [Affects only compilation of users' code. If defined, some deprecated shorthand macro names will not be available.]] - [[`BOOST_LOG_USE_COMPILER_TLS`] [Affects only compilation of the library. This macro enables support for compiler intrinsics for thread-local storage. Defining it may improve performance of Boost.Log if certain usage limitations are acceptable. See below for more comments.]] - [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.]] + [[Macro name] [Effect] [CMake notes]] + [[`BOOST_LOG_DYN_LINK`] [If defined in user code, the library will assume the binary is built as a dynamically loaded library ("dll" or "so"). Otherwise it is assumed that the library is built in static mode. This macro must be either defined or not defined for all translation units of user application that uses logging. This macro can help with auto-linking on platforms that support it.] [Defined automatically depending on `BUILD_SHARED_LIBS` CMake option.]] + [[`BOOST_ALL_DYN_LINK`] [Same as `BOOST_LOG_DYN_LINK` but also affects other Boost libraries the same way.] []] + [[`BOOST_USE_WINAPI_VERSION`] [Affects compilation of both the library and user's code. This macro is Windows-specific. Selects the target Windows version for various Boost libraries, including Boost.Log. Code compiled for a particular Windows version will likely fail to run on the older Windows versions, but may improve performance because of using newer OS features. The macro is expected to have an integer value equivalent to [@https://msdn.microsoft.com/en-us/library/6sehtctf.aspx `_WIN32_WINNT`].] []] + [[`BOOST_LOG_NO_THREADS`] [If defined, disables multithreading support. Affects the compilation of both the library and users' code. The macro is automatically defined if no threading support is detected.] []] + [[`BOOST_LOG_WITHOUT_CHAR`] [If defined, disables support for narrow character logging. Affects the compilation of both the library and users' code.] []] + [[`BOOST_LOG_WITHOUT_WCHAR_T`] [If defined, disables support for wide character logging. Affects the compilation of both the library and users' code.] []] + [[`BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER`] [This macro is only useful on Windows. It affects the compilation of both the library and users' code. If defined, disables support for the `QueryPerformanceCounter` API in the `timer` attribute. This will result in significantly less accurate time readings. The macro is intended to solve possible problems with earlier revisions of AMD Athlon CPU, described [@http://support.microsoft.com/?scid=kb;en-us;895980 here] and [@http://support.microsoft.com/?id=896256 here]. There are also known chipset hardware failures that may prevent this API from functioning properly (see [@http://support.microsoft.com/kb/274323 here]).] []] + [[`BOOST_LOG_USE_NATIVE_SYSLOG`] [Affects only compilation of the library. If for some reason support for the native SysLog API is not detected automatically, define this macro to forcibly enable it.] []] + [[`BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`] [Affects only compilation of the library. If defined, the parsers for settings will be built without any default factories for filters and formatters. The user will have to register all attributes in the library before parsing any filters or formatters from strings. This can substantially reduce the binary size.] []] + [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.] [Disables compilation of the `boost_log_setup` library.]] + [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only compilation of the library. If defined, the support for debugger output on Windows will not be built.] []] + [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.] []] + [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for syslog backend will not be built.] []] + [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for interprocess queues will not be built.] []] + [[`BOOST_LOG_NO_SHORTHAND_NAMES`] [Affects only compilation of users' code. If defined, some deprecated shorthand macro names will not be available.] [Not a CMake configuration option.]] + [[`BOOST_LOG_USE_COMPILER_TLS`] [Affects only compilation of the library. This macro enables support for compiler intrinsics for thread-local storage. Defining it may improve performance of Boost.Log if certain usage limitations are acceptable. See below for more comments.] []] + [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.] [Instead of definitng one of these macros, use `BOOST_LOG_USE_REGEX_BACKEND` string option with one of the following values: "std::regex", "Boost.Regex" or "Boost.Xpressive". The macros will be defined accordingly by CMake.]] ] You can define configuration macros in the `bjam` command line, like this: @@ -238,6 +238,12 @@ You can define configuration macros in the `bjam` command line, like this: bjam --with-log variant=release define=BOOST_LOG_WITHOUT_EVENT_LOG define=BOOST_USE_WINAPI_VERSION=0x0600 stage ] +With CMake, the configuration macros can be specified as CMake options in the command line like this: + +[pre + cmake .. -DCMAKE_BUILD_TYPE=Release -DBOOST_LOG_WITHOUT_EVENT_LOG=On +] + However, it may be more convenient to define configuration macros in the "boost/config/user.hpp" file in order to automatically define them both for the library and user's projects. If none of the options are specified, the library will try to support the most comprehensive setup, including support for all character types and features available for the target platform. The logging library uses several other Boost libraries that require building too. These are __boost_filesystem__, __boost_system__, __boost_date_time__, __boost_thread__ and in some configurations __boost_regex__. Refer to their documentation for detailed instructions on the building procedure. @@ -272,6 +278,12 @@ By default, Boost (and Boost.Log being part of it) is built with native `wchar_t Because of that using the emulation mode is discouraged and should be avoided. In future releases of the library its support may be removed completely. +[heading Notes for CMake users on Windows] + +In order to compile Boost.Log with event log support on Windows using CMake, the initial CMake configuration should be performed with resource (`rc.exe` or `windres.exe`) and message compiler tools (`mc.exe` or `windmc.exe`) available in `PATH` environment variable. With MSVC, it is recommended to run CMake in the Visual Studio command line or otherwise ensure that Windows SDK environment variables are set. + +Alternatively, users may set `RC` and `MC` environment variables to paths of the resource and message compiler executables, respectively, or set `CMAKE_RC_COMPILER` and `CMAKE_MC_COMPILER` CMake options to the corresponding paths in the command line. + [endsect] [endsect] From ebaabd9c57ae23513af9419b36fd081625cad6a4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 4 Nov 2021 00:02:58 +0300 Subject: [PATCH 175/309] Removed auto-linking Boost.System and Boost.DateTime. Boost.System and Boost.DateTime are header-only now. We used to include Boost.System config header to auto-link with it (which it no longer does) and manually auto-link Boost.DateTime. The latter caused a problem with partial Boost checkout and build/install, when the enabled dependencies were derived from the Boost.Log Jamfile, which does not contain a dependency on DateTime. Closes https://github.com/boostorg/log/issues/166. --- include/boost/log/detail/config.hpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 207258567a..1c36768525 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -249,15 +249,7 @@ // other Boost libraries. We explicitly add comments here for other libraries. // In dynamic-library builds this is not needed. # if !defined(BOOST_LOG_DLL) -# include # include -# if !defined(BOOST_DATE_TIME_NO_LIB) && !defined(BOOST_DATE_TIME_SOURCE) -# define BOOST_LIB_NAME boost_date_time -# if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_DATE_TIME_DYN_LINK) -# define BOOST_DYN_LINK -# endif -# include -# endif // Boost.Thread's config is included below, if needed # endif # endif // auto-linking disabled From 036bd4fffd9b66041daa1dc52cded8d807f2bac8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 13 Nov 2021 01:20:26 +0300 Subject: [PATCH 176/309] Removed workaround dependency on Boost.Align that was missing in Boost.ASIO. --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 910fab2d81..1d7df88fb4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -609,7 +609,6 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) ${boost_log_setup_public_deps} PRIVATE - Boost::align # A missing dependency of Boost.ASIO, see https://github.com/boostorg/asio/pull/384 Boost::asio Boost::bind Boost::date_time From 1aaf946b18fada68adc7ff9cbdc67d7609e07610 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 16 Nov 2021 00:50:58 +0300 Subject: [PATCH 177/309] Updated check for apt-add-repository capabilities. In Ubuntu 20.04 there appeared an updated version of the software-properties-common package in focal-updates, which ships a newer apt-add-repository version that doesn't support -P/-S/-U command line arguments. Since we cannot rely on package version checks to determine apt-add-repository capabilities, we have to parse its --help output instead. Also, made source list processing more protected against spaces. --- .github/workflows/ci.yml | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1d0ca41258..a6b7589c4e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -260,7 +260,7 @@ jobs: if [ -f "/etc/debian_version" ] then apt-get -o Acquire::Retries=$NET_RETRY_COUNT update - apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ python python3 git cmake + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ python python3 perl git cmake fi fi git config --global pack.threads 0 @@ -270,28 +270,32 @@ jobs: - name: Install packages if: matrix.install run: | - SOURCE_KEYS=(${{join(matrix.source_keys, ' ')}}) - SOURCES=(${{join(matrix.sources, ' ')}}) + declare -a SOURCE_KEYS SOURCES + if [ -n "${{join(matrix.source_keys, ' ')}}" ] + then + SOURCE_KEYS=("${{join(matrix.source_keys, '" "')}}") + fi + if [ -n "${{join(matrix.sources, ' ')}}" ] + then + SOURCES=("${{join(matrix.sources, '" "')}}") + fi for key in "${SOURCE_KEYS[@]}" do for i in {1..$NET_RETRY_COUNT} do + echo "Adding key: $key" wget -O - "$key" | sudo apt-key add - && break || sleep 2 done done if [ ${#SOURCES[@]} -gt 0 ] then APT_ADD_REPO_COMMON_ARGS=("-y") - APT_ADD_REPO_HAS_SOURCE_ARGS=0 - SOFTWARE_PROPERTIES_VERSION="$(dpkg-query --showformat='${Version}' --show software-properties-common)" - if dpkg --compare-versions "$SOFTWARE_PROPERTIES_VERSION" ge "0.96.24.20" + APT_ADD_REPO_SUPPORTED_ARGS="$(apt-add-repository --help | perl -ne 'if (/^\s*-n/) { print "n"; } elsif (/^\s*-P/) { print "P"; } elsif (/^\s*-S/) { print "S"; } elsif (/^\s*-U/) { print "U"; }')" + if [ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*n*}" ] then APT_ADD_REPO_COMMON_ARGS+=("-n") fi - if dpkg --compare-versions "$SOFTWARE_PROPERTIES_VERSION" ge "0.98.10" - then - APT_ADD_REPO_HAS_SOURCE_ARGS=1 - fi + APT_ADD_REPO_HAS_SOURCE_ARGS="$([ -n "$APT_ADD_REPO_SUPPORTED_ARGS" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*P*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*S*}" -a -z "${APT_ADD_REPO_SUPPORTED_ARGS##*U*}" ] && echo 1 || echo 0)" for source in "${SOURCES[@]}" do for i in {1..$NET_RETRY_COUNT} @@ -312,6 +316,7 @@ jobs: esac fi APT_ADD_REPO_ARGS+=("$source") + echo "apt-add-repository ${APT_ADD_REPO_ARGS[@]}" sudo -E apt-add-repository "${APT_ADD_REPO_ARGS[@]}" && break || sleep 2 done done @@ -342,7 +347,7 @@ jobs: REF=${GITHUB_BASE_REF:-$GITHUB_REF} REF=${REF#refs/heads/} echo REF: $REF - BOOST_BRANCH=develop && [ "$REF" == "master" ] && BOOST_BRANCH=master || true + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true echo BOOST_BRANCH: $BOOST_BRANCH BUILD_JOBS=$((nproc || sysctl -n hw.ncpu) 2> /dev/null) echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV From 8024d7c9c9b83268a101f2c6aae9a95b2ba765a4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 2 Dec 2021 17:57:04 +0300 Subject: [PATCH 178/309] Enabled matches with Boost.Xpressive test for gcc 11.2 and newer. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102293 is fixed in gcc 11.2. --- test/run/filt_matches_xpressive.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/run/filt_matches_xpressive.cpp b/test/run/filt_matches_xpressive.cpp index c52d163f83..aafcabf21c 100644 --- a/test/run/filt_matches_xpressive.cpp +++ b/test/run/filt_matches_xpressive.cpp @@ -14,9 +14,9 @@ #include -// gcc 10 and 11 are known to ICE on Boost.Xpressive code in C++03 mode, see: +// gcc 10 and 11 prior to 11.2 are known to ICE on Boost.Xpressive code in C++03 mode, see: // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102293 -#if !defined(BOOST_GCC) || defined(BOOST_GCC_CXX11) || BOOST_GCC < 100000 +#if !defined(BOOST_GCC) || defined(BOOST_GCC_CXX11) || BOOST_GCC < 100000 || BOOST_GCC >= 110200 #define BOOST_TEST_MODULE filt_matches_xpressive @@ -112,11 +112,11 @@ BOOST_AUTO_TEST_CASE(composition_check) BOOST_CHECK(f(values3)); } -#else // !defined(BOOST_GCC) || BOOST_GCC < 100000 +#else // !defined(BOOST_GCC) || defined(BOOST_GCC_CXX11) || BOOST_GCC < 100000 || BOOST_GCC >= 110200 int main() { return 0; } -#endif // !defined(BOOST_GCC) || BOOST_GCC < 100000 +#endif // !defined(BOOST_GCC) || defined(BOOST_GCC_CXX11) || BOOST_GCC < 100000 || BOOST_GCC >= 110200 From 4973d4154d71d58398c017c6b913591a7ff26447 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 4 Feb 2022 14:44:06 +0300 Subject: [PATCH 179/309] Extracted Boost library include paths collection to a CMake module. Also, save the collected paths to a global property to avoid potentially scanning the filesystem in every library that needs these paths. --- CMakeLists.txt | 19 ++-------------- cmake/BoostLibraryIncludes.cmake | 37 ++++++++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 17 deletions(-) create mode 100644 cmake/BoostLibraryIncludes.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 1d7df88fb4..592281c92e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2021 Andrey Semashev +# Copyright 2021-2022 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt @@ -35,28 +35,13 @@ if (NOT BOOST_LOG_NO_THREADS) find_package(Threads REQUIRED) endif() -# Generates a list of include paths for all Boost libraries in \a result variable. Uses unified Boost include tree, if available. -function(generate_boost_include_paths result) - if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/../../boost" AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../../boost/version.hpp") - set(${result} "${CMAKE_CURRENT_SOURCE_DIR}/../.." PARENT_SCOPE) - return() - endif() - file(GLOB path_list LIST_DIRECTORIES True "${CMAKE_CURRENT_SOURCE_DIR}/../*") - foreach(path IN LISTS path_list) - if (IS_DIRECTORY "${path}/include") - list(APPEND include_list "${path}/include") - endif() - endforeach() - set(${result} ${include_list} PARENT_SCOPE) -endfunction() - # Note: We can't use the Boost::library targets in the configure checks as they may not yet be included # by the superproject when this CMakeLists.txt is included. We also don't want to hardcode include paths # of the needed libraries and their dependencies, recursively, as this is too fragile and requires maintenance. # Instead, we collect include paths of all libraries and use them in the configure checks. This works faster # if there is a unified Boost include tree in the filesystem (i.e. if `b2 headers` was run or we're in the # official monolithic Boost distribution tree). -generate_boost_include_paths(BOOST_LIBRARY_INCLUDES) +include(cmake/BoostLibraryIncludes.cmake) set(CMAKE_REQUIRED_INCLUDES ${BOOST_LIBRARY_INCLUDES}) diff --git a/cmake/BoostLibraryIncludes.cmake b/cmake/BoostLibraryIncludes.cmake new file mode 100644 index 0000000000..b875bbdba9 --- /dev/null +++ b/cmake/BoostLibraryIncludes.cmake @@ -0,0 +1,37 @@ +# Copyright 2022 Andrey Semashev +# +# Distributed under the Boost Software License, Version 1.0. +# See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt +# +# After including this module, BOOST_LIBRARY_INCLUDES variable is set to the list of include +# directories for all Boost libraries. If the monolithic include directory is found, it is +# used instead. + +if (NOT CMAKE_VERSION VERSION_LESS 3.10) + include_guard() +endif() + +# Generates a list of include paths for all Boost libraries in \a result variable. Uses unified Boost include tree, if available. +function(generate_boost_include_paths result) + if (IS_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}/../../../boost" AND EXISTS "${CMAKE_CURRENT_LIST_DIR}/../../../boost/version.hpp") + get_filename_component(include_dir "${CMAKE_CURRENT_LIST_DIR}/../../.." ABSOLUTE) + set(${result} "${include_dir}" PARENT_SCOPE) + return() + endif() + file(GLOB path_list LIST_DIRECTORIES True "${CMAKE_CURRENT_LIST_DIR}/../../../libs/*") + foreach(path IN LISTS path_list) + if (IS_DIRECTORY "${path}/include") + get_filename_component(include_dir "${path}/include" ABSOLUTE) + list(APPEND include_list "${include_dir}") + endif() + endforeach() + set(${result} ${include_list} PARENT_SCOPE) +endfunction() + +if (NOT DEFINED BOOST_LIBRARY_INCLUDES) + generate_boost_include_paths(__BOOST_LIBRARY_INCLUDES) + # Save the paths in a global property to avoid scanning the filesystem if this module is used in multiple libraries + set(BOOST_LIBRARY_INCLUDES ${__BOOST_LIBRARY_INCLUDES} CACHE INTERNAL "List of all Boost library include paths") + unset(__BOOST_LIBRARY_INCLUDES) + # message(STATUS "Boost library includes: ${BOOST_LIBRARY_INCLUDES}") +endif() From d78f9c1fd5796760c57ecca973ae0407a7f21ff0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 10 Feb 2022 23:56:28 +0300 Subject: [PATCH 180/309] Added a warning about using named scopes with coroutines and similar APIs. This is in response to https://github.com/boostorg/log/issues/178. --- doc/attributes.qbk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/attributes.qbk b/doc/attributes.qbk index 921a5895d7..2d07fc7aad 100644 --- a/doc/attributes.qbk +++ b/doc/attributes.qbk @@ -266,6 +266,8 @@ After executing `foo` we will be able to see in the log that the `bar` function [note The `BOOST_LOG_FUNCTION` macro uses compiler-specific extensions to generate the scope name from the enclosing function. C++11 defines a standard macro `__func__` for this purpose, but it is not universally supported. Additionally, format of the string is not standardized and may vary from one compiler to another. For this reason it is generally advised to use `BOOST_LOG_NAMED_SCOPE` instead of `BOOST_LOG_FUNCTION` to ensure consistent and portable behavior.] +[warning The `BOOST_LOG_FUNCTION` and `BOOST_LOG_NAMED_SCOPE` macros effectively form a linked list of scope descriptors on the stack, which is automatically maintained as control enters and leaves scopes in the LIFO (last in, first out) order. The attribute implementation relies on this LIFO order. This breaks when execution switches to another stack and back at arbitrary points, which allows control to enter and leave scopes in any order. This is what happens on thread context switching, for example when using coroutines or low level system APIs like [@https://pubs.opengroup.org/onlinepubs/7908799/xsh/ucontext.h.html ucontext] and [@https://docs.microsoft.com/en-us/windows/win32/procthread/fibers fibers]. Using named scopes in code that utilizes such context switching facilities requires careful programming to maintain the LIFO order of entering/leaving scopes marked with named scope macros. Otherwise, using named scopes will result in undefined behavior and should be avoided. Note that with arbitrary context switching the list of scopes would not provide meaningful information anyway.] + Another good use case is attaching the scope stack information to an exception. With the help of __boost_exception__, this is possible: void bar(int x) From 656fd1b0c1af504bf4e8fede0c62e9660050886c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 26 Feb 2022 16:01:21 +0300 Subject: [PATCH 181/309] Avoid updating file counter in scan_for_files if no new files are found. This prevents the file counter from being reset to zero if scan_for_files is called multiple times, and subsequent calls don't find any new files. Reported in https://github.com/boostorg/log/issues/179. --- doc/changelog.qbk | 8 +++++++- src/text_file_backend.cpp | 34 +++++++++++++++++++++------------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 6deac45eb3..ca16ea2d6c 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2021. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.24, Boost 1.79] + +[*Bug fixes:] + +* Fixed file counter being set to zero if the user calls [link log.detailed.sink_backends.text_file.file_scanning `text_file_backend::scan_for_files`] multiple times, and the second and the following calls don't find any new files. ([github_issue 179]) + [heading 2.23, Boost 1.78] [*General changes:] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 8c03dda313..18f3bb223f 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -892,7 +892,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { uintmax_t file_collector::scan_for_files( file::scan_method method, filesystem::path const& pattern, unsigned int* counter) { - uintmax_t file_count = 0; + uintmax_t file_count = 0u; if (method != file::no_scan) { filesystem::path dir = m_StorageDir; @@ -912,14 +912,16 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::file_status status = filesystem::status(dir, ec); if (status.type() == filesystem::directory_file) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) - + unsigned int new_counter = 0u; if (counter) - *counter = 0; + new_counter = *counter; + bool found_file_number = false; + + BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) file_list files; filesystem::directory_iterator it(dir), end; - uintmax_t total_size = 0; + uintmax_t total_size = 0u; for (; it != end; ++it) { filesystem::directory_entry const& dir_entry = *it; @@ -951,9 +953,12 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { files.push_back(info); ++file_count; - // Test that the file_number >= *counter accounting for the integer overflow - if (file_number_parsed && counter != NULL && (file_number - *counter) < ((~0u) ^ ((~0u) >> 1))) - *counter = file_number + 1u; + // Test that the file_number >= new_counter accounting for the integer overflow + if (file_number_parsed && (file_number - new_counter) < ((~0u) ^ ((~0u) >> 1u))) + { + found_file_number = true; + new_counter = file_number + 1u; + } } } } @@ -963,6 +968,9 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { m_Files.splice(m_Files.end(), files); m_TotalSize += total_size; m_Files.sort(boost::bind(&file_info::m_TimeStamp, boost::placeholders::_1) < boost::bind(&file_info::m_TimeStamp, boost::placeholders::_2)); + + if (counter && found_file_number) + *counter = new_counter; } } @@ -1207,9 +1215,6 @@ BOOST_LOG_API bool rotation_at_time_interval::operator()() const //! Sink implementation data struct text_file_backend::implementation { - //! File open mode - std::ios_base::openmode m_FileOpenMode; - //! File name pattern filesystem::path m_FileNamePattern; //! Directory to store files in @@ -1227,6 +1232,9 @@ struct text_file_backend::implementation //! Stored files counter unsigned int m_FileCounter; + //! File open mode + std::ios_base::openmode m_FileOpenMode; + //! Current file name filesystem::path m_FileName; //! File stream @@ -1253,9 +1261,9 @@ struct text_file_backend::implementation bool m_FinalRotationEnabled; implementation(uintmax_t rotation_size, auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) : + m_FileCounter(0u), m_FileOpenMode(std::ios_base::trunc | std::ios_base::out), - m_FileCounter(0), - m_CharactersWritten(0), + m_CharactersWritten(0u), m_FileRotationSize(rotation_size), m_AutoNewlineMode(auto_newline), m_AutoFlush(auto_flush), From 69ec057e7ca505a29488ed290478ac6c252d034b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Feb 2022 00:03:37 +0300 Subject: [PATCH 182/309] Added support for appending to files with file counter placeholders in names. Previously, text_file_backend would generate a new file name when the file name pattern contained a file counter placeholder, which prevented appending to the file. Appending was only possible when the active file name was stable across process restarts (effectively, this prohibited the file counter to be used in the active file name). This commit adds support for appending in such configuration. The file collector has been updated to return the last found file counter during filesystem scanning, and the sink backend doesn't increment it when the initial file is opened, when appending is enabled, and when the file to be opened exists and, if file collector is used, is in the target storage of the file collector. In all other cases the file counter is incremented, which leaves the behavior unchanged. Closes https://github.com/boostorg/log/issues/179. --- doc/changelog.qbk | 7 + doc/sink_backends.qbk | 2 +- include/boost/log/sinks/text_file_backend.hpp | 36 ++- src/text_file_backend.cpp | 239 +++++++++++++----- 4 files changed, 214 insertions(+), 70 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index ca16ea2d6c..ab5f8b4911 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -11,6 +11,13 @@ [heading 2.24, Boost 1.79] +[*General changes:] + +* In [link log.detailed.sink_backends.text_file `text_file_backend`], added support for appending to a previously written log file, when file rotation is used and log file names use file counters. For this to work, the target storage directory must be the same as the directory where the active log file is written, and `text_file_backend::scan_for_files` must be called prior to emitting any log records to discover the last file counter used in the target storage directory. Previously, in such a configuration the sink backend would generate a new file name instead of appending to the last written one. +* *Breaking change:* The [class_file_collector] interface has changed: + * `scan_for_files` method returns a `scan_result` structure that contains information collected during the scan; + * `is_in_storage` method added for testing if a path refers to a file within the target storage directory. + [*Bug fixes:] * Fixed file counter being set to zero if the user calls [link log.detailed.sink_backends.text_file.file_scanning `text_file_backend::scan_for_files`] multiple times, and the second and the following calls don't find any new files. ([github_issue 179]) diff --git a/doc/sink_backends.qbk b/doc/sink_backends.qbk index e30505c185..0894fb02f5 100644 --- a/doc/sink_backends.qbk +++ b/doc/sink_backends.qbk @@ -210,7 +210,7 @@ The sink backend supports appending to the previously written files (e.g. left f When initializing from [link log.detailed.utilities.setup.settings settings], the "Append" parameter of the "TextFile" sink enables appending. -In order for file appending to actually happen, it is important that the name of the newly opened log file matches the previously written file. Othewise, the sink will simply create a new file under the new name. There are several recommendations to follow when file appending is desirable: +In order for file appending to actually happen, it is important that the name of the newly opened log file matches the previously written file. Otherwise, the sink will simply create a new file under the new name. There are several recommendations to follow when file appending is desirable: * Don't use placeholders in the active file name pattern. This will ensure that every time the sink opens a file for writing, that file has the same name. * Use a distinct target file name pattern, preferably with date, time or counter placeholders. This will ensure that when the file is rotated and collected, it doesn't clash with the previously written files, and that the newly opened file will have a different name from the previous one. diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 719acc958b..48ce8a7f3c 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -66,6 +67,20 @@ enum scan_method scan_all //!< Scan for all files in the directory }; +//! The structure contains filesystem scanning results +struct scan_result +{ + //! The number of found files + uintmax_t found_count; + //! If populated, the largest file counter that was used in the found file names + boost::optional< unsigned int > last_file_counter; + + scan_result() BOOST_NOEXCEPT : + found_count(0u) + { + } +}; + /*! * \brief Base class for file collectors * @@ -81,7 +96,7 @@ struct BOOST_LOG_NO_VTABLE collector /*! * Virtual destructor */ - virtual ~collector() {} + BOOST_DEFAULTED_FUNCTION(virtual ~collector(), {}) /*! * The function stores the specified file in the storage. May lead to an older file @@ -91,6 +106,13 @@ struct BOOST_LOG_NO_VTABLE collector */ virtual void store_file(filesystem::path const& src_path) = 0; + /*! + * The function checks if the specified path refers to an existing file in the storage. + * + * \param src_path The path to be checked + */ + virtual bool is_in_storage(filesystem::path const& src_path) const = 0; + /*! * Scans the target directory for the files that have already been stored. The found * files are added to the collector in order to be tracked and erased, if needed. @@ -110,19 +132,17 @@ struct BOOST_LOG_NO_VTABLE collector * \param method The method of scanning. If \c no_scan is specified, the call has no effect. * \param pattern The file name pattern if \a method is \c scan_matching. Otherwise the parameter * is not used. - * \param counter If not \c NULL and \a method is \c scan_matching, the method suggests initial value - * of a file counter that may be used in the file name pattern. The parameter - * is not used otherwise. - * \return The number of found files. + * \return The result of filesystem scanning. The last file counter is only populated if + * \a method is \c scan_matching, the \a pattern contains %N placeholder, and at least + * one file matching the pattern is found. * * \note In case if \a method is \c scan_matching the effect of this function is highly dependent * on the \a pattern definition. It is recommended to choose patterns with easily * distinguished placeholders (i.e. having delimiters between them). Otherwise * either some files can be mistakenly found or not found, which in turn may lead - * to an incorrect file deletion. + * to deletion of an unintended file. */ - virtual uintmax_t scan_for_files( - scan_method method, filesystem::path const& pattern = filesystem::path(), unsigned int* counter = 0) = 0; + virtual scan_result scan_for_files(scan_method method, filesystem::path const& pattern = filesystem::path()) = 0; BOOST_DELETED_FUNCTION(collector(collector const&)) BOOST_DELETED_FUNCTION(collector& operator= (collector const&)) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 18f3bb223f..8b8920e866 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -32,10 +32,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -79,9 +79,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { typedef filesystem::filesystem_error filesystem_error; //! A possible Boost.Filesystem extension - renames or moves the file to the target storage - inline void move_file( - filesystem::path const& from, - filesystem::path const& to) + inline void move_file(filesystem::path const& from, filesystem::path const& to) { #if defined(BOOST_WINDOWS_API) // On Windows MoveFile already does what we need @@ -610,6 +608,38 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Information about a single stored file struct file_info { + //! Ordering predicate by timestamp + struct order_by_timestamp + { + typedef bool result_type; + + result_type operator()(file_info const& left, file_info const& right) const BOOST_NOEXCEPT + { + return left.m_TimeStamp < right.m_TimeStamp; + } + }; + + //! Predicate for testing if a file_info refers to a file equivalent to another path + class equivalent_file + { + public: + typedef bool result_type; + + private: + filesystem::path const& m_Path; + + public: + explicit equivalent_file(filesystem::path const& path) BOOST_NOEXCEPT : + m_Path(path) + { + } + + result_type operator()(file_info const& info) const + { + return filesystem::equivalent(info.m_Path, m_Path); + } + }; + uintmax_t m_Size; std::time_t m_TimeStamp; filesystem::path m_Path; @@ -664,9 +694,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! The function stores the specified file in the storage void store_file(filesystem::path const& file_name) BOOST_OVERRIDE; + //! The function checks if the specified path refers to an existing file in the storage + bool is_in_storage(filesystem::path const& src_path) const BOOST_OVERRIDE; + //! Scans the target directory for the files that have already been stored - uintmax_t scan_for_files( - file::scan_method method, filesystem::path const& pattern, unsigned int* counter) BOOST_OVERRIDE; + file::scan_result scan_for_files(file::scan_method method, filesystem::path const& pattern) BOOST_OVERRIDE; //! The function updates storage restrictions void update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files); @@ -679,7 +711,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { private: //! Makes relative path absolute with respect to the base path - filesystem::path make_absolute(filesystem::path const& p) + filesystem::path make_absolute(filesystem::path const& p) const { return filesystem::absolute(p, m_BasePath); } @@ -779,8 +811,8 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { // Check if the file is already in the target directory filesystem::path src_dir = src_path.has_parent_path() ? - filesystem::system_complete(src_path.parent_path()) : - m_BasePath; + filesystem::system_complete(src_path.parent_path()) : + m_BasePath; const bool is_in_target_dir = filesystem::equivalent(src_dir, m_StorageDir); if (!is_in_target_dir) { @@ -888,11 +920,34 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { m_TotalSize += info.m_Size; } + //! The function checks if the specified path refers to an existing file in the storage + bool file_collector::is_in_storage(filesystem::path const& src_path) const + { + const filesystem::path file_name_path = src_path.filename(); + const filesystem::path trg_path = m_StorageDir / file_name_path; + + // Check if the file is already in the target directory + system::error_code ec; + filesystem::path src_dir = src_path.has_parent_path() ? + filesystem::system_complete(src_path.parent_path(), ec) : + m_BasePath; + if (ec) + return false; + + filesystem::file_status status = filesystem::status(trg_path, ec); + if (ec || status.type() != filesystem::regular_file) + return false; + bool equiv = filesystem::equivalent(src_dir / file_name_path, trg_path, ec); + if (ec) + return false; + + return equiv; + } + //! Scans the target directory for the files that have already been stored - uintmax_t file_collector::scan_for_files( - file::scan_method method, filesystem::path const& pattern, unsigned int* counter) + file::scan_result file_collector::scan_for_files(file::scan_method method, filesystem::path const& pattern) { - uintmax_t file_count = 0u; + file::scan_result result; if (method != file::no_scan) { filesystem::path dir = m_StorageDir; @@ -903,20 +958,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (pattern.has_parent_path()) dir = make_absolute(pattern.parent_path()); } - else - { - counter = NULL; - } system::error_code ec; filesystem::file_status status = filesystem::status(dir, ec); if (status.type() == filesystem::directory_file) { - unsigned int new_counter = 0u; - if (counter) - new_counter = *counter; - bool found_file_number = false; - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) file_list files; @@ -931,18 +977,10 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (status.type() == filesystem::regular_file) { // Check that there are no duplicates in the resulting list - struct local - { - static bool equivalent(filesystem::path const& left, file_info const& right) - { - return filesystem::equivalent(left, right.m_Path); - } - }; - if (std::find_if(m_Files.begin(), m_Files.end(), - boost::bind(&local::equivalent, boost::cref(info.m_Path), boost::placeholders::_1)) == m_Files.end()) + if (std::find_if(m_Files.begin(), m_Files.end(), file_info::equivalent_file(info.m_Path)) == m_Files.end()) { // Check that the file name matches the pattern - unsigned int file_number = 0; + unsigned int file_number = 0u; bool file_number_parsed = false; if (method != file::scan_matching || match_pattern(filename_string(info.m_Path), mask, file_number, file_number_parsed)) @@ -951,14 +989,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { total_size += info.m_Size; info.m_TimeStamp = filesystem::last_write_time(info.m_Path); files.push_back(info); - ++file_count; - - // Test that the file_number >= new_counter accounting for the integer overflow - if (file_number_parsed && (file_number - new_counter) < ((~0u) ^ ((~0u) >> 1u))) - { - found_file_number = true; - new_counter = file_number + 1u; - } + ++result.found_count; + + // Test that the file_number >= result.last_file_counter accounting for the integer overflow + if (file_number_parsed && (!result.last_file_counter || (file_number - *result.last_file_counter) < ((~0u) ^ ((~0u) >> 1u)))) + result.last_file_counter = file_number; } } } @@ -967,14 +1002,11 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { // Sort files chronologically m_Files.splice(m_Files.end(), files); m_TotalSize += total_size; - m_Files.sort(boost::bind(&file_info::m_TimeStamp, boost::placeholders::_1) < boost::bind(&file_info::m_TimeStamp, boost::placeholders::_2)); - - if (counter && found_file_number) - *counter = new_counter; + m_Files.sort(file_info::order_by_timestamp()); } } - return file_count; + return result; } //! The function updates storage restrictions @@ -1229,7 +1261,7 @@ struct text_file_backend::implementation //! Target file name generator (according to m_TargetFileNamePattern) boost::log::aux::light_function< path_string_type (unsigned int) > m_TargetFileNameGenerator; - //! Stored files counter + //! Counter to use in file names unsigned int m_FileCounter; //! File open mode @@ -1260,6 +1292,11 @@ struct text_file_backend::implementation //! The flag indicates whether the final rotation should be performed bool m_FinalRotationEnabled; + //! The flag indicates that \c m_FileCounter is set to the last used counter value + bool m_FileCounterIsLastUsed; + //! The flag indicates whether the next opened file will be the first file opened by this backend + bool m_IsFirstFile; + implementation(uintmax_t rotation_size, auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) : m_FileCounter(0u), m_FileOpenMode(std::ios_base::trunc | std::ios_base::out), @@ -1267,7 +1304,9 @@ struct text_file_backend::implementation m_FileRotationSize(rotation_size), m_AutoNewlineMode(auto_newline), m_AutoFlush(auto_flush), - m_FinalRotationEnabled(enable_final_rotation) + m_FinalRotationEnabled(enable_final_rotation), + m_FileCounterIsLastUsed(false), + m_IsFirstFile(true) { } }; @@ -1383,13 +1422,49 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ rotate_file(); } - if (!m_pImpl->m_File.is_open()) + while (!m_pImpl->m_File.is_open()) { filesystem::path new_file_name; if (!use_prev_file_name) - new_file_name = m_pImpl->m_StorageDir / m_pImpl->m_FileNameGenerator(m_pImpl->m_FileCounter++); + { + unsigned int file_counter = m_pImpl->m_FileCounter; + if (BOOST_LIKELY(m_pImpl->m_FileCounterIsLastUsed)) + { + // If the sink backend is configured to append to a previously written file, don't + // increment the file counter and try to open the existing file. Only do this if the + // file is not moved to a different storage location by the file collector. + bool increment_file_counter = true; + if (BOOST_UNLIKELY(m_pImpl->m_IsFirstFile && (m_pImpl->m_FileOpenMode & std::ios_base::app) != 0)) + { + filesystem::path last_file_name = m_pImpl->m_StorageDir / m_pImpl->m_FileNameGenerator(file_counter); + if (!!m_pImpl->m_pFileCollector) + { + increment_file_counter = !m_pImpl->m_pFileCollector->is_in_storage(last_file_name); + } + else + { + system::error_code ec; + increment_file_counter = filesystem::status(last_file_name, ec).type() != filesystem::regular_file; + } + } + + if (BOOST_LIKELY(increment_file_counter)) + { + ++file_counter; + m_pImpl->m_FileCounter = file_counter; + } + } + else + { + m_pImpl->m_FileCounterIsLastUsed = true; + } + + new_file_name = m_pImpl->m_StorageDir / m_pImpl->m_FileNameGenerator(file_counter); + } else + { prev_file_name.swap(new_file_name); + } filesystem::create_directories(new_file_name.parent_path()); @@ -1402,11 +1477,47 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ system::error_code(system::errc::io_error, system::generic_category()))); } m_pImpl->m_FileName.swap(new_file_name); + m_pImpl->m_IsFirstFile = false; + + // Check the file size before invoking the open handler, as it may write more data to the file + m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); + if (m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize) + { + // Avoid running the close handler, as we haven't run the open handler yet + struct close_handler_backup_guard + { + explicit close_handler_backup_guard(close_handler_type& orig_close_handler) BOOST_NOEXCEPT : + m_orig_close_handler(orig_close_handler) + { + orig_close_handler.swap(m_backup_close_handler); + } + ~close_handler_backup_guard() BOOST_NOEXCEPT + { + m_orig_close_handler.swap(m_backup_close_handler); + } + + private: + close_handler_type& m_orig_close_handler; + close_handler_type m_backup_close_handler; + } + close_handler_guard(m_pImpl->m_CloseHandler); + + rotate_file(); + continue; + } if (!m_pImpl->m_OpenHandler.empty()) + { m_pImpl->m_OpenHandler(m_pImpl->m_File); - m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); + // Update the size of the written data, but don't rotate the file. If the open handler + // exceeds the file size limit we could end up in an infinite loop, as we are constantly + // rotating the file and immediately exceeding its size limit after the open handler is run. + // Write the log record and then rotate the file upon the next log record. + m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); + } + + break; } m_pImpl->m_File.write(formatted_message.data(), static_cast< std::streamsize >(formatted_message.size())); @@ -1499,8 +1610,7 @@ BOOST_LOG_API void text_file_backend::rotate_file() { if (!!m_pImpl->m_TargetFileNameGenerator) { - // File counter was incremented when the file was opened, we have to use the same counter value we used to generate the original filename - filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter - 1u); + filesystem::path new_file_name = m_pImpl->m_TargetStorageDir / m_pImpl->m_TargetFileNameGenerator(m_pImpl->m_FileCounter); if (new_file_name != prev_file_name) { @@ -1555,20 +1665,27 @@ BOOST_LOG_API filesystem::path text_file_backend::get_current_file_name() const //! Performs scanning of the target directory for log files BOOST_LOG_API uintmax_t text_file_backend::scan_for_files(file::scan_method method, bool update_counter) { - if (BOOST_LIKELY(!!m_pImpl->m_pFileCollector)) + if (BOOST_UNLIKELY(!m_pImpl->m_pFileCollector)) { - unsigned int* counter = update_counter ? &m_pImpl->m_FileCounter : static_cast< unsigned int* >(NULL); - return m_pImpl->m_pFileCollector->scan_for_files - ( - method, - m_pImpl->m_TargetFileNamePattern.empty() ? m_pImpl->m_FileNamePattern : m_pImpl->m_TargetFileNamePattern, - counter - ); + BOOST_LOG_THROW_DESCR(setup_error, "File collector is not set"); } - else + + file::scan_result result = m_pImpl->m_pFileCollector->scan_for_files + ( + method, + m_pImpl->m_TargetFileNamePattern.empty() ? m_pImpl->m_FileNamePattern : m_pImpl->m_TargetFileNamePattern + ); + + if (update_counter && !!result.last_file_counter) { - BOOST_LOG_THROW_DESCR(setup_error, "File collector is not set"); + if (!m_pImpl->m_FileCounterIsLastUsed || (*result.last_file_counter - m_pImpl->m_FileCounter) < ((~0u) ^ ((~0u) >> 1u))) + { + m_pImpl->m_FileCounter = *result.last_file_counter; + m_pImpl->m_FileCounterIsLastUsed = true; + } } + + return result.found_count; } } // namespace sinks From 9bcde8b4ec60ea1347318f3258b0e6131cc0af08 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Feb 2022 04:37:17 +0300 Subject: [PATCH 183/309] Workaround gcc 4.6 not supporting defaulted virtual destructors. --- include/boost/log/sinks/text_file_backend.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 48ce8a7f3c..2894871226 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -96,7 +96,12 @@ struct BOOST_LOG_NO_VTABLE collector /*! * Virtual destructor */ +#if !defined(BOOST_GCC) || (BOOST_GCC >= 40700) BOOST_DEFAULTED_FUNCTION(virtual ~collector(), {}) +#else + // gcc 4.6 does not support defaulted virtual destructors + virtual ~collector() {} +#endif /*! * The function stores the specified file in the storage. May lead to an older file From a268b411493f5f4164c36c43d55e9c7406217cd1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Feb 2022 05:43:11 +0300 Subject: [PATCH 184/309] Added a new invoke stream manipulator. The manipulator allows to inject user's function into a stream output expression. The manipulator will pass a reference to the stream to the user's function as the first parameter, optionally followed by additional arguments passed to the manipulator construction. --- doc/changelog.qbk | 1 + doc/utilities.qbk | 58 +++++++ include/boost/log/detail/config.hpp | 25 ++- .../boost/log/utility/manipulators/invoke.hpp | 155 ++++++++++++++++++ test/run/util_manip_invoke.cpp | 152 +++++++++++++++++ 5 files changed, 386 insertions(+), 5 deletions(-) create mode 100644 include/boost/log/utility/manipulators/invoke.hpp create mode 100644 test/run/util_manip_invoke.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index ab5f8b4911..407a7a2682 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -17,6 +17,7 @@ * *Breaking change:* The [class_file_collector] interface has changed: * `scan_for_files` method returns a `scan_result` structure that contains information collected during the scan; * `is_in_storage` method added for testing if a path refers to a file within the target storage directory. +* Added a new [link log.detailed.utilities.manipulators.invoke `invoke_manip`] stream manipulator that can be used for injecting user's function into a stream output expression. [*Bug fixes:] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index 016f56b779..f8b2f25fc9 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -325,6 +325,64 @@ The "none" marker argument, if specified, is inserted into stream in case if the [endsect] +[section:invoke Invoke manipulator] + + #include <``[boost_log_utility_manipulators_invoke_hpp]``> + +Invoke manipulator allows to inject a user-defined function call into the stream output expression. The function will be called when the manipulator is inserted into the stream. The manipulator will pass a reference to the stream to the function as the first argument, optionally followed by a number of additional arguments that were specified on the manipulator construction. For example: + + void print_signal(std::ostream& stream, int sig) + { + switch (sig) + { + case SIGINT: + stream << "SIGINT"; + break; + case SIGTERM: + stream << "SIGTERM"; + break; + default: + stream << sig; + break; + } + } + + int sig = SIGINT; + + // Outputs: "Signal received: SIGINT" + BOOST_LOG(lg) << "Signal received: " << logging::invoke_manip(&print_signal, sig); + +[tip This manipulator can also be used with regular output streams, not necessarily loggers.] + +Here, `print_signal` will be called by the manipulator when its `operator<<` is called. The output stream will be passed as the first argument and any additional arguments (`sig`, in this case) following that. The arguments are captured by value by default. One can use `std::ref`/`boost::ref` if capturing by reference is needed. + +[note Passing additional arguments to the function requires a C++14 compiler. Use `std::bind`, __boost_bind__ or C++11 lambdas to bind arguments to the function instead of passing them separately if lower C++ version is required.] + +Please note that the function will be called only if the streaming expression is executed. If the log record is discarded by filters, the streaming expression is skipped and the user's function is not called. Do not use this manipulator for injecting business-critical calls into logging expressions. + +This manipulator is especially convenient with C++11 lambdas. The above example could be rewritten like this: + + int sig = SIGINT; + + // Outputs: "Signal received: SIGINT" + BOOST_LOG(lg) << "Signal received: " << logging::invoke_manip([sig](auto& stream) + { + switch (sig) + { + case SIGINT: + stream << "SIGINT"; + break; + case SIGTERM: + stream << "SIGTERM"; + break; + default: + stream << sig; + break; + } + }); + +[endsect] + [endsect] [section:ipc Interprocess communication tools] diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 1c36768525..c7c0330799 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -119,7 +119,7 @@ # include #endif -#if (!defined(__CRYSTAX__) && defined(__ANDROID__) && (__ANDROID_API__+0) < 21) \ +#if (!defined(__CRYSTAX__) && defined(__ANDROID__) && (__ANDROID_API__ < 21)) \ || (defined(__VXWORKS__) && !defined(_WRS_CONFIG_USER_MANAGEMENT)) // Until Android API version 21 Google NDK does not provide getpwuid_r # define BOOST_LOG_NO_GETPWUID_R @@ -143,21 +143,36 @@ #define BOOST_LOG_NO_CXX11_ARG_PACKS_TO_NON_VARIADIC_ARGS_EXPANSION #endif -#if defined(BOOST_NO_CXX11_CONSTEXPR) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) +#if defined(BOOST_NO_CXX11_CONSTEXPR) || (defined(BOOST_GCC) && (BOOST_GCC / 100) <= 406) // GCC 4.6 does not support in-class brace initializers for static constexpr array members #define BOOST_LOG_NO_CXX11_CONSTEXPR_DATA_MEMBER_BRACE_INITIALIZERS #endif -#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && ((BOOST_GCC+0) / 100) <= 406) +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && (BOOST_GCC / 100) <= 406) // GCC 4.6 cannot handle a defaulted function with noexcept specifier #define BOOST_LOG_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS #endif -#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_CLANG) && (((__clang_major__+0) == 3) && ((__clang_minor__+0) <= 1))) +#if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_CLANG) && ((__clang_major__ == 3) && (__clang_minor__ <= 1))) // Clang 3.1 cannot handle a defaulted constexpr constructor in some cases (presumably, if the class contains a member with a constexpr constructor) #define BOOST_LOG_NO_CXX11_DEFAULTED_CONSTEXPR_CONSTRUCTORS #endif +// The macro indicates that the compiler does not support C++20 pack expansions in lambda init-captures. +// Early gcc, clang and MSVC versions support C++20 pack expansions in lambda init-captures, +// but define __cpp_init_captures to a lower value. +#if (!defined(__cpp_init_captures) || (__cpp_init_captures < 201803)) && \ + !(\ + BOOST_CXX_VERSION > 201703 && \ + (\ + (defined(BOOST_GCC) && (BOOST_GCC >= 90000)) || \ + (defined(BOOST_CLANG) && (BOOST_CLANG_VERSION >= 90000)) || \ + (defined(BOOST_MSVC) && (BOOST_MSVC >= 1922))\ + )\ + ) +#define BOOST_LOG_NO_CXX20_PACK_EXPANSION_IN_LAMBDA_INIT_CAPTURE +#endif + #if defined(_MSC_VER) # define BOOST_LOG_NO_VTABLE __declspec(novtable) #else @@ -365,7 +380,7 @@ inline namespace BOOST_LOG_VERSION_NAMESPACE {} # define BOOST_LOG_OPEN_NAMESPACE namespace log { inline namespace BOOST_LOG_VERSION_NAMESPACE { # define BOOST_LOG_CLOSE_NAMESPACE }} -# elif defined(BOOST_GCC) && (BOOST_GCC+0) >= 40400 +# elif defined(BOOST_GCC) && (BOOST_GCC >= 40400) // GCC 7 deprecated strong using directives but allows inline namespaces in C++03 mode since GCC 4.4. __extension__ inline namespace BOOST_LOG_VERSION_NAMESPACE {} diff --git a/include/boost/log/utility/manipulators/invoke.hpp b/include/boost/log/utility/manipulators/invoke.hpp new file mode 100644 index 0000000000..a33a43e295 --- /dev/null +++ b/include/boost/log/utility/manipulators/invoke.hpp @@ -0,0 +1,155 @@ +/* + * Copyright Andrey Semashev 2022. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * https://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file utility/manipulators/invoke.hpp + * \author Andrey Semashev + * \date 27.02.2022 + * + * The header contains implementation of a stream manipulator for invoking a user-defined function. + */ + +#ifndef BOOST_LOG_UTILITY_MANIPULATORS_INVOKE_HPP_INCLUDED_ +#define BOOST_LOG_UTILITY_MANIPULATORS_INVOKE_HPP_INCLUDED_ + +#include +#include +#include +#include +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#include +#endif +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +/*! + * Stream manipulator for invoking a user-defined function as part of stream output. + */ +template< typename FunctionT > +class invoke_manipulator +{ +private: + mutable FunctionT m_function; + +public: + //! Initializing constructor + explicit invoke_manipulator(FunctionT const& func) : + m_function(func) + { + } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + //! Initializing constructor + explicit invoke_manipulator(FunctionT&& func) : + m_function(static_cast< FunctionT&& >(func)) + { + } +#endif + + //! The method invokes the saved function with the output stream + template< typename StreamT > + void output(StreamT& stream) const + { + m_function(stream); + } +}; + +/*! + * Stream output operator for \c invoke_manipulator. Invokes the function saved in the manipulator. + */ +template< typename StreamT, typename FunctionT > +inline typename boost::enable_if_c< log::aux::is_ostream< StreamT >::value, StreamT& >::type operator<< (StreamT& stream, invoke_manipulator< FunctionT > const& manip) +{ + manip.output(stream); + return stream; +} + +#if !defined(BOOST_LOG_DOXYGEN_PASS) + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +//! Invoke manipulator generator function +template< typename FunctionT > +inline invoke_manipulator< + typename boost::remove_cv< + typename boost::remove_reference< FunctionT >::type + >::type +> +invoke_manip(FunctionT&& func) +{ + return invoke_manipulator< + typename boost::remove_cv< + typename boost::remove_reference< FunctionT >::type + >::type + >(static_cast< FunctionT&& >(func)); +} + +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) && \ + !defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) + +//! Invoke manipulator generator function +template< typename FunctionT, typename Arg0, typename... Args > +inline auto invoke_manip(FunctionT&& func, Arg0&& arg0, Args&&... args) +{ + return boost::log::invoke_manip + ( +#if !defined(BOOST_LOG_NO_CXX20_PACK_EXPANSION_IN_LAMBDA_INIT_CAPTURE) + [func = static_cast< FunctionT&& >(func), arg0 = static_cast< Arg0&& >(arg0), ...args = static_cast< Args&& >(args)](auto& stream) mutable +#else + [func, arg0, args...](auto& stream) mutable +#endif + { + static_cast< FunctionT&& >(func)(stream, static_cast< Arg0&& >(arg0), static_cast< Args&& >(args)...); + } + ); +} + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) ... + +#else // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +//! Invoke manipulator generator function +template< typename FunctionT > +inline invoke_manipulator< typename boost::remove_cv< FunctionT >::type > +invoke_manip(FunctionT const& func) +{ + return invoke_manipulator< typename boost::remove_cv< FunctionT >::type >(func); +} + +#endif // !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) + +#else // !defined(BOOST_LOG_DOXYGEN_PASS) + +/*! + * Invoke manipulator generator function. + * + * \param func User-defined function to invoke on output. The function must be callable with a reference to the output stream as the first argument, followed by \a args. + * \param args Additional arguments to pass to \a func. + * \returns Manipulator to be inserted into the stream. + * + * \note \a args are only supported since C++14. + */ +template< typename FunctionT, typename... Args > +invoke_manipulator< unspecified > invoke_manip(FunctionT&& func, Args&&... args); + +#endif // !defined(BOOST_LOG_DOXYGEN_PASS) + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_UTILITY_MANIPULATORS_INVOKE_HPP_INCLUDED_ diff --git a/test/run/util_manip_invoke.cpp b/test/run/util_manip_invoke.cpp new file mode 100644 index 0000000000..c0ea0e983a --- /dev/null +++ b/test/run/util_manip_invoke.cpp @@ -0,0 +1,152 @@ +/* + * Copyright Andrey Semashev 2022. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file util_manip_invoke.cpp + * \author Andrey Semashev + * \date 27.02.2022 + * + * \brief This header contains tests for the invoke manipulator. + */ + +#define BOOST_TEST_MODULE util_manip_invoke + +#include +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; + +struct my_function0 +{ + typedef void result_type; + + template< typename StreamT > + result_type operator() (StreamT& stream) const + { + stream << "my_function0"; + } +}; + +struct my_function1 +{ + typedef void result_type; + + template< typename StreamT > + result_type operator() (StreamT& stream, int n) const + { + stream << "my_function1(" << n << ")"; + } +}; + +template< typename StreamT > +void free_function(StreamT& stream, int n) +{ + stream << "free_function(" << n << ")"; +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(invoke_my_function0, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + ostream_type strm_dump; + strm_dump << logging::invoke_manip(my_function0()); + + ostream_type strm_correct; + my_function0()(strm_correct); + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(invoke_boost_bind, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + { + ostream_type strm_dump; + strm_dump << logging::invoke_manip(boost::bind(my_function1(), boost::placeholders::_1, 10)); + + ostream_type strm_correct; + boost::bind(my_function1(), boost::placeholders::_1, 10)(strm_correct); + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); + } + { + ostream_type strm_dump; + strm_dump << logging::invoke_manip(boost::bind(&free_function< ostream_type >, boost::placeholders::_1, 10)); + + ostream_type strm_correct; + boost::bind(&free_function< ostream_type >, boost::placeholders::_1, 10)(strm_correct); + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); + } +} + +#if !defined(BOOST_NO_CXX11_LAMBDAS) + +BOOST_AUTO_TEST_CASE_TEMPLATE(invoke_lambda, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + ostream_type strm_dump; + strm_dump << logging::invoke_manip([](ostream_type& strm) { strm << "lambda"; }); + + ostream_type strm_correct; + strm_correct << "lambda"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +#endif // !defined(BOOST_NO_CXX11_LAMBDAS) + +// This list of config macros matches the similar list in boost/log/utility/manipulators/invoke.hpp +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) && \ + !defined(BOOST_NO_CXX14_GENERIC_LAMBDAS) && \ + !defined(BOOST_NO_CXX14_RETURN_TYPE_DEDUCTION) + +BOOST_AUTO_TEST_CASE_TEMPLATE(invoke_lambda_args, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + ostream_type strm_dump; + strm_dump << logging::invoke_manip([](ostream_type& strm, int x, int y) { strm << "lambda(" << x << ", " << y << ")"; }, 10, 20); + + ostream_type strm_correct; + strm_correct << "lambda(" << 10 << ", " << 20 << ")"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); +} + +BOOST_AUTO_TEST_CASE_TEMPLATE(invoke_lambda_args_ref, CharT, char_types) +{ + typedef CharT char_type; + typedef std::basic_ostringstream< char_type > ostream_type; + + int external_var = 30; + ostream_type strm_dump; + strm_dump << logging::invoke_manip([](ostream_type& strm, int x, int y, int& z) + { + strm << "lambda(" << x << ", " << y << ", " << z << ")"; + ++z; + }, 10, 20, boost::ref(external_var)); + + ostream_type strm_correct; + strm_correct << "lambda(" << 10 << ", " << 20 << ", " << 30 << ")"; + + BOOST_CHECK(equal_strings(strm_dump.str(), strm_correct.str())); + BOOST_CHECK_EQUAL(external_var, 31); +} + +#endif // !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) ... From 0e4a467573abf9df07616319306fc827d3900168 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Feb 2022 05:51:48 +0300 Subject: [PATCH 185/309] Define a config macro for gcc 4.6 not supporting defaulted virtual dtors. --- include/boost/log/detail/config.hpp | 3 ++- include/boost/log/sinks/text_file_backend.hpp | 3 +-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index c7c0330799..c7a37ac346 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -149,8 +149,9 @@ #endif #if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_GCC) && (BOOST_GCC / 100) <= 406) -// GCC 4.6 cannot handle a defaulted function with noexcept specifier +// GCC 4.6 cannot handle defaulted functions with noexcept specifier or virtual functions #define BOOST_LOG_NO_CXX11_DEFAULTED_NOEXCEPT_FUNCTIONS +#define BOOST_LOG_NO_CXX11_DEFAULTED_VIRTUAL_FUNCTIONS #endif #if defined(BOOST_NO_CXX11_DEFAULTED_FUNCTIONS) || (defined(BOOST_CLANG) && ((__clang_major__ == 3) && (__clang_minor__ <= 1))) diff --git a/include/boost/log/sinks/text_file_backend.hpp b/include/boost/log/sinks/text_file_backend.hpp index 2894871226..e6674f54cc 100644 --- a/include/boost/log/sinks/text_file_backend.hpp +++ b/include/boost/log/sinks/text_file_backend.hpp @@ -96,10 +96,9 @@ struct BOOST_LOG_NO_VTABLE collector /*! * Virtual destructor */ -#if !defined(BOOST_GCC) || (BOOST_GCC >= 40700) +#if !defined(BOOST_LOG_NO_CXX11_DEFAULTED_VIRTUAL_FUNCTIONS) BOOST_DEFAULTED_FUNCTION(virtual ~collector(), {}) #else - // gcc 4.6 does not support defaulted virtual destructors virtual ~collector() {} #endif From 98479a4f250f911157ec469c857be24fade8d79c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 27 Feb 2022 13:04:18 +0300 Subject: [PATCH 186/309] Work around MSVC 14.0 ICE in invoke_manip. --- include/boost/log/utility/manipulators/invoke.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/boost/log/utility/manipulators/invoke.hpp b/include/boost/log/utility/manipulators/invoke.hpp index a33a43e295..9907746718 100644 --- a/include/boost/log/utility/manipulators/invoke.hpp +++ b/include/boost/log/utility/manipulators/invoke.hpp @@ -111,7 +111,12 @@ inline auto invoke_manip(FunctionT&& func, Arg0&& arg0, Args&&... args) [func, arg0, args...](auto& stream) mutable #endif { +#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1910 static_cast< FunctionT&& >(func)(stream, static_cast< Arg0&& >(arg0), static_cast< Args&& >(args)...); +#else + // MSVC 19.0 (VS 14.0) ICEs if we use perfect forwarding here + func(stream, arg0, args...); +#endif } ); } From dda118619ad4abc0ffb5c603e7e086a291da2c72 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 22 Apr 2022 18:14:11 +0300 Subject: [PATCH 187/309] Fixed binding IPv4 local address in syslog_backend when IPv6 target is used. Fixes https://github.com/boostorg/log/issues/181. --- doc/changelog.qbk | 6 ++++++ src/syslog_backend.cpp | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 407a7a2682..a385a5b08b 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,12 @@ [section:changelog Changelog] +[heading 2.25, Boost 1.80] + +[*Bug fixes:] + +* Fixed binding incorrect local address in UDP socket-based [link log.detailed.sink_backends.syslog `syslog_backend`] when IPv6 address is used for the syslog server. ([github_issue 181]) + [heading 2.24, Boost 1.79] [*General changes:] diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index b39838d58b..7331c7d293 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -452,7 +452,7 @@ struct syslog_backend::implementation::udp_socket_based : { if (!m_pSocket.get()) { - asio::ip::udp::endpoint any_local_address; + asio::ip::udp::endpoint any_local_address(m_Protocol, 0u); m_pSocket.reset(new syslog_udp_socket(m_pService->m_IOContext, m_Protocol, any_local_address)); } From 77f1e20bd69c2e7a9e25e6a9818ae6105f7d070c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 5 Jun 2022 17:15:09 +0300 Subject: [PATCH 188/309] Ported strictest_lock from mpl::integral_c to boost::integral_constant. This removes one dependency on Boost.MPL and should resolve compiler warnings coming from mpl::integral_c definition (integral_c defines typedefs for previous and next values, which cannot be deduced for enums). --- include/boost/log/utility/strictest_lock.hpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/include/boost/log/utility/strictest_lock.hpp b/include/boost/log/utility/strictest_lock.hpp index accc8b7a70..e40e400f6e 100644 --- a/include/boost/log/utility/strictest_lock.hpp +++ b/include/boost/log/utility/strictest_lock.hpp @@ -16,7 +16,7 @@ #ifndef BOOST_LOG_UTILITY_STRICTEST_LOCK_HPP_INCLUDED_ #define BOOST_LOG_UTILITY_STRICTEST_LOCK_HPP_INCLUDED_ -#include +#include #include #include #if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) @@ -67,49 +67,49 @@ template< typename LockT > struct thread_access_mode_of; template< typename MutexT > -struct thread_access_mode_of< no_lock< MutexT > > : mpl::integral_c< lock_access_mode, unlocked_access > +struct thread_access_mode_of< no_lock< MutexT > > : boost::integral_constant< lock_access_mode, unlocked_access > { }; #if !defined(BOOST_LOG_NO_THREADS) template< typename MutexT > -struct thread_access_mode_of< lock_guard< MutexT > > : mpl::integral_c< lock_access_mode, exclusive_access > +struct thread_access_mode_of< lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > { }; template< typename MutexT > -struct thread_access_mode_of< shared_lock_guard< MutexT > > : mpl::integral_c< lock_access_mode, shared_access > +struct thread_access_mode_of< shared_lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > { }; template< typename MutexT > -struct thread_access_mode_of< unique_lock< MutexT > > : mpl::integral_c< lock_access_mode, exclusive_access > +struct thread_access_mode_of< unique_lock< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > { }; template< typename MutexT > -struct thread_access_mode_of< shared_lock< MutexT > > : mpl::integral_c< lock_access_mode, shared_access > +struct thread_access_mode_of< shared_lock< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > { }; template< typename MutexT > -struct thread_access_mode_of< upgrade_lock< MutexT > > : mpl::integral_c< lock_access_mode, shared_access > +struct thread_access_mode_of< upgrade_lock< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > { }; template< typename MutexT > -struct thread_access_mode_of< boost::log::aux::exclusive_lock_guard< MutexT > > : mpl::integral_c< lock_access_mode, exclusive_access > +struct thread_access_mode_of< boost::log::aux::exclusive_lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > { }; template< typename MutexT > -struct thread_access_mode_of< boost::log::aux::shared_lock_guard< MutexT > > : mpl::integral_c< lock_access_mode, shared_access > +struct thread_access_mode_of< boost::log::aux::shared_lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > { }; template< typename MutexT1, typename MutexT2 > -struct thread_access_mode_of< boost::log::aux::multiple_unique_lock2< MutexT1, MutexT2 > > : mpl::integral_c< lock_access_mode, exclusive_access > +struct thread_access_mode_of< boost::log::aux::multiple_unique_lock2< MutexT1, MutexT2 > > : boost::integral_constant< lock_access_mode, exclusive_access > { }; From 269cedff6cdb81711e70e1202fddb67520012931 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 5 Jun 2022 18:17:57 +0300 Subject: [PATCH 189/309] Added a workaround for std::codecvt::do_length bug in libstdc++. Apparently, std::codecvt::do_length in libstdc++ from gcc 11.2 accesses input characters outside the input range if max is specified larger than the input range. This causes buffer overflow and a crash. Use the input range size as the max limit, which should have the same effect as the previous hardcoded limit. gcc bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105857 --- doc/changelog.qbk | 1 + include/boost/log/detail/attachable_sstream_buf.hpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index a385a5b08b..a73f959ef8 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -14,6 +14,7 @@ [*Bug fixes:] * Fixed binding incorrect local address in UDP socket-based [link log.detailed.sink_backends.syslog `syslog_backend`] when IPv6 address is used for the syslog server. ([github_issue 181]) +* Added a workaround for a [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105857 bug] in libstdc++ from gcc 11.2. When [link log.detailed.expressions.formatters.decorators.max_size `max_size_decor`] was used on a formatting stream, `std::codecvt::do_length` incorrectly accessed the input buffer and caused a buffer overflow. [heading 2.24, Boost 1.79] diff --git a/include/boost/log/detail/attachable_sstream_buf.hpp b/include/boost/log/detail/attachable_sstream_buf.hpp index 6a4fc5cb76..b7005ce248 100644 --- a/include/boost/log/detail/attachable_sstream_buf.hpp +++ b/include/boost/log/detail/attachable_sstream_buf.hpp @@ -283,12 +283,12 @@ class basic_ostringstreambuf : private: //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size - size_type length_until_boundary(const char_type* s, size_type, size_type max_size, boost::integral_constant< std::size_t, 1u >) const + size_type length_until_boundary(const char_type* s, size_type n, size_type max_size, boost::integral_constant< std::size_t, 1u >) const { std::locale loc = this->getloc(); std::codecvt< wchar_t, char, std::mbstate_t > const& fac = std::use_facet< std::codecvt< wchar_t, char, std::mbstate_t > >(loc); std::mbstate_t mbs = std::mbstate_t(); - return static_cast< size_type >(fac.length(mbs, s, s + max_size, ~static_cast< std::size_t >(0u))); + return static_cast< size_type >(fac.length(mbs, s, s + max_size, n)); } //! Finds the string length so that it includes only complete characters, and does not exceed \a max_size From e6e59f350f52160e2eb92cda623aa944b56d441f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 6 Jun 2022 03:30:50 +0300 Subject: [PATCH 190/309] Added VS2022 job and C++20 jobs to AppVeyor CI. --- appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 05ae1b220d..c874354ce2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,8 +37,12 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: msvc-14.2 ADDRESS_MODEL: 64 - CXXSTD: 14,17 + CXXSTD: 14,17,20 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 + - TOOLSET: msvc-14.3 + ADDRESS_MODEL: 64 + CXXSTD: 14,17,20 + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 - TOOLSET: gcc ADDRESS_MODEL: 64 CXXSTD: 03,11 @@ -83,7 +87,7 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - TOOLSET: msvc-14.2 ADDRESS_MODEL: 32 - CXXSTD: 14,17 + CXXSTD: 14,17,20 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: gcc ADDRESS_MODEL: 32 From de974a6c70f7b8f3bb72a772aa4b25c34ee61054 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 6 Jun 2022 03:32:20 +0300 Subject: [PATCH 191/309] Updated copyright years in AppVeyor CI config. --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c874354ce2..14015be8e4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# Copyright 2019 - 2021 Andrey Semashev +# Copyright 2019 - 2022 Andrey Semashev # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) From cb3d7c5b0849655fa328da3b0d3b458eddeb9683 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 8 Jun 2022 14:52:54 +0300 Subject: [PATCH 192/309] Ported some components from Boost.MPL to Boost.TypeTraits and pure C++. --- .../boost/log/sinks/basic_sink_frontend.hpp | 6 ++--- .../boost/log/sinks/frontend_requirements.hpp | 26 ++++++++++++++++--- .../log/sources/exception_handler_feature.hpp | 6 ++--- .../boost/log/sources/threading_models.hpp | 6 ++--- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/include/boost/log/sinks/basic_sink_frontend.hpp b/include/boost/log/sinks/basic_sink_frontend.hpp index 38ecf0ea54..c446985e2b 100644 --- a/include/boost/log/sinks/basic_sink_frontend.hpp +++ b/include/boost/log/sinks/basic_sink_frontend.hpp @@ -15,7 +15,7 @@ #ifndef BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_BASIC_SINK_FRONTEND_HPP_INCLUDED_ -#include +#include #include #include #include @@ -224,7 +224,7 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : private: //! Flushes record buffers in the backend (the actual implementation) template< typename BackendMutexT, typename BackendT > - void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, mpl::true_) + void flush_backend_impl(BackendMutexT& backend_mutex, BackendT& backend, boost::true_type) { try { @@ -247,7 +247,7 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : } //! Flushes record buffers in the backend (stub for backends that don't support flushing) template< typename BackendMutexT, typename BackendT > - void flush_backend_impl(BackendMutexT&, BackendT&, mpl::false_) + void flush_backend_impl(BackendMutexT&, BackendT&, boost::false_type) { } }; diff --git a/include/boost/log/sinks/frontend_requirements.hpp b/include/boost/log/sinks/frontend_requirements.hpp index 3577ab1905..5fd1586658 100644 --- a/include/boost/log/sinks/frontend_requirements.hpp +++ b/include/boost/log/sinks/frontend_requirements.hpp @@ -17,6 +17,9 @@ #ifndef BOOST_LOG_SINKS_FRONTEND_REQUIREMENTS_HPP_INCLUDED_ #define BOOST_LOG_SINKS_FRONTEND_REQUIREMENTS_HPP_INCLUDED_ +#include +#include +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #include #include @@ -24,8 +27,7 @@ #include #include #include -#include -#include +#endif #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -75,7 +77,7 @@ struct formatted_records {}; */ struct flushing {}; -#ifdef BOOST_LOG_DOXYGEN_PASS +#if defined(BOOST_LOG_DOXYGEN_PASS) /*! * The metafunction combines multiple requirement tags into one type. The resulting type will @@ -84,6 +86,24 @@ struct flushing {}; template< typename... RequirementsT > struct combine_requirements; +#elif !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + +namespace aux { + +template< typename... RequirementsT > +struct combined_requirements : + public RequirementsT... +{ +}; + +} // namespace aux + +template< typename... RequirementsT > +struct combine_requirements +{ + typedef sinks::aux::combined_requirements< RequirementsT... > type; +}; + #else template< BOOST_PP_ENUM_PARAMS_WITH_A_DEFAULT(BOOST_LOG_COMBINE_REQUIREMENTS_LIMIT, typename ReqT, mpl::na) > diff --git a/include/boost/log/sources/exception_handler_feature.hpp b/include/boost/log/sources/exception_handler_feature.hpp index 146815e0d4..feedc247d8 100644 --- a/include/boost/log/sources/exception_handler_feature.hpp +++ b/include/boost/log/sources/exception_handler_feature.hpp @@ -15,11 +15,11 @@ #ifndef BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ #define BOOST_LOG_SOURCES_EXCEPTION_HANDLER_FEATURE_HPP_INCLUDED_ -#include #include #include #include #include +#include #include #include #include @@ -211,8 +211,8 @@ class basic_exception_handler_logger : // we shall acquire a read lock here, when an exception is caught. // If other features do require locking, the thread model is // already locked by now, and we don't do locking at all. - typedef typename mpl::if_< - is_same< no_lock< threading_model >, typename final_type::push_record_lock >, + typedef typename boost::conditional< + is_same< no_lock< threading_model >, typename final_type::push_record_lock >::value, boost::log::aux::shared_lock_guard< threading_model >, no_lock< threading_model > >::type lock_type; diff --git a/include/boost/log/sources/threading_models.hpp b/include/boost/log/sources/threading_models.hpp index b9a5220873..20920eec23 100644 --- a/include/boost/log/sources/threading_models.hpp +++ b/include/boost/log/sources/threading_models.hpp @@ -21,7 +21,7 @@ #include #include // is_mutex_type #if !defined(BOOST_LOG_NO_THREADS) -#include +#include #endif #include @@ -121,12 +121,12 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #if !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_DOXYGEN_PASS) template< > -struct is_mutex_type< boost::log::sources::single_thread_model > : mpl::true_ +struct is_mutex_type< boost::log::sources::single_thread_model > : boost::true_type { }; template< typename T > -struct is_mutex_type< boost::log::sources::multi_thread_model< T > > : mpl::true_ +struct is_mutex_type< boost::log::sources::multi_thread_model< T > > : boost::true_type { }; From 34304f253f40d4a1c6058ca34a52c7efba162b38 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 8 Jun 2022 16:57:33 +0300 Subject: [PATCH 193/309] Fixed a typo causing missing includes. --- include/boost/log/sinks/frontend_requirements.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/log/sinks/frontend_requirements.hpp b/include/boost/log/sinks/frontend_requirements.hpp index 5fd1586658..d89ea9f309 100644 --- a/include/boost/log/sinks/frontend_requirements.hpp +++ b/include/boost/log/sinks/frontend_requirements.hpp @@ -19,7 +19,7 @@ #include #include -#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) +#if defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) #include #include #include From fa675cca2b58d6c087fc63de56e894fa7fb607f3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 24 Jun 2022 18:20:58 +0300 Subject: [PATCH 194/309] Switched to Boost.TypeTraits from Boost.MPL for sink init helpers. --- include/boost/log/detail/sink_init_helpers.hpp | 10 +++++----- include/boost/log/utility/setup/file.hpp | 5 +++-- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/include/boost/log/detail/sink_init_helpers.hpp b/include/boost/log/detail/sink_init_helpers.hpp index 4f0bed850c..8d98384cfa 100644 --- a/include/boost/log/detail/sink_init_helpers.hpp +++ b/include/boost/log/detail/sink_init_helpers.hpp @@ -17,10 +17,10 @@ #define BOOST_LOG_DETAIL_SINK_INIT_HELPERS_HPP_INCLUDED_ #include -#include #include #include #include +#include #include #include #include @@ -90,12 +90,12 @@ inline typename boost::disable_if_c< // The function installs filter into the sink, if provided in the arguments pack template< typename SinkT, typename ArgsT > -inline void setup_filter(SinkT&, ArgsT const&, mpl::true_) +inline void setup_filter(SinkT&, ArgsT const&, boost::true_type) { } template< typename SinkT, typename ArgsT > -inline void setup_filter(SinkT& s, ArgsT const& args, mpl::false_) +inline void setup_filter(SinkT& s, ArgsT const& args, boost::false_type) { s.set_filter(aux::acquire_filter(args[keywords::filter])); } @@ -144,12 +144,12 @@ inline typename boost::disable_if_c< // The function installs filter into the sink, if provided in the arguments pack template< typename SinkT, typename ArgsT > -inline void setup_formatter(SinkT&, ArgsT const&, mpl::true_) +inline void setup_formatter(SinkT&, ArgsT const&, boost::true_type) { } template< typename SinkT, typename ArgsT > -inline void setup_formatter(SinkT& s, ArgsT const& args, mpl::false_) +inline void setup_formatter(SinkT& s, ArgsT const& args, boost::false_type) { s.set_formatter(aux::acquire_formatter(args[keywords::format])); } diff --git a/include/boost/log/utility/setup/file.hpp b/include/boost/log/utility/setup/file.hpp index 769b223e57..373c740ed9 100644 --- a/include/boost/log/utility/setup/file.hpp +++ b/include/boost/log/utility/setup/file.hpp @@ -16,6 +16,7 @@ #define BOOST_LOG_UTILITY_SETUP_FILE_HPP_INCLUDED_ #include +#include #include #include #include // for is_named_argument @@ -61,12 +62,12 @@ namespace aux { //! The function creates a file collector according to the specified arguments template< typename ArgsT > -inline shared_ptr< sinks::file::collector > setup_file_collector(ArgsT const&, mpl::true_ const&) +inline shared_ptr< sinks::file::collector > setup_file_collector(ArgsT const&, boost::true_type) { return shared_ptr< sinks::file::collector >(); } template< typename ArgsT > -inline shared_ptr< sinks::file::collector > setup_file_collector(ArgsT const& args, mpl::false_ const&) +inline shared_ptr< sinks::file::collector > setup_file_collector(ArgsT const& args, boost::false_type) { return sinks::file::make_collector(args); } From e078fc69cdbc3d67998560af8b852942c6aa4ae0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 12 Aug 2022 16:01:22 +0300 Subject: [PATCH 195/309] Switch to macos-11 GHA image as macos-10.15 is deprecated. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a6b7589c4e..5a40b1460a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -236,7 +236,7 @@ jobs: - toolset: clang cxxstd: "03,11,14,17,2a" - os: macos-10.15 + os: macos-11 - name: CMake tests cmake_tests: 1 From 4f28b2894b34e7760babfb9ce8d6e32270e1d2ef Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Aug 2022 14:09:46 +0300 Subject: [PATCH 196/309] Replaced ubuntu-18.04 GHA CI images with containers. Also use ubuntu-latest image for jobs that are running in a container. --- .github/workflows/ci.yml | 53 ++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5a40b1460a..4217cc7383 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# Copyright 2021 Andrey Semashev +# Copyright 2021-2022 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -37,7 +37,7 @@ jobs: # Linux, gcc - toolset: gcc-4.4 cxxstd: "98,0x" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.4 @@ -45,7 +45,7 @@ jobs: - "ppa:ubuntu-toolchain-r/test" - toolset: gcc-4.6 cxxstd: "03,0x" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.6 @@ -53,46 +53,51 @@ jobs: - "ppa:ubuntu-toolchain-r/test" - toolset: gcc-4.7 cxxstd: "03,11" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.7 - toolset: gcc-4.8 cxxstd: "03,11" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - g++-4.8 - toolset: gcc-4.9 cxxstd: "03,11" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.9 extra_tests: 1 - toolset: gcc-5 cxxstd: "03,11,14,1z" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - g++-5 - toolset: gcc-6 cxxstd: "03,11,14,1z" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - g++-6 - toolset: gcc-7 cxxstd: "03,11,14,17" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - g++-7 - toolset: gcc-8 cxxstd: "03,11,14,17,2a" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - g++-8 - toolset: gcc-9 cxxstd: "03,11,14,17,2a" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - g++-9 - toolset: gcc-10 @@ -122,66 +127,72 @@ jobs: - toolset: clang compiler: clang++-3.5 cxxstd: "03,11" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.5 - toolset: clang compiler: clang++-3.6 cxxstd: "03,11,14" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.6 - toolset: clang compiler: clang++-3.7 cxxstd: "03,11,14" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.7 - toolset: clang compiler: clang++-3.8 cxxstd: "03,11,14" - os: ubuntu-20.04 + os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.8 - toolset: clang compiler: clang++-3.9 cxxstd: "03,11,14" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-3.9 - toolset: clang compiler: clang++-4.0 cxxstd: "03,11,14" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-4.0 - toolset: clang compiler: clang++-5.0 cxxstd: "03,11,14,1z" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-5.0 - toolset: clang compiler: clang++-6.0 cxxstd: "03,11,14,17" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-6.0 - toolset: clang compiler: clang++-7 cxxstd: "03,11,14,17" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-7 # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode - toolset: clang compiler: clang++-8 cxxstd: "03,11,14,17,2a" - os: ubuntu-18.04 + os: ubuntu-latest + container: ubuntu:18.04 install: - clang-8 - g++-7 From 93174ac2c69e9909025287fbb5b99ed43e49c1af Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Aug 2022 17:54:25 +0300 Subject: [PATCH 197/309] Switched gcc-9 to ubuntu-20.04 GHA CI image. --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4217cc7383..873da0774e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -96,8 +96,7 @@ jobs: - g++-8 - toolset: gcc-9 cxxstd: "03,11,14,17,2a" - os: ubuntu-latest - container: ubuntu:18.04 + os: ubuntu-20.04 install: - g++-9 - toolset: gcc-10 From dcea5e6b0fa7990418f82b735e25734d2ac88a59 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 28 Aug 2022 23:26:31 +0300 Subject: [PATCH 198/309] Added a docs section discussing Boost.Log use in libraries. Closes https://github.com/boostorg/log/issues/193. --- doc/rationale.qbk | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/doc/rationale.qbk b/doc/rationale.qbk index baa668085a..742c89fd70 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -224,4 +224,34 @@ The suggested solution is to upgrade Visual Studio 2010 to Visual Studio 2010 SP [endsect] +[section:how_to_use_in_libraries How to use Boost.Log in libraries?] + +When using Boost.Log with libraries, there are several recommendadions to follow. First, as noted in the [link log.installation.config library configuration] section, using the library in multiple modules (including libraries and the application itself) requires Boost.Log to be built as a shared library. This is needed because Boost.Log maintains a number of process-wide singletons and may not function correctly if these singletons are duplicated. If building Boost.Log as a shared library is not desirable, it is possible to encapsulate it in a single user's shared library and link the rest of the modules with that library. In this case, Boost.Log can be built as a shared library and linked into user's shared library. The shared library API and other modules must not use Boost.Log components, including: + +* Logging core +* Sinks +* Loggers +* Attributes, including named scope markup +* Library configuration helpers, including filter, formatter and settings parsers + +However, user's shared library may provide its own API that will implement similar functionality, using relevant Boost.Log facilities internally. + +Next, it is important to ensure that logging configuration is coordinated between all modules. For example, if a file log is needed, only one file sink must be added, regardless of how many libraries are using logging. The preferred way to achieve this is perform logging configuration only in the main application, for the following reasons: + +* Logging configuration should be performed early in the `main` function, which is implemented in the application. Using global constructors in libraries can be problematic due to undefined order of global initialization and the possibility of dynamic loading and unloading of the libraries. +* Libraries are normally "serving the needs" of the main application, and conceptually it is the application that must decide how the library exposes its diagnostic information such as logs. One application may want to output its logs to console, another one store it in a file, and a third one may want to completely suppress any logging. A well-behaved library should transparently support any such use case and Boost.Log allows to achieve exactly that. + +It should be noted that having logging configured by the application implies that the application is written in C++ and can use Boost.Log. If this is not the case, libraries should still allow for this design and offer an API for configuring logging on behalf of the application. Alternatively, a separate library written in C++ can be used for the sole purpose of configuring logging. This way logging set up decisions are still made by the application, indirectly through the library API. + +To implement this design, here are recommendations for library writers: + +* Libraries should refrain from adding or configuring sinks, filters or formatters, including using library configuration helpers. The exception is the aforementioned API that configures logging on behalf of the application, but this configuretion should not be performed by default. +* Libraries should be careful about adding or removing global and thread-specific attributes in the logging core - any such actions must be clearly documented. +* Libraries can freely create loggers, modify their attributes and emit log records. +* Libraries may use named scope markup, even if they don't register [link log.detailed.attributes.named_scope `named_scope`] attribute themselves. The application can add and configure this attribute, which will enable this information in the output. +* Libraries should document the attributes it uses, incliding their names and value types, so that the application can configure filters and formatters accordingly. This includes the message text attribute - in particular, it is important to know the type of the attribute value (e.g. `std::string` vs. `std::wstring`) and what character encoding it uses. If possible, declare [link log.detailed.expressions.attr_keywords attribute keywords] for all attributes used by the library in a public header. +* Libraries are recommended to mark all log records they emit with an attribute. For example, all log records could be made in a specific [link log.detailed.sources.channel_logger channel]. This way the application will be able to configure logging specifically for the library (for example, extract log records from the library to a separate file or apply a different severity level threshold). + +[endsect] + [endsect] From 01d627a480451d8e44b88686407fd79f80ec417d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 28 Aug 2022 23:29:44 +0300 Subject: [PATCH 199/309] Updated docs copyright years. --- doc/attributes.qbk | 2 +- doc/core.qbk | 2 +- doc/design.qbk | 2 +- doc/expressions.qbk | 2 +- doc/extension.qbk | 2 +- doc/log.qbk | 2 +- doc/rationale.qbk | 2 +- doc/sink_backends.qbk | 2 +- doc/sink_frontends.qbk | 2 +- doc/sources.qbk | 2 +- doc/todo.qbk | 2 +- doc/tutorial.qbk | 2 +- doc/utilities.qbk | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/attributes.qbk b/doc/attributes.qbk index 2d07fc7aad..4429afed20 100644 --- a/doc/attributes.qbk +++ b/doc/attributes.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/core.qbk b/doc/core.qbk index 160c4e739d..b28b96ce0e 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/design.qbk b/doc/design.qbk index 2371c11ecf..a0f6afcaf6 100644 --- a/doc/design.qbk +++ b/doc/design.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/expressions.qbk b/doc/expressions.qbk index eaaa9c5ff8..c0511566c4 100644 --- a/doc/expressions.qbk +++ b/doc/expressions.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2016. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/extension.qbk b/doc/extension.qbk index 6ac92bd623..c488dde9bf 100644 --- a/doc/extension.qbk +++ b/doc/extension.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/log.qbk b/doc/log.qbk index 3f7e17d06e..cd68a81641 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -2,7 +2,7 @@ [quickbook 1.5] [version v2] [authors [Semashev, Andrey]] - [copyright 2007 - 2021 Andrey Semashev] + [copyright 2007 - 2022 Andrey Semashev] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 742c89fd70..26d2ce16c6 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/sink_backends.qbk b/doc/sink_backends.qbk index 0894fb02f5..38586994fd 100644 --- a/doc/sink_backends.qbk +++ b/doc/sink_backends.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2016. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/sink_frontends.qbk b/doc/sink_frontends.qbk index 8c00ce0c6a..e9196929b6 100644 --- a/doc/sink_frontends.qbk +++ b/doc/sink_frontends.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/sources.qbk b/doc/sources.qbk index 0f52ecd42e..221329d551 100644 --- a/doc/sources.qbk +++ b/doc/sources.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/todo.qbk b/doc/todo.qbk index 602f0b4e0f..161cde63c5 100644 --- a/doc/todo.qbk +++ b/doc/todo.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index edb5cb21df..433e13a9ba 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2015. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/utilities.qbk b/doc/utilities.qbk index f8b2f25fc9..3f91880679 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2016. + Copyright Andrey Semashev 2007 - 2022. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) From b7cfe7ee0e08db464d5a6d83f7f0a8606b46e5e1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 29 Aug 2022 00:20:14 +0300 Subject: [PATCH 200/309] Wording improvements in the docs. --- doc/attributes.qbk | 6 ++++-- doc/expressions.qbk | 2 +- doc/rationale.qbk | 2 +- doc/tutorial.qbk | 24 ++++++++++++------------ doc/utilities.qbk | 4 ++-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/doc/attributes.qbk b/doc/attributes.qbk index 4429afed20..275756f40d 100644 --- a/doc/attributes.qbk +++ b/doc/attributes.qbk @@ -173,6 +173,8 @@ One of the "must-have" features of any logging library is support for attaching BOOST_LOG(lg) << "This record has a time stamp"; } +[note As any other attribute, the value of the wall clock attribute is obtained at the point of the log record creation, not at the point of its processing in a sink. This means that (a) timetamps attached to log records always reflect the time point of the event occurrence, not the time of storing the log record, and (b) if the same log record is processed by multiple sinks, even at different points in time, these sinks will process (e.g. store in their respective files) the same timestamp. This is a useful property of the wall clock attribute, although it may result in [link log.rationale.why_weak_record_ordering weak ordering of log records] in the output.] + [endsect] [section:timer Stop watch (timer)] @@ -364,7 +366,7 @@ This attribute is a simple wrapper around a user-defined function object. Each a logging::core::get()->add_global_attribute("MyRandomAttr", attrs::make_function(&std::rand)); } -Auto-generated function objects, like the ones defined in __boost_bind__ or STL, are also supported. +Auto-generated function objects, like the ones defined in __boost_bind__ or C++ standard library, are also supported. [note Some deficient compilers may not support `result_of` construct properly. This metafunction is used in the `make_function` function to automatically detect the return type of the function object. If `result_of` breaks or detects incorrect type, one can try to explicitly specify the return type of the function object as a template argument to the `make_function` function.] @@ -392,7 +394,7 @@ The [class_log_attribute_name] class supports an empty (uninitialized) state whe #include <``[boost_log_attributes_attribute_set_hpp]``> -Attribute set is an unordered associative container that maps [link log.detailed.attributes.related_components.attribute_name attribute names] to [link log.detailed.attributes attributes]. It is used in [link log.detailed.sources loggers] and the [link log.detailed.core.core logging core] to store source-specific, thread-specific and global attributes. The interface is very similar to STL associative containers and is described in the [class_log_attribute_set] class reference. +Attribute set is an unordered associative container that maps [link log.detailed.attributes.related_components.attribute_name attribute names] to [link log.detailed.attributes attributes]. It is used in [link log.detailed.sources loggers] and the [link log.detailed.core.core logging core] to store source-specific, thread-specific and global attributes. The interface is very similar to standard library associative containers and is described in the [class_log_attribute_set] class reference. [endsect] diff --git a/doc/expressions.qbk b/doc/expressions.qbk index c0511566c4..bbc0c3bdb6 100644 --- a/doc/expressions.qbk +++ b/doc/expressions.qbk @@ -272,7 +272,7 @@ As was noted in the [link log.tutorial.formatters tutorial], the library provide sink->set_formatter(expr::stream << expr1 << expr2 << ... << exprN); -Here expressions `expr1` through `exprN` may be either manipulators, described in this section, or other expressions resulting in an object that supports putting into an STL-stream. +Here expressions `expr1` through `exprN` may be either manipulators, described in this section, or other expressions resulting in an object that supports putting into a standard library output stream. To use __boost_format__-style syntax one should use `format` construct: diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 26d2ce16c6..4a764b820a 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -91,7 +91,7 @@ There were other issues, like having an attribute set iterator that points to on [section:why_weak_record_ordering Why log records are weakly ordered in a multithreaded application?] -Although the library guarantees that log records made in a given thread are always delivered to sinks in the same order as they were made in, the library cannot provide such guarantee for different threads. For instance, it is possible that thread A emits a log record and gets preempted, then thread B emits its log record and manages to deliver it to a sink before being preempted. The resulting log will contain log record from thread B before the record made in thread A. However, attribute values attached to the records will always be actual with regard to the moment of emitting the record and not the moment of passing the record to the sink. This is the reason for a strange, at first glance, situation when a log record with an earlier time stamp follows a record with a later time stamp. The problem appears quite rarely, usually when thread contention on logging is very high. +Although the library guarantees that log records made in a given thread are always delivered to sinks in the same order as they were made in, the library cannot provide such guarantee for different threads. For instance, it is possible that thread A emits a log record and gets preempted, then thread B emits its log record and manages to deliver it to a sink before being preempted. The resulting log will contain log record from thread B before the record made in thread A. However, attribute values attached to the records will always be actual with regard to the moment of emitting the record and not the moment of passing the record to the sink. This is the reason for a strange, at first glance, situation when a log record with an earlier time stamp follows a record with a later time stamp. The problem appears quite rarely, usually when thread contention on logging is rather high. There are few possible ways to cope with the problem: diff --git a/doc/tutorial.qbk b/doc/tutorial.qbk index 433e13a9ba..fbb73b1220 100644 --- a/doc/tutorial.qbk +++ b/doc/tutorial.qbk @@ -13,7 +13,7 @@ In this section we shall walk through the essential steps to get started with th [section:trivial Trivial logging] -For those who don't want to read tons of clever manuals and just need a simple tool for logging, here you go: +For those who don't want to read tons of abstruse manuals and just need a simple tool for logging, here you go: [example_tutorial_trivial] @@ -25,7 +25,7 @@ The `BOOST_LOG_TRIVIAL` macro accepts a severity level and results in a stream-l # It is safe to write logs from different threads concurrently, log messages will not be corrupted. # As will be shown later, filtering can be applied. -It must be said that the macro, along with other similar macros provided by the library, is not the only interface the library offers. It is possible to issue log records without using any macros at all. +It must be said that the macro, along with other similar macros provided by the library, is not the only interface the library offers. As will be shown later, it is possible to issue log records without using any macros at all. [endsect] @@ -69,7 +69,7 @@ The added piece is the call to the [link log.detailed.utilities.setup.convenienc You can see that the options are passed to the function in the named form. This approach is also taken in many other places of the library. You'll get used to it. The meaning of the parameters is mostly self-explaining and is documented in this manual (see [link log.detailed.sink_backends.text_file here] for what regards the text file sink). This and other convenience initialization functions are described in [link log.detailed.utilities.setup.convenience this] section. -[note You can register more than one sink. Each sink will receive and process log records as you emit them independently from others.] +[tip You can register more than one sink. Each sink will receive and process log records as you emit them independently from others.] [heading Sinks in depth: More sinks] @@ -85,7 +85,7 @@ Ok, the first thing you may have noticed about sinks is that they are composed o The [link log.detailed.sink_frontends.sync `synchronous_sink`] class template above indicates that the sink is synchronous, that is, it allows for several threads to log simultaneously and will block in case of contention. This means that the backend [link log.detailed.sink_backends.text_ostream `text_ostream_backend`] doesn't have to worry about multithreading at all. There are other sink frontends available, you can read more about them [link log.detailed.sink_frontends here]. -The [link log.detailed.sink_backends.text_ostream `text_ostream_backend`] class writes formatted log records into STL-compatible streams. We have used a file stream above but we could have used any type of stream. For example, adding output to console could look as follows: +The [link log.detailed.sink_backends.text_ostream `text_ostream_backend`] class writes formatted log records into standard library-compatible streams. We have used a file stream above but we could have used any type of stream. For example, adding output to console could look as follows: #include @@ -99,7 +99,7 @@ The [link log.detailed.sink_backends.text_ostream `text_ostream_backend`] suppor The library provides a number of [link log.detailed.sink_backends backends] that provide different log processing logic. For instance, by specifying the [link log.detailed.sink_backends.syslog syslog] backend you can send log records over the network to the syslog server, or by setting up the [link log.detailed.sink_backends.event_log Windows NT event log] backend you can monitor your application run time with the standard Windows tools. -The last thing worth noting here is the `locked_backend` member function call to access the sink backend. It is used to get thread-safe access to the backend and is provided by all sink frontends. This function returns a smart-pointer to the backend and as long as it exists the backend is locked (which means even if another thread tries to log and the log record is passed to the sink, it will not be logged until you release the backend). The only exception is the [link log.detailed.sink_frontends.unlocked `unlocked_sink`] frontend which does not synchronize at all and simply returns an unlocked pointer to the backend. +The last thing worth noting here is the `locked_backend` member function call to access the sink backend. It is used to get thread-safe exclusive access to the backend and is provided by all sink frontends. This function returns a smart-pointer to the backend and as long as it exists the backend is locked (which means even if another thread tries to log and the log record is passed to the sink, it will not be logged until you release the backend). The only exception is the [link log.detailed.sink_frontends.unlocked `unlocked_sink`] frontend which does not synchronize at all and simply returns an unlocked pointer to the backend. [endsect] @@ -107,13 +107,13 @@ The last thing worth noting here is the `locked_backend` member function call to [heading Dedicated logger objects] -Now that we have defined where and how the log is to be stored, it's time to go on and try logging. In order to do this one has to create a logging source. This would be a logger object in our case and it is as simple as that: +Now that we have defined where and how the log is to be stored, it's time to see how we emit log records. In order to be able to make log records one has to create a logging source first. This would be a logger object in our case and it is as simple as that: src::logger lg; -[note A curious reader could have noticed that we did not create any loggers for trivial logging. In fact the logger is provided by the library and is used behind the scenes.] +[note A mindful reader could have noticed that we did not create any loggers when we tried trivial logging. In that case the logger is provided by the library and is used behind the scenes.] -Unlike sinks, sources need not be registered anywhere since they interact directly with the logging core. Also note that there are two versions of loggers provided by the library: the thread-safe ones and the non-thread-safe ones. For the non-thread-safe loggers it is safe for different threads to write logs through different instances of loggers and thus there should be a separate logger for each thread that writes logs. The thread-safe counterparts can be accessed from different threads concurrently, but this will involve locking and may slow things down in case of intense logging. The thread-safe logger types have the `_mt` suffix in their name. +Unlike sinks, sources need not be registered anywhere since they interact directly with the logging core. Also note that there are two versions of loggers provided by the library: the thread-safe ones and the non-thread-safe ones. For the non-thread-safe loggers it is safe for different threads to write logs through different instances of loggers and thus there should be a separate logger for each thread that writes logs. The thread-safe counterparts can be accessed from different threads concurrently, but this will involve locking and may slow things down in case of intense contention. The thread-safe logger types have the `_mt` suffix in their name. Regardless of the thread safety, all loggers provided by the library are default and copy-constructible and support swapping, so there should be no problem in making a logger a member of your class. As you will see later, such approach can give you additional benefits. @@ -133,7 +133,7 @@ Later on you can acquire the logger like this: src::logger_mt& lg = my_logger::get(); -The `lg` will refer to the one and only instance of the logger throughout the application, even if the application consists of multiple modules. The `get` function itself is thread-safe, so there is no need in additional synchronization around it. +Then, `lg` will refer to the one and only instance of the logger throughout the application, even if the application consists of multiple modules. The `get` function itself is thread-safe, so there is no need in additional synchronization around it. [heading Writing logs] @@ -147,7 +147,7 @@ Of course, the above syntax can easily be wrapped in a macro and, in fact, users BOOST_LOG(lg) << "Hello, World!"; -Looks a bit shorter, doesn't it? The `BOOST_LOG` macro, along with other similar ones, is defined by the library. It automatically provides an STL-like stream in order to format the message with ordinary insertion expressions. Having all that code written, compiled and executed you should be able to see the "Hello, World!" record in the "sample.log" file. You will find the full code of this section [@boost:/libs/log/example/doc/tutorial_logging.cpp here]. +Looks a bit shorter, doesn't it? The `BOOST_LOG` macro, along with other similar ones, is defined by the library. It automatically provides a standard library-like output stream in order to format the message with ordinary insertion expressions. Having all that code written, compiled and executed you should be able to see the "Hello, World!" record in the "sample.log" file. You will find the full code of this section [@boost:/libs/log/example/doc/tutorial_logging.cpp here]. [endsect] @@ -155,7 +155,7 @@ Looks a bit shorter, doesn't it? The `BOOST_LOG` macro, along with other similar In previous sections we mentioned attributes and attribute values several times. Here we will discover how attributes can be used to add more data to log records. -Each log record can have a number of named attribute values attached. Attributes can represent any essential information about the conditions in which the log record occurred, such as position in the code, executable module name, current date and time, or any piece of data relevant to your particular application and execution environment. An attribute may behave as a value generator, in which case it would return a different value for each log record it's involved in. As soon as the attribute generates the value, the latter becomes independent from the creator and can be used by filters, formatters and sinks. But in order to use the attribute value one has to know its name and type, or at least a set of types it may have. There are a number of commonly used attributes implemented in the library, you can find the types of their values in the documentation. +Each log record can have a number of named attribute values attached. Attributes can represent any essential information about the conditions in which the log record occurred, such as position in code, executable module name, current date and time, or any piece of data relevant to your particular application and execution environment. An attribute may behave as a value generator, in which case it would return a different value for each log record it's involved in. As soon as the attribute generates the value, the latter becomes independent from the creator and can be used by filters, formatters and sinks. But in order to use the attribute value one has to know its name and type, or at least a set of types it may have. There are a number of commonly used attributes implemented in the library, you can find the types of their values in the documentation. Aside from that, as described in the [link log.design Design overview] section, there are three possible scopes of attributes: source-specific, thread-specific and global. When a log record is made, attribute values from these three sets are joined into a single set and passed to sinks. This implies that the origin of the attribute makes no difference for sinks. Any attribute can be registered in any scope. When registered, an attribute is given a unique name in order to make it possible to search for it. If it happens that the same named attribute is found in several scopes, the attribute from the most specific scope is taken into consideration in any further processing, including filtering and formatting. Such behavior makes it possible to override global or thread-scoped attributes with the ones registered in your local logger, thus reducing thread interference. @@ -314,7 +314,7 @@ Here `CharT` is the target character type. The formatter will be invoked wheneve [tip Record views are very similar to records. The notable distinction is that the view is immutable and implements shallow copy. Formatters and sinks only operate on record views, which prevents them from modifying the record while it can be still in use by other sinks in other threads.] -The formatted record should be composed by insertion into STL-compatible output stream `strm`. Here's an example of a custom formatter function usage: +The formatted record should be composed by insertion into standard library-compatible output stream `strm`. Here's an example of a custom formatter function usage: [example_tutorial_formatters_custom] diff --git a/doc/utilities.qbk b/doc/utilities.qbk index 3f91880679..7f00d24610 100644 --- a/doc/utilities.qbk +++ b/doc/utilities.qbk @@ -17,7 +17,7 @@ String literals are used in several places throughout the library. However, this The functionality is implemented in the [class_log_basic_string_literal] class template, which is parametrized with the character and character traits, similar to `std::basic_string`. There are also two convenience typedefs provided: `string_literal` and `wstring_literal`, for narrow and wide character types, respectively. In order to ease string literal construction in generic code there is also a `str_literal` function template that accepts a string literal and returns a [class_log_basic_string_literal] instance for the appropriate character type. -String literals support interface similar to STL strings, except for string modification functions. However, it is possible to assign to or clear string literals, as long as only string literals involved. Relational and stream output operators are also supported. +String literals support interface similar to standard library string types, except for string modification functions. However, it is possible to assign to or clear string literals, as long as only string literals involved. Relational and stream output operators are also supported. [endsect] @@ -67,7 +67,7 @@ One may notice that when using type dispatchers and defining filters and formatt [[`integral_types`] [All integral types, including `bool`, character and 64 bit integral types, if available]] [[`floating_point_types`] [Floating point types]] [[`numeric_types`] [Includes `integral_types` and `floating_point_types`]] - [[`string_types`] [Narrow and wide string types. Currently only includes STL string types and [link log.detailed.utilities.string_literal string literals].]] + [[`string_types`] [Narrow and wide string types. Currently only includes C++ standard library string types and [link log.detailed.utilities.string_literal string literals].]] ] There are also a number of time-related type sequences available: From f8b3ad885065645e7f93b79ec2c55642505b076e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 29 Aug 2022 02:59:20 +0300 Subject: [PATCH 201/309] Fixed a typo. --- doc/rationale.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 4a764b820a..304bd94106 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -239,7 +239,7 @@ However, user's shared library may provide its own API that will implement simil Next, it is important to ensure that logging configuration is coordinated between all modules. For example, if a file log is needed, only one file sink must be added, regardless of how many libraries are using logging. The preferred way to achieve this is perform logging configuration only in the main application, for the following reasons: * Logging configuration should be performed early in the `main` function, which is implemented in the application. Using global constructors in libraries can be problematic due to undefined order of global initialization and the possibility of dynamic loading and unloading of the libraries. -* Libraries are normally "serving the needs" of the main application, and conceptually it is the application that must decide how the library exposes its diagnostic information such as logs. One application may want to output its logs to console, another one store it in a file, and a third one may want to completely suppress any logging. A well-behaved library should transparently support any such use case and Boost.Log allows to achieve exactly that. +* Libraries are normally "serving the needs" of the main application, and conceptually it is the application that must decide how the library exposes its diagnostic information such as logs. One application may want to output its logs to console, another one store it in a file, and a third one may want to completely suppress any logging. A well-behaving library should transparently support any such use case and Boost.Log allows to achieve exactly that. It should be noted that having logging configured by the application implies that the application is written in C++ and can use Boost.Log. If this is not the case, libraries should still allow for this design and offer an API for configuring logging on behalf of the application. Alternatively, a separate library written in C++ can be used for the sole purpose of configuring logging. This way logging set up decisions are still made by the application, indirectly through the library API. From 5782827b5554087e10b133abeeef937f57582fdf Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 10 Sep 2022 01:38:03 +0300 Subject: [PATCH 202/309] GitHub Actions config update. - Added gcc-12 and clang-13 through 15 jobs. - Added C++23 testing for gcc and clang on Linux. - Updated clang version for UBSAN job. - Updated Ubuntu version for clang jobs to avoid having to use external APT repository. - Updated python package installation for compatibility with Ubuntu 22.04. --- .github/workflows/ci.yml | 81 ++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 24 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 873da0774e..a4209452ba 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -105,22 +105,23 @@ jobs: install: - g++-10 - toolset: gcc-11 - cxxstd: "03,11,14,17,20" - os: ubuntu-20.04 + cxxstd: "03,11,14,17,20,23" + os: ubuntu-22.04 install: - g++-11 - sources: - - "ppa:ubuntu-toolchain-r/test" + - toolset: gcc-12 + cxxstd: "03,11,14,17,20,23" + os: ubuntu-22.04 + install: + - g++-12 - name: UBSAN toolset: gcc-11 - cxxstd: "03,11,14,17,20" + cxxstd: "03,11,14,17,20,23" ubsan: 1 build_variant: debug - os: ubuntu-20.04 + os: ubuntu-22.04 install: - g++-11 - sources: - - "ppa:ubuntu-toolchain-r/test" # Linux, clang - toolset: clang @@ -211,38 +212,64 @@ jobs: - toolset: clang compiler: clang++-11 cxxstd: "03,11,14,17,20" - os: ubuntu-20.04 + os: ubuntu-22.04 install: - clang-11 - toolset: clang compiler: clang++-12 - cxxstd: "03,11,14,17,20" - os: ubuntu-20.04 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 install: - clang-12 - toolset: clang - compiler: clang++-12 - cxxstd: "03,11,14,17,20" - os: ubuntu-20.04 + compiler: clang++-13 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 install: - - clang-12 - - libc++-12-dev - - libc++abi-12-dev + - clang-13 + - toolset: clang + compiler: clang++-14 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-14 + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-15 + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-15 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-15 + - libc++-15-dev + - libc++abi-15-dev + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" cxxflags: -stdlib=libc++ linkflags: -stdlib=libc++ - name: UBSAN toolset: clang - compiler: clang++-12 - cxxstd: "03,11,14,17,20" + compiler: clang++-14 + cxxstd: "03,11,14,17,20,2b" cxxflags: -stdlib=libc++ linkflags: -stdlib=libc++ ubsan: 1 build_variant: debug - os: ubuntu-20.04 + os: ubuntu-22.04 install: - - clang-12 - - libc++-12-dev - - libc++abi-12-dev + - clang-14 + - libc++-14-dev + - libc++abi-14-dev - toolset: clang cxxstd: "03,11,14,17,2a" @@ -270,7 +297,13 @@ jobs: if [ -f "/etc/debian_version" ] then apt-get -o Acquire::Retries=$NET_RETRY_COUNT update - apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ python python3 perl git cmake + if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] + then + PYTHON_PACKAGE="python-is-python3" + else + PYTHON_PACKAGE="python" + fi + apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common tzdata wget curl apt-transport-https ca-certificates make build-essential g++ $PYTHON_PACKAGE python3 perl git cmake fi fi git config --global pack.threads 0 From 3f22dbe131908e6d72c47c9d17b221ddae873bfc Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 18 Oct 2022 18:00:26 +0300 Subject: [PATCH 203/309] Updated to GHA checkout@v3 to avoid deprecation warnings. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4209452ba..191cfa964a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -308,7 +308,7 @@ jobs: fi git config --global pack.threads 0 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install packages if: matrix.install From 9be578442ea9060b894c02a045aab6526e7aec76 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 9 Dec 2022 04:48:09 +0300 Subject: [PATCH 204/309] Moved snprintf.hpp to Boost.Core. --- include/boost/log/detail/snprintf.hpp | 107 ------------------ .../expressions/formatters/c_decorator.hpp | 10 +- src/global_logger_storage.cpp | 33 ++++-- src/setup/default_formatter_factory.cpp | 10 +- src/syslog_backend.cpp | 8 +- src/windows/ipc_sync_wrappers.cpp | 16 ++- 6 files changed, 48 insertions(+), 136 deletions(-) delete mode 100644 include/boost/log/detail/snprintf.hpp diff --git a/include/boost/log/detail/snprintf.hpp b/include/boost/log/detail/snprintf.hpp deleted file mode 100644 index 14c6a6b1dc..0000000000 --- a/include/boost/log/detail/snprintf.hpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright Andrey Semashev 2007 - 2015. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - */ -/*! - * \file snprintf.hpp - * \author Andrey Semashev - * \date 20.02.2009 - * - * \brief This header is the Boost.Log library implementation, see the library documentation - * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. - */ - -#ifndef BOOST_LOG_DETAIL_SNPRINTF_HPP_INCLUDED_ -#define BOOST_LOG_DETAIL_SNPRINTF_HPP_INCLUDED_ - -#include -#include -#include -#include -#ifdef BOOST_LOG_USE_WCHAR_T -#include -#endif // BOOST_LOG_USE_WCHAR_T -#include - -#ifdef BOOST_HAS_PRAGMA_ONCE -#pragma once -#endif - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace aux { - -#if defined(_MSC_VER) || (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR)) - -// MSVC snprintfs are not conforming but they are good enough for our cases. -// MinGW32, at least the older versions up until gcc 4.7, also provide the non-conforming interface. -inline int vsnprintf(char* buf, std::size_t size, const char* format, std::va_list args) -{ - int n = _vsnprintf(buf, size, format, args); - if (static_cast< unsigned int >(n) >= size) - { - n = static_cast< int >(size); - buf[size - 1] = '\0'; - } - return n; -} - -# ifdef BOOST_LOG_USE_WCHAR_T -inline int vswprintf(wchar_t* buf, std::size_t size, const wchar_t* format, std::va_list args) -{ - int n = _vsnwprintf(buf, size, format, args); - if (static_cast< unsigned int >(n) >= size) - { - n = static_cast< int >(size); - buf[size - 1] = L'\0'; - } - return n; -} -# endif // BOOST_LOG_USE_WCHAR_T - -inline int snprintf(char* buf, std::size_t size, const char* format, ...) -{ - std::va_list args; - va_start(args, format); - int n = vsnprintf(buf, size, format, args); - va_end(args); - return n; -} - -# ifdef BOOST_LOG_USE_WCHAR_T -inline int swprintf(wchar_t* buf, std::size_t size, const wchar_t* format, ...) -{ - std::va_list args; - va_start(args, format); - int n = vswprintf(buf, size, format, args); - va_end(args); - return n; -} -# endif // BOOST_LOG_USE_WCHAR_T - -#else - -// Standard-conforming compilers already have the correct snprintfs -using ::snprintf; -using ::vsnprintf; - -# ifdef BOOST_LOG_USE_WCHAR_T -using ::swprintf; -using ::vswprintf; -# endif // BOOST_LOG_USE_WCHAR_T - -#endif - -} // namespace aux - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#include - -#endif // BOOST_LOG_DETAIL_SNPRINTF_HPP_INCLUDED_ diff --git a/include/boost/log/expressions/formatters/c_decorator.hpp b/include/boost/log/expressions/formatters/c_decorator.hpp index fe96fb20b6..f786b24350 100644 --- a/include/boost/log/expressions/formatters/c_decorator.hpp +++ b/include/boost/log/expressions/formatters/c_decorator.hpp @@ -16,9 +16,9 @@ #define BOOST_LOG_EXPRESSIONS_FORMATTERS_C_DECORATOR_HPP_INCLUDED_ #include +#include #include #include -#include #include #include @@ -60,8 +60,8 @@ struct c_decorator_traits< char > template< unsigned int N > static std::size_t print_escaped(char (&buf)[N], char c) { - int n = boost::log::aux::snprintf(buf, N, "\\x%.2X", static_cast< unsigned int >(static_cast< uint8_t >(c))); - if (n < 0) + int n = boost::core::snprintf(buf, N, "\\x%.2X", static_cast< unsigned int >(static_cast< uint8_t >(c))); + if (BOOST_UNLIKELY(n < 0)) { n = 0; buf[0] = '\0'; @@ -112,8 +112,8 @@ struct c_decorator_traits< wchar_t > val = static_cast< uint32_t >(c); } - int n = boost::log::aux::swprintf(buf, N, format, val); - if (n < 0) + int n = boost::core::swprintf(buf, N, format, val); + if (BOOST_UNLIKELY(n < 0)) { n = 0; buf[0] = L'\0'; diff --git a/src/global_logger_storage.cpp b/src/global_logger_storage.cpp index 6ddcc1b7ce..6662f19f34 100644 --- a/src/global_logger_storage.cpp +++ b/src/global_logger_storage.cpp @@ -18,8 +18,8 @@ #include #include #include +#include #include -#include #include #include #if !defined(BOOST_LOG_NO_THREADS) @@ -83,18 +83,27 @@ BOOST_LOG_API BOOST_LOG_NORETURN void throw_odr_violation( typeindex::type_index logger_type, logger_holder_base const& registered) { + std::string str("Could not initialize global logger with tag \""); + str.append(tag_type.pretty_name()); + str.append("\" and type \""); + str.append(logger_type.pretty_name()); + str.append("\". A logger of type \""); + str.append(registered.m_LoggerType.pretty_name()); + str.append("\" with the same tag has already been registered at "); + str.append(registered.m_RegistrationFile); + char buf[std::numeric_limits< unsigned int >::digits10 + 3]; - if (log::aux::snprintf(buf, sizeof(buf), "%u", registered.m_RegistrationLine) < 0) - buf[0] = '\0'; - std::string str = - std::string("Could not initialize global logger with tag \"") + - tag_type.pretty_name() + - "\" and type \"" + - logger_type.pretty_name() + - "\". A logger of type \"" + - registered.m_LoggerType.pretty_name() + - "\" with the same tag has already been registered at " + - registered.m_RegistrationFile + ":" + buf + "."; + int res = boost::core::snprintf(buf, sizeof(buf), "%u", registered.m_RegistrationLine); + if (BOOST_LIKELY(res > 0)) + { + if (BOOST_UNLIKELY(static_cast< unsigned int >(res) >= sizeof(buf))) + res = sizeof(buf) - 1u; + + str.push_back(':'); + str.append(buf, res); + } + + str.push_back('.'); BOOST_LOG_THROW_DESCR(odr_violation, str); } diff --git a/src/setup/default_formatter_factory.cpp b/src/setup/default_formatter_factory.cpp index 15a0b8384f..5aec94416e 100644 --- a/src/setup/default_formatter_factory.cpp +++ b/src/setup/default_formatter_factory.cpp @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #if !defined(BOOST_LOG_NO_THREADS) #include @@ -112,8 +112,8 @@ class default_formatter char buf[32]; std::size_t len = std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &t); std::size_t size = sizeof(buf) - len; - int res = boost::log::aux::snprintf(buf + len, size, ".%.6u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000)); - if (res < 0) + int res = boost::core::snprintf(buf + len, size, ".%.6u", static_cast< unsigned int >(value.time_of_day().total_microseconds() % 1000000)); + if (BOOST_UNLIKELY(res < 0)) buf[len] = '\0'; else if (static_cast< std::size_t >(res) >= size) len += size - 1; @@ -172,8 +172,8 @@ class default_formatter unsigned int seconds = static_cast< unsigned int >(total_useconds / 1000000ull % 60ull); unsigned int useconds = static_cast< unsigned int >(total_useconds % 1000000ull); char buf[64]; - int len = boost::log::aux::snprintf(buf, sizeof(buf), "%.2llu:%.2u:%.2u.%.6u", hours, minutes, seconds, useconds); - if (len > 0) + int len = boost::core::snprintf(buf, sizeof(buf), "%.2llu:%.2u:%.2u.%.6u", hours, minutes, seconds, useconds); + if (BOOST_LIKELY(len > 0)) { unsigned int size = static_cast< unsigned int >(len) >= sizeof(buf) ? static_cast< unsigned int >(sizeof(buf)) : static_cast< unsigned int >(len); m_strm.write(buf, size); diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 7331c7d293..e505893053 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -40,7 +41,6 @@ #include #include #include -#include #include #if !defined(BOOST_LOG_NO_THREADS) #include @@ -392,7 +392,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { // The packet size is mandated in RFC3164, plus one for the terminating zero char packet[1025]; - int n = boost::log::aux::snprintf + int n = boost::core::snprintf ( packet, sizeof(packet), @@ -535,7 +535,7 @@ BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, un if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; - boost::log::aux::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); + boost::core::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); asio::ip::udp::endpoint local_address; { @@ -581,7 +581,7 @@ BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, u if (udp_socket_based_impl* impl = dynamic_cast< udp_socket_based_impl* >(m_pImpl)) { char service_name[std::numeric_limits< unsigned int >::digits10 + 3]; - boost::log::aux::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); + boost::core::snprintf(service_name, sizeof(service_name), "%u", static_cast< unsigned int >(port)); asio::ip::udp::endpoint remote_address; { diff --git a/src/windows/ipc_sync_wrappers.cpp b/src/windows/ipc_sync_wrappers.cpp index 12d743aa60..77ec34b8fa 100644 --- a/src/windows/ipc_sync_wrappers.cpp +++ b/src/windows/ipc_sync_wrappers.cpp @@ -32,8 +32,8 @@ #include #include #include +#include #include -#include #include "unique_ptr.hpp" #include "windows/ipc_sync_wrappers.hpp" #include @@ -217,8 +217,18 @@ bool interprocess_semaphore::is_semaphore_zero_count_nt_query_semaphore(boost::w if (BOOST_UNLIKELY(err != 0u)) { char buf[sizeof(unsigned int) * 2u + 4u]; - boost::log::aux::snprintf(buf, sizeof(buf), "0x%08x", static_cast< unsigned int >(err)); - BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, std::string("Failed to test an interprocess semaphore object for zero count, NT status: ") + buf, (ERROR_INVALID_HANDLE)); + int res = boost::core::snprintf(buf, sizeof(buf), "0x%08x", static_cast< unsigned int >(err)); + if (BOOST_UNLIKELY(res < 0)) + { + buf[0] = '?'; + buf[1] = '\0'; + res = 1; + } + else if (BOOST_UNLIKELY(static_cast< unsigned int >(res) >= sizeof(buf))) + { + res = sizeof(buf) - 1u; + } + BOOST_LOG_THROW_DESCR_PARAMS(boost::log::system_error, std::string("Failed to test an interprocess semaphore object for zero count, NT status: ").append(buf, res), (ERROR_INVALID_HANDLE)); } return info.current_count == 0u; From f5fbec2deb3993bcde2d536fed47cf2d72a57a2f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 22 Dec 2022 14:54:45 +0300 Subject: [PATCH 205/309] Removed superfluous value_ref copy constructor. The implicitly generated copy constructor is fine. Fixes https://github.com/boostorg/log/issues/201. --- include/boost/log/utility/value_ref.hpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/include/boost/log/utility/value_ref.hpp b/include/boost/log/utility/value_ref.hpp index 1f9a360785..07096e14c1 100644 --- a/include/boost/log/utility/value_ref.hpp +++ b/include/boost/log/utility/value_ref.hpp @@ -449,11 +449,6 @@ class value_ref : */ BOOST_DEFAULTED_FUNCTION(value_ref(), BOOST_NOEXCEPT {}) - /*! - * Copy constructor. - */ - BOOST_DEFAULTED_FUNCTION(value_ref(value_ref const& that), BOOST_NOEXCEPT : base_type(static_cast< base_type const& >(that)) {}) - /*! * Initializing constructor. Creates a reference wrapper that refers to the specified value. */ @@ -461,7 +456,7 @@ class value_ref : explicit value_ref(U const& val #ifndef BOOST_LOG_DOXYGEN_PASS // MSVC-8 can't handle SFINAE in this case properly and often wrongly disables this constructor -#if !defined(_MSC_VER) || (_MSC_VER + 0) >= 1500 +#if !defined(BOOST_MSVC) || BOOST_MSVC >= 1500 , typename boost::enable_if_c< compatibility_traits::BOOST_NESTED_TEMPLATE is_compatible< value_type, U >::value, boost::log::aux::sfinae_dummy >::type = boost::log::aux::sfinae_dummy() #endif #endif From 5e2d93d22965045d7af3b4da5c7b6ca87883f27f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 22 Dec 2022 15:00:04 +0300 Subject: [PATCH 206/309] Marked value_ref default constructor as constexpr. --- include/boost/log/utility/value_ref.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/boost/log/utility/value_ref.hpp b/include/boost/log/utility/value_ref.hpp index 07096e14c1..855ca7364e 100644 --- a/include/boost/log/utility/value_ref.hpp +++ b/include/boost/log/utility/value_ref.hpp @@ -112,7 +112,7 @@ class singular_ref protected: //! Default constructor - singular_ref() BOOST_NOEXCEPT : m_ptr(NULL) + BOOST_CONSTEXPR singular_ref() BOOST_NOEXCEPT : m_ptr(NULL) { } @@ -270,7 +270,7 @@ class variant_ref protected: //! Default constructor - variant_ref() BOOST_NOEXCEPT : m_ptr(NULL), m_type_idx(0) + BOOST_CONSTEXPR variant_ref() BOOST_NOEXCEPT : m_ptr(NULL), m_type_idx(0u) { } @@ -447,7 +447,7 @@ class value_ref : /*! * Default constructor. Creates a reference wrapper that does not refer to a value. */ - BOOST_DEFAULTED_FUNCTION(value_ref(), BOOST_NOEXCEPT {}) + BOOST_DEFAULTED_FUNCTION(BOOST_CONSTEXPR value_ref(), BOOST_NOEXCEPT {}) /*! * Initializing constructor. Creates a reference wrapper that refers to the specified value. From 1019905128247071dbc2e73e4a2209d2d0c7283f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 27 Feb 2023 20:00:01 +0300 Subject: [PATCH 207/309] Removed inclusion of Boost.Predef and Boost.Preprocessor in config.hpp. Those includes could be avoided relatively easily, so drop those to reduce code footprint. --- include/boost/log/detail/config.hpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index c7a37ac346..7835a5b4b0 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -17,10 +17,8 @@ #ifndef BOOST_LOG_DETAIL_CONFIG_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_CONFIG_HPP_INCLUDED_ -#include - // Try including WinAPI config as soon as possible so that any other headers don't include Windows SDK headers -#if defined(BOOST_OS_WINDOWS_AVAILABLE) +#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(__TOS_WIN__) || defined(__WINDOWS__) #include #endif @@ -36,10 +34,6 @@ # define BOOST_LOG_HAS_PRAGMA_DETECT_MISMATCH #endif -#if defined(BOOST_LOG_HAS_PRAGMA_DETECT_MISMATCH) -#include -#endif - #if !defined(BOOST_WINDOWS) # ifndef BOOST_LOG_WITHOUT_DEBUG_OUTPUT # define BOOST_LOG_WITHOUT_DEBUG_OUTPUT @@ -414,7 +408,7 @@ namespace log {} #endif // !defined(BOOST_LOG_DOXYGEN_PASS) #if defined(BOOST_LOG_HAS_PRAGMA_DETECT_MISMATCH) -#pragma detect_mismatch("boost_log_abi", BOOST_PP_STRINGIZE(BOOST_LOG_VERSION_NAMESPACE)) +#pragma detect_mismatch("boost_log_abi", BOOST_STRINGIZE(BOOST_LOG_VERSION_NAMESPACE)) #endif } // namespace boost From 56674b03caefefc54677eab1f522222ecdd39d99 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 28 Feb 2023 05:14:45 +0300 Subject: [PATCH 208/309] Added -lubsan linker flag to work around linking errors with clang UBSAN. Works around https://github.com/llvm/llvm-project/issues/60578. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 191cfa964a..8b9de543e9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -262,7 +262,7 @@ jobs: compiler: clang++-14 cxxstd: "03,11,14,17,20,2b" cxxflags: -stdlib=libc++ - linkflags: -stdlib=libc++ + linkflags: "-stdlib=libc++ -lubsan" ubsan: 1 build_variant: debug os: ubuntu-22.04 From 051f69658971fab5ceccd6bd24b057dd24a2d9c4 Mon Sep 17 00:00:00 2001 From: maximd-g <53081079+maximd-g@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:34:36 +0400 Subject: [PATCH 209/309] Fix a typo in scoped_feeding_operation --- include/boost/log/sinks/async_frontend.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index a329ce7a24..3d20718978 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -167,24 +167,24 @@ class asynchronous_sink : }; //! A scope guard that implements active operation management - class scoped_feeding_opereation + class scoped_feeding_operation { private: asynchronous_sink& m_self; public: //! Initializing constructor - explicit scoped_feeding_opereation(asynchronous_sink& self) : m_self(self) + explicit scoped_feeding_operation(asynchronous_sink& self) : m_self(self) { } //! Destructor - ~scoped_feeding_opereation() + ~scoped_feeding_operation() { m_self.complete_feeding_operation(); } - BOOST_DELETED_FUNCTION(scoped_feeding_opereation(scoped_feeding_opereation const&)) - BOOST_DELETED_FUNCTION(scoped_feeding_opereation& operator= (scoped_feeding_opereation const&)) + BOOST_DELETED_FUNCTION(scoped_feeding_operation(scoped_feeding_operation const&)) + BOOST_DELETED_FUNCTION(scoped_feeding_operation& operator= (scoped_feeding_operation const&)) }; //! A scope guard that resets a flag on destructor @@ -384,7 +384,7 @@ class asynchronous_sink : return; } - scoped_feeding_opereation guard(*this); + scoped_feeding_operation guard(*this); // Now start the feeding loop while (true) @@ -455,7 +455,7 @@ class asynchronous_sink : return; } - scoped_feeding_opereation guard(*this); + scoped_feeding_operation guard(*this); // Now start the feeding loop do_feed_records(); @@ -488,7 +488,7 @@ class asynchronous_sink : m_FlushRequested.store(true, boost::memory_order_relaxed); } - scoped_feeding_opereation guard(*this); + scoped_feeding_operation guard(*this); do_feed_records(); } From f6808349bfd91f39ec18cc8ef25d1e1a3104d149 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 29 Mar 2023 02:14:28 +0300 Subject: [PATCH 210/309] Added a note about C++03 deprecation. --- doc/changelog.qbk | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index a73f959ef8..89d28f8852 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2022. + Copyright Andrey Semashev 2007 - 2023. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.26, Boost 1.82] + +* Due to changes in Boost libraries used by Boost.Log, support for C++03 is deprecated. C++11 will become the minimum starting with Boost.Log 1.84. + [heading 2.25, Boost 1.80] [*Bug fixes:] From b5c42771403a272800bd423a763366bbe70054c1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 10 May 2023 19:55:32 +0300 Subject: [PATCH 211/309] Don't rotate the empty log file if the message size exceeds rotation_size. In text_file_backend, we try to avoid exceeding the rotation_size limit when we open a new file, potentially in append mode. To do so, we check the combined size of the opened file and the formatted log record to write against this limit. It was possible that the log record alone exceeds the limit, which makes this check always fail and cause an infinite loop of rotating files. To avoid this, don't perform the check if the file size is 0, which is the case when a new file is created. In this case, we will write the log record (thus exceeding the rotation_size limit) and then rotate the file upon the next log record we write. Closes https://github.com/boostorg/log/issues/209. --- doc/changelog.qbk | 4 ++++ src/text_file_backend.cpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 89d28f8852..ca06e92c2e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.27, Boost 1.83] + +* Fixed a possible infinite loop in [link log.detailed.sink_backends.text_file `text_file_backend`], when the size of a formatted log record exceeds the `rotation_size` limit. ([github_issue 209]) + [heading 2.26, Boost 1.82] * Due to changes in Boost libraries used by Boost.Log, support for C++03 is deprecated. C++11 will become the minimum starting with Boost.Log 1.84. diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 8b8920e866..312cc38e66 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1481,7 +1481,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ // Check the file size before invoking the open handler, as it may write more data to the file m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); - if (m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize) + if (m_pImpl->m_CharactersWritten > 0 && m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize) { // Avoid running the close handler, as we haven't run the open handler yet struct close_handler_backup_guard From 407260f24f136d8948b1ae1726fb57499672c805 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 10 May 2023 20:18:26 +0300 Subject: [PATCH 212/309] Check for file counter when rotating the newly opened log file. This ensures that the file opening loop will eventually exit, even if there are 2^32 log files in the filesystem and none of them allow to fit the new log record. --- src/text_file_backend.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 312cc38e66..0df9a3722d 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1422,6 +1422,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ rotate_file(); } + const unsigned int last_file_counter = m_pImpl->m_FileCounter - 1u; while (!m_pImpl->m_File.is_open()) { filesystem::path new_file_name; @@ -1464,6 +1465,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ else { prev_file_name.swap(new_file_name); + use_prev_file_name = false; } filesystem::create_directories(new_file_name.parent_path()); @@ -1479,9 +1481,11 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ m_pImpl->m_FileName.swap(new_file_name); m_pImpl->m_IsFirstFile = false; - // Check the file size before invoking the open handler, as it may write more data to the file + // Check the file size before invoking the open handler, as it may write more data to the file. + // Only do this check if we haven't exhausted the file counter to avoid looping indefinitely. m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); - if (m_pImpl->m_CharactersWritten > 0 && m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize) + if (m_pImpl->m_CharactersWritten > 0 && m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize && + m_pImpl->m_FileCounter != last_file_counter) { // Avoid running the close handler, as we haven't run the open handler yet struct close_handler_backup_guard From 28c6b1da87caec38919bd2d26385676ed15b4ac6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 5 Jun 2023 03:20:06 +0300 Subject: [PATCH 213/309] Add clang-16 CI jobs, switch to clang-15 from stock Ubuntu repos. --- .github/workflows/ci.yml | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8b9de543e9..564720ad67 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -239,27 +239,33 @@ jobs: os: ubuntu-22.04 install: - clang-15 + - toolset: clang + compiler: clang++-16 + cxxstd: "03,11,14,17,20,2b" + os: ubuntu-22.04 + install: + - clang-16 sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang - compiler: clang++-15 + compiler: clang++-16 cxxstd: "03,11,14,17,20,2b" os: ubuntu-22.04 install: - - clang-15 - - libc++-15-dev - - libc++abi-15-dev + - clang-16 + - libc++-16-dev + - libc++abi-16-dev sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main" + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" cxxflags: -stdlib=libc++ linkflags: -stdlib=libc++ - name: UBSAN toolset: clang - compiler: clang++-14 + compiler: clang++-15 cxxstd: "03,11,14,17,20,2b" cxxflags: -stdlib=libc++ linkflags: "-stdlib=libc++ -lubsan" @@ -267,9 +273,9 @@ jobs: build_variant: debug os: ubuntu-22.04 install: - - clang-14 - - libc++-14-dev - - libc++abi-14-dev + - clang-15 + - libc++-15-dev + - libc++abi-15-dev - toolset: clang cxxstd: "03,11,14,17,2a" From 756a3d0b3d57a1ceb063c7bd36a12d39c1da8a5e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 13 Jun 2023 13:31:25 +0300 Subject: [PATCH 214/309] Switch MSVC-14.3 AppVeyor CI build to Windows 10. This allows to test compilation when using the latest Windows APIs. In particular, this allows to test that linking works when Boost.Atomic uses WaitOnAddress API. --- appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 14015be8e4..f713735bd5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# Copyright 2019 - 2022 Andrey Semashev +# Copyright 2019 - 2023 Andrey Semashev # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -43,6 +43,7 @@ environment: ADDRESS_MODEL: 64 CXXSTD: 14,17,20 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022 + B2_ARGS: define=_WIN32_WINNT=0x0A00 - TOOLSET: gcc ADDRESS_MODEL: 64 CXXSTD: 03,11 From b3ffed4ec2cdb376e9355a17d5e89ec2f3bc893a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 19 Oct 2021 00:13:29 +0300 Subject: [PATCH 215/309] Disable building boost_log_setup when settings parsers are disabled. Check the BOOST_LOG_WITHOUT_SETTINGS_PARSERS macro in the Jamfile and suppress building boost_log_setup if it is defined. The built library is empty in this case, and MSVC linker even produces no library, which later breaks installation. Fixes https://github.com/boostorg/log/issues/164. Closes https://github.com/boostorg/log/pull/165. Blocked by https://github.com/bfgroup/b2/issues/104. --- build/Jamfile.v2 | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index a81fb8b274..46dd045965 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -418,10 +418,23 @@ local BOOST_LOG_SETUP_COMMON_SRC = default_formatter_factory.cpp ; +rule check-boost_log_setup-enabled ( properties * ) +{ + local result ; + + if [ has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] + { + result = no ; + } + + return $(result) ; +} + lib boost_log_setup : ## sources ## setup/$(BOOST_LOG_SETUP_COMMON_SRC) : ## requirements ## + @check-boost_log_setup-enabled shared:BOOST_LOG_DYN_LINK=1 shared:BOOST_LOG_SETUP_DLL BOOST_LOG_SETUP_BUILDING_THE_LIB=1 From ee82d5ba10bb52ad6bd2ef45d564d98b6eefcc21 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 13 Aug 2023 15:50:50 +0300 Subject: [PATCH 216/309] Removed C++03 compilers from the CI. Dependency libraries no longer support C++03, so we are removing support for C++03 from Boost.Log. For now, drop C++03 from CI configs. --- .github/workflows/ci.yml | 76 ++++++++++++++++++---------------------- appveyor.yml | 37 ++++--------------- 2 files changed, 40 insertions(+), 73 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 564720ad67..2b97f22579 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,16 +35,8 @@ jobs: matrix: include: # Linux, gcc - - toolset: gcc-4.4 - cxxstd: "98,0x" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - g++-4.4 - sources: - - "ppa:ubuntu-toolchain-r/test" - toolset: gcc-4.6 - cxxstd: "03,0x" + cxxstd: "0x" os: ubuntu-latest container: ubuntu:16.04 install: @@ -52,71 +44,71 @@ jobs: sources: - "ppa:ubuntu-toolchain-r/test" - toolset: gcc-4.7 - cxxstd: "03,11" + cxxstd: "11" os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.7 - toolset: gcc-4.8 - cxxstd: "03,11" + cxxstd: "11" os: ubuntu-latest container: ubuntu:18.04 install: - g++-4.8 - toolset: gcc-4.9 - cxxstd: "03,11" + cxxstd: "11" os: ubuntu-latest container: ubuntu:16.04 install: - g++-4.9 extra_tests: 1 - toolset: gcc-5 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:16.04 install: - g++-5 - toolset: gcc-6 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:18.04 install: - g++-6 - toolset: gcc-7 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-latest container: ubuntu:18.04 install: - g++-7 - toolset: gcc-8 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-latest container: ubuntu:18.04 install: - g++-8 - toolset: gcc-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: - g++-9 - toolset: gcc-10 - cxxstd: "03,11,14,17,20" + cxxstd: "11,14,17,20" os: ubuntu-20.04 install: - g++-10 - toolset: gcc-11 - cxxstd: "03,11,14,17,20,23" + cxxstd: "11,14,17,20,23" os: ubuntu-22.04 install: - g++-11 - toolset: gcc-12 - cxxstd: "03,11,14,17,20,23" + cxxstd: "11,14,17,20,23" os: ubuntu-22.04 install: - g++-12 - name: UBSAN toolset: gcc-11 - cxxstd: "03,11,14,17,20,23" + cxxstd: "11,14,17,20,23" ubsan: 1 build_variant: debug os: ubuntu-22.04 @@ -126,63 +118,63 @@ jobs: # Linux, clang - toolset: clang compiler: clang++-3.5 - cxxstd: "03,11" + cxxstd: "11" os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.5 - toolset: clang compiler: clang++-3.6 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.6 - toolset: clang compiler: clang++-3.7 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.7 - toolset: clang compiler: clang++-3.8 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:16.04 install: - clang-3.8 - toolset: clang compiler: clang++-3.9 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:18.04 install: - clang-3.9 - toolset: clang compiler: clang++-4.0 - cxxstd: "03,11,14" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:18.04 install: - clang-4.0 - toolset: clang compiler: clang++-5.0 - cxxstd: "03,11,14,1z" + cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:18.04 install: - clang-5.0 - toolset: clang compiler: clang++-6.0 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-latest container: ubuntu:18.04 install: - clang-6.0 - toolset: clang compiler: clang++-7 - cxxstd: "03,11,14,17" + cxxstd: "11,14,17" os: ubuntu-latest container: ubuntu:18.04 install: @@ -190,7 +182,7 @@ jobs: # Note: clang-8 does not fully support C++20, so it is not compatible with libstdc++-8 in this mode - toolset: clang compiler: clang++-8 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-latest container: ubuntu:18.04 install: @@ -199,49 +191,49 @@ jobs: gcc_toolchain: 7 - toolset: clang compiler: clang++-9 - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: ubuntu-20.04 install: - clang-9 - toolset: clang compiler: clang++-10 - cxxstd: "03,11,14,17,20" + cxxstd: "11,14,17,20" os: ubuntu-20.04 install: - clang-10 - toolset: clang compiler: clang++-11 - cxxstd: "03,11,14,17,20" + cxxstd: "11,14,17,20" os: ubuntu-22.04 install: - clang-11 - toolset: clang compiler: clang++-12 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-12 - toolset: clang compiler: clang++-13 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-13 - toolset: clang compiler: clang++-14 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-14 - toolset: clang compiler: clang++-15 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-15 - toolset: clang compiler: clang++-16 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-16 @@ -251,7 +243,7 @@ jobs: - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang compiler: clang++-16 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-16 @@ -266,7 +258,7 @@ jobs: - name: UBSAN toolset: clang compiler: clang++-15 - cxxstd: "03,11,14,17,20,2b" + cxxstd: "11,14,17,20,2b" cxxflags: -stdlib=libc++ linkflags: "-stdlib=libc++ -lubsan" ubsan: 1 @@ -278,7 +270,7 @@ jobs: - libc++abi-15-dev - toolset: clang - cxxstd: "03,11,14,17,2a" + cxxstd: "11,14,17,2a" os: macos-11 - name: CMake tests diff --git a/appveyor.yml b/appveyor.yml index f713735bd5..18a79c9834 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,19 +14,6 @@ branches: environment: matrix: -# AppVeyor doesn't provide 64-bit compilers for these MSVC versions -# - TOOLSET: msvc-9.0 -# ADDRESS_MODEL: 64 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -# - TOOLSET: msvc-10.0 -# ADDRESS_MODEL: 64 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 -# - TOOLSET: msvc-11.0 -# ADDRESS_MODEL: 64 -# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - TOOLSET: msvc-12.0 - ADDRESS_MODEL: 64 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.0 ADDRESS_MODEL: 64 EXTRA_TESTS: 1 @@ -46,19 +33,19 @@ environment: B2_ARGS: define=_WIN32_WINNT=0x0A00 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11 + CXXSTD: 11 ADDPATH: C:\cygwin64\bin EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11,14 + CXXSTD: 11,14 ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 03,11,14,17 + CXXSTD: 11,14,17 ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: clang-win @@ -67,18 +54,6 @@ environment: ENV_SCRIPT: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - - TOOLSET: msvc-9.0 - ADDRESS_MODEL: 32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - TOOLSET: msvc-10.0 - ADDRESS_MODEL: 32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - TOOLSET: msvc-11.0 - ADDRESS_MODEL: 32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - TOOLSET: msvc-12.0 - ADDRESS_MODEL: 32 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: msvc-14.0 ADDRESS_MODEL: 32 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 @@ -92,17 +67,17 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11 + CXXSTD: 11 ADDPATH: C:\cygwin\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11 + CXXSTD: 11 ADDPATH: C:\mingw\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 32 - CXXSTD: 03,11,14 + CXXSTD: 11,14 ADDPATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: clang-win From e175d010e6cc104da8f6f73d42bf7599553442c0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 13 Aug 2023 15:53:19 +0300 Subject: [PATCH 217/309] Updated docs to note that C++11 is now required. --- doc/changelog.qbk | 4 ++++ doc/log.qbk | 15 ++++++++------- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index ca06e92c2e..e46cc2bfb4 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.28, Boost 1.84] + +* C++03 is no longer supported. A C++11 or later compiler is required. + [heading 2.27, Boost 1.83] * Fixed a possible infinite loop in [link log.detailed.sink_backends.text_file `text_file_backend`], when the size of a formatted log record exceeds the `rotation_size` limit. ([github_issue 209]) diff --git a/doc/log.qbk b/doc/log.qbk index cd68a81641..ae2bef3b7e 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -163,18 +163,19 @@ To keep the code snippets in this documentation simple, the following namespace [section:supported_compilers Supported compilers and platforms] -The library should build and work with a reasonably compliant compiler. The library was successfully built and tested on the following platforms: +The library should build and work with a reasonably compliant C++11 compiler. The library was successfully built and tested on the following platforms: -* Windows XP, Windows Vista, Windows 7. MSVC 8.0 SP1, MSVC 9.0 and newer. -* Linux. GCC 4.5 and newer. Older versions may work too, but it was not tested. -* Linux. Intel C++ 13.1.0.146 Build 20130121. -* Linux. Clang 3.2 and newer. +* Windows 10. MSVC 14.0 and newer. MinGW32 with gcc 5.x and MinGW-w64 with gcc 6.x and newer. +* Cygwin and Cygwin64 with gcc 7.x and newer. +* Linux. GCC 4.6 and newer. +* Linux. Clang 3.5 and newer. The following compilers/platforms are not supported and will likely fail to compile the library: +* Compilers that do not support C++11. * C++11 compilers with non-C++11 standard libraries (like Clang with libstdc++ from GCC 4.2). Please, use a C++11 standard library in C++11 mode. -* MSVC 8.0 (without SP1) and older. -* GCC 4.2 and older. +* MSVC 12.0 and older. +* GCC 4.4 and older. * Borland C++ 5.5.1 (free version). Newer versions might or might not work. * Solaris Studio 12.3 and older. * Windows 9x, ME, NT4, 2000 and older are not supported. From 7ddeff52f1825106f0f194c42f3621d14ebbf1ad Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 25 Aug 2023 14:48:46 +0300 Subject: [PATCH 218/309] Removed dependency on Boost.LexicalCast. --- CMakeLists.txt | 2 -- example/doc/extension_filter_parser.cpp | 17 +++++++++++++--- .../extension_filter_parser_custom_rel.cpp | 20 +++++++++++++++---- .../doc/extension_stat_collector_settings.cpp | 3 +-- .../boost/log/utility/setup/filter_parser.hpp | 9 +++++++-- src/process_name.cpp | 8 ++++---- 6 files changed, 42 insertions(+), 17 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 592281c92e..2ce9546974 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -485,7 +485,6 @@ target_link_libraries(boost_log Boost::bind Boost::exception Boost::interprocess - Boost::lexical_cast Boost::optional Boost::random Boost::spirit @@ -544,7 +543,6 @@ set(boost_log_setup_public_deps Boost::config Boost::core Boost::iterator - Boost::lexical_cast Boost::move Boost::optional Boost::parameter diff --git a/example/doc/extension_filter_parser.cpp b/example/doc/extension_filter_parser.cpp index 016f400830..1b9721fa3c 100644 --- a/example/doc/extension_filter_parser.cpp +++ b/example/doc/extension_filter_parser.cpp @@ -6,11 +6,11 @@ */ #include +#include #include #include #include #include -#include #include #include #include @@ -110,12 +110,23 @@ class point_filter_factory : logging::filter on_equality_relation(logging::attribute_name const& name, string_type const& arg) { - return expr::attr< point >(name) == boost::lexical_cast< point >(arg); + return expr::attr< point >(name) == parse_argument(arg); } logging::filter on_inequality_relation(logging::attribute_name const& name, string_type const& arg) { - return expr::attr< point >(name) != boost::lexical_cast< point >(arg); + return expr::attr< point >(name) != parse_argument(arg); + } + +private: + static point parse_argument(string_type const& arg) + { + std::istringstream strm(arg); + point val; + strm >> val; + if (strm.fail() || strm.bad()) + throw std::runtime_error("Failed to parse point from \"" + arg + "\""); + return val; } }; diff --git a/example/doc/extension_filter_parser_custom_rel.cpp b/example/doc/extension_filter_parser_custom_rel.cpp index 0498a0059f..7390b9c65e 100644 --- a/example/doc/extension_filter_parser_custom_rel.cpp +++ b/example/doc/extension_filter_parser_custom_rel.cpp @@ -6,11 +6,11 @@ */ #include +#include #include #include #include #include -#include #include #include #include @@ -142,22 +142,34 @@ class point_filter_factory : logging::filter on_equality_relation(logging::attribute_name const& name, string_type const& arg) { - return expr::attr< point >(name) == boost::lexical_cast< point >(arg); + return expr::attr< point >(name) == parse_argument< point >(arg); } logging::filter on_inequality_relation(logging::attribute_name const& name, string_type const& arg) { - return expr::attr< point >(name) != boost::lexical_cast< point >(arg); + return expr::attr< point >(name) != parse_argument< point >(arg); } logging::filter on_custom_relation(logging::attribute_name const& name, string_type const& rel, string_type const& arg) { if (rel == "is_in_rectangle") { - return boost::phoenix::bind(&is_in_rectangle, expr::attr< point >(name), boost::lexical_cast< rectangle >(arg)); + return boost::phoenix::bind(&is_in_rectangle, expr::attr< point >(name), parse_argument< rectangle >(arg)); } throw std::runtime_error("Unsupported filter relation: " + rel); } + +private: + template< typename ArgumentT > + static ArgumentT parse_argument(string_type const& arg) + { + std::istringstream strm(arg); + ArgumentT val; + strm >> val; + if (strm.fail() || strm.bad()) + throw std::runtime_error("Failed to parse argument from \"" + arg + "\""); + return val; + } }; void init_factories() diff --git a/example/doc/extension_stat_collector_settings.cpp b/example/doc/extension_stat_collector_settings.cpp index b333c4e1c1..6d81cb24c7 100644 --- a/example/doc/extension_stat_collector_settings.cpp +++ b/example/doc/extension_stat_collector_settings.cpp @@ -12,7 +12,6 @@ #include #include #include -#include #include #include #include @@ -169,7 +168,7 @@ class stat_collector_factory : boost::posix_time::time_duration write_interval = boost::posix_time::minutes(1); if (boost::optional< std::string > param = settings["WriteInterval"]) { - unsigned int sec = boost::lexical_cast< unsigned int >(param.get()); + unsigned long sec = std::stoul(param.get()); write_interval = boost::posix_time::seconds(sec); } diff --git a/include/boost/log/utility/setup/filter_parser.hpp b/include/boost/log/utility/setup/filter_parser.hpp index 9a6c9f6d25..16d2cc5475 100644 --- a/include/boost/log/utility/setup/filter_parser.hpp +++ b/include/boost/log/utility/setup/filter_parser.hpp @@ -16,7 +16,7 @@ #define BOOST_LOG_UTILITY_SETUP_FILTER_PARSER_HPP_INCLUDED_ #include -#include +#include #include #include #include @@ -217,7 +217,12 @@ class basic_filter_factory : */ virtual value_type parse_argument(string_type const& arg) { - return boost::lexical_cast< value_type >(arg); + std::basic_istringstream< typename base_type::char_type > strm(arg); + value_type val{}; + strm >> val; + if (BOOST_UNLIKELY((strm.rdstate() & (std::ios_base::badbit | std::ios_base::failbit)) != 0)) + BOOST_LOG_THROW_DESCR(parse_error, "Failed to parse argument value from \"" + boost::log::aux::to_narrow(arg) + "\""); + return val; } }; diff --git a/src/process_name.cpp b/src/process_name.cpp index 864defacaa..b44d00c10e 100644 --- a/src/process_name.cpp +++ b/src/process_name.cpp @@ -113,7 +113,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include #include #include -#include +#include #include #include @@ -137,7 +137,7 @@ BOOST_LOG_API std::string get_process_name() if (filesystem::exists("/proc/curproc/file")) return filesystem::read_symlink("/proc/curproc/file").filename().string(); - return boost::lexical_cast< std::string >(getpid()); + return std::to_string(getpid()); } } // namespace aux @@ -151,7 +151,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #else #include -#include +#include #include #include @@ -173,7 +173,7 @@ BOOST_LOG_API std::string get_process_name() if (filesystem::exists("/proc/curproc/exe")) return filesystem::read_symlink("/proc/curproc/exe").filename().string(); - return boost::lexical_cast< std::string >(getpid()); + return std::to_string(getpid()); } } // namespace aux From 62d63678ae0edd192e81d8785678898091bafce9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 3 Sep 2023 02:30:41 +0300 Subject: [PATCH 219/309] Switch to boost::core::invoke_swap. boost::swap is deprecated and will be removed. Use boost::core::invoke_swap as a replacement. --- include/boost/log/sources/severity_feature.hpp | 4 ++-- src/core.cpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/log/sources/severity_feature.hpp b/include/boost/log/sources/severity_feature.hpp index e798fb0dde..2fdd21235e 100644 --- a/include/boost/log/sources/severity_feature.hpp +++ b/include/boost/log/sources/severity_feature.hpp @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include #include @@ -261,7 +261,7 @@ class basic_severity_logger : void swap_unlocked(basic_severity_logger& that) { base_type::swap_unlocked(static_cast< base_type& >(that)); - boost::swap(m_DefaultSeverity, that.m_DefaultSeverity); + boost::core::invoke_swap(m_DefaultSeverity, that.m_DefaultSeverity); m_SeverityAttr.swap(that.m_SeverityAttr); } }; diff --git a/src/core.cpp b/src/core.cpp index 4fe27c7eea..657de0eb8d 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -20,7 +20,7 @@ #include #include #include -#include +#include #include #include #include @@ -61,7 +61,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Sequence shuffling algorithm. Very similar to std::random_shuffle, used for forward portability with compilers that removed it from the standard library (C++17). template< typename Iterator, typename RandomNumberGenerator > -void random_shuffle(Iterator begin, Iterator end, RandomNumberGenerator& rng) +inline void random_shuffle(Iterator begin, Iterator end, RandomNumberGenerator& rng) { Iterator it = begin; ++it; @@ -69,7 +69,7 @@ void random_shuffle(Iterator begin, Iterator end, RandomNumberGenerator& rng) { Iterator where = begin + rng() % (it - begin + 1u); if (where != it) - boost::swap(*where, *it); + boost::core::invoke_swap(*where, *it); ++it; } } From adbdc63e1048c5e2c70e6e8eac8b7d6a1f292ede Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 3 Sep 2023 03:52:11 +0300 Subject: [PATCH 220/309] Drop gcc 4.6 and 4.7 from CI. Boost.Variant now uses reference qualitication for its methods, which is only supported since gcc 4.8. --- .github/workflows/ci.yml | 14 -------------- doc/log.qbk | 2 +- 2 files changed, 1 insertion(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2b97f22579..f19f6253c8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,20 +35,6 @@ jobs: matrix: include: # Linux, gcc - - toolset: gcc-4.6 - cxxstd: "0x" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - g++-4.6 - sources: - - "ppa:ubuntu-toolchain-r/test" - - toolset: gcc-4.7 - cxxstd: "11" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - g++-4.7 - toolset: gcc-4.8 cxxstd: "11" os: ubuntu-latest diff --git a/doc/log.qbk b/doc/log.qbk index ae2bef3b7e..2cae856362 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -167,7 +167,7 @@ The library should build and work with a reasonably compliant C++11 compiler. Th * Windows 10. MSVC 14.0 and newer. MinGW32 with gcc 5.x and MinGW-w64 with gcc 6.x and newer. * Cygwin and Cygwin64 with gcc 7.x and newer. -* Linux. GCC 4.6 and newer. +* Linux. GCC 4.8 and newer. * Linux. Clang 3.5 and newer. The following compilers/platforms are not supported and will likely fail to compile the library: From 4db6450fe8a9f8682f1a2e645e57abea8ed04f2f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 25 Sep 2023 20:06:26 +0300 Subject: [PATCH 221/309] Conditionally link with Boost.Regex library, if it's in C++03 mode. Boost.Log supports compilers that do not qualify as C++11 compilers for Boost.Regex, even if they are compiling in C++11 mode. In that case, we still need to link with Boost.Regex v4 prebuilt library. For more recent compilers, Boost.Regex v5 is used, and that is a header-only library. This commit removes linking with Boost.Regex when this is detected at configure time. Note that only Boost.Build is updated. CMake doesn't need to be updated since even header-only libraries need to be listed as dependencies. Closes https://github.com/boostorg/log/pull/219. --- build/Jamfile.v2 | 147 ++---------------- build/log-arch-config.jam | 18 +++ build/log-build-config.jam | 135 ++++++++++++++++ config/regex-header-only/Jamfile.jam | 19 +++ .../regex-header-only/regex_header_only.cpp | 17 ++ doc/changelog.qbk | 1 + test/Jamfile.v2 | 3 +- 7 files changed, 206 insertions(+), 134 deletions(-) create mode 100644 build/log-build-config.jam create mode 100644 config/regex-header-only/Jamfile.jam create mode 100644 config/regex-header-only/regex_header_only.cpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 46dd045965..f3fcb58fa2 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -14,16 +14,14 @@ import feature ; import configure ; import log-arch-config ; import log-platform-config ; +import log-build-config ; + using mc ; local here = [ modules.binding $(__name__) ] ; project.push-current [ project.current ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/message-compiler ] ; project.load [ path.join [ path.make $(here:D) ] ../config/x86-ext ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/pthread-mutex-robust ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/native-syslog ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/atomic-int32 ] ; project.pop-current ; # Windows libs @@ -41,132 +39,15 @@ lib nsl ; lib ipv6 ; explicit rt socket nsl ipv6 ; -rule has-config-flag ( flag : properties * ) -{ - if ( "$(flag)" in $(properties) || "$(flag)=1" in $(properties) ) - { - return 1 ; - } - else - { - return ; - } -} - -rule check-instruction-set ( properties * ) -{ - local result ; - local instruction_set = [ log-arch-config.deduce-instruction-set $(properties) ] ; - - if $(instruction_set) = i386 || $(instruction_set) = i486 - { - if ! $(.annouced-failure) - { - ECHO Boost.Log is not supported on the specified target CPU and will not be built. At least i586 class CPU is required. ; - .annouced-failure = 1 ; - } - result = no ; - } - - return $(result) ; -} - -rule select-regex-backend ( properties * ) -{ - local result ; - - # Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching. - if ! ( - [ has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] || - [ has-config-flag BOOST_LOG_WITHOUT_DEFAULT_FACTORIES : $(properties) ] || - [ has-config-flag BOOST_LOG_USE_STD_REGEX : $(properties) ] || - [ has-config-flag BOOST_LOG_USE_BOOST_XPRESSIVE : $(properties) ] ) - { - result = /boost/regex//boost_regex ; - } - - return $(result) ; -} - -rule check-pthread-mutex-robust ( properties * ) -{ - local result ; - - local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : "pthread supports robust mutexes" ] ; - if $(has_pthread_mutex_robust) - { - result = BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST ; - } - - return $(result) ; -} - -rule check-atomic-int32 ( properties * ) -{ - local result ; - - local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : "native atomic int32 supported" ] ; - if ! $(has_atomic_int32) - { - result = BOOST_LOG_WITHOUT_IPC ; - } - - return $(result) ; -} - -rule check-native-syslog ( properties * ) -{ - local result ; - - if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] - { - local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : "native syslog supported" ] ; - if $(has_native_syslog) - { - result = BOOST_LOG_USE_NATIVE_SYSLOG ; - } - } - - return $(result) ; -} - -rule check-message-compiler ( properties * ) -{ - local result ; - - if windows in $(properties) - { - if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] - { - local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : "has message compiler" ] ; - if ! $(has_mc) - { - result = BOOST_LOG_WITHOUT_EVENT_LOG ; - } - } - else - { - # This branch is needed to fix building with MinGW - result = BOOST_LOG_WITHOUT_EVENT_LOG ; - } - } - else - { - result = BOOST_LOG_WITHOUT_EVENT_LOG ; - } - - return $(result) ; -} - project boost/log : source-location ../src : requirements - @check-instruction-set - @check-atomic-int32 - @select-regex-backend - @check-pthread-mutex-robust - @check-native-syslog - @check-message-compiler + @log-arch-config.check-instruction-set + @log-build-config.check-atomic-int32 + @log-build-config.select-regex-backend + @log-build-config.check-pthread-mutex-robust + @log-build-config.check-native-syslog + @log-build-config.check-message-compiler @log-platform-config.set-platform-defines ../src @@ -346,7 +227,7 @@ rule select-platform-specific-sources ( properties * ) result += windows/light_rw_mutex.cpp ; result += windows/is_debugger_present.cpp ; - if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] + if ! [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] { result += windows/object_name.cpp ; result += windows/mapped_shared_memory.cpp ; @@ -355,12 +236,12 @@ rule select-platform-specific-sources ( properties * ) result += secur32 ; } - if ! [ has-config-flag BOOST_LOG_WITHOUT_DEBUG_OUTPUT : $(properties) ] + if ! [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_DEBUG_OUTPUT : $(properties) ] { result += windows/debug_output_backend.cpp ; } - if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] + if ! [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] { result += windows/simple_event_log.mc ; result += windows/event_log_backend.cpp ; @@ -374,14 +255,14 @@ rule select-platform-specific-sources ( properties * ) result += BOOST_LOG_WITHOUT_EVENT_LOG ; result += BOOST_LOG_WITHOUT_DEBUG_OUTPUT ; - if ! [ has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] + if ! [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_IPC : $(properties) ] { result += posix/object_name.cpp ; result += posix/ipc_reliable_message_queue.cpp ; } } - if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] + if ! [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] { result += syslog_backend.cpp ; } @@ -422,7 +303,7 @@ rule check-boost_log_setup-enabled ( properties * ) { local result ; - if [ has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] + if [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] { result = no ; } diff --git a/build/log-arch-config.jam b/build/log-arch-config.jam index 89ecee4051..ee410ce1e0 100644 --- a/build/log-arch-config.jam +++ b/build/log-arch-config.jam @@ -154,3 +154,21 @@ rule avx2-flags ( properties * ) return $(result) ; } + +rule check-instruction-set ( properties * ) +{ + local result ; + local instruction_set = [ log-arch-config.deduce-instruction-set $(properties) ] ; + + if $(instruction_set) = i386 || $(instruction_set) = i486 + { + if ! $(.annouced-failure) + { + ECHO Boost.Log is not supported on the specified target CPU and will not be built. At least i586 class CPU is required. ; + .annouced-failure = 1 ; + } + result = no ; + } + + return $(result) ; +} diff --git a/build/log-build-config.jam b/build/log-build-config.jam new file mode 100644 index 0000000000..51cc312798 --- /dev/null +++ b/build/log-build-config.jam @@ -0,0 +1,135 @@ +# log-build-config.jam +# +# Copyright 2023 Andrey Semashev +# +# Distributed under the Boost Software License Version 1.0. (See +# accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import configure ; +import project ; +import path ; +import property ; +import feature ; + +local here = [ modules.binding $(__name__) ] ; + +project.push-current [ project.current ] ; +project.load [ path.join [ path.make $(here:D) ] ../config/message-compiler ] ; +project.load [ path.join [ path.make $(here:D) ] ../config/pthread-mutex-robust ] ; +project.load [ path.join [ path.make $(here:D) ] ../config/native-syslog ] ; +project.load [ path.join [ path.make $(here:D) ] ../config/atomic-int32 ] ; +project.load [ path.join [ path.make $(here:D) ] ../config/regex-header-only ] ; +project.pop-current ; + +rule has-config-flag ( flag : properties * ) +{ + if ( "$(flag)" in $(properties) || "$(flag)=1" in $(properties) ) + { + return 1 ; + } + else + { + return ; + } +} + +rule check-regex-header-only ( properties * ) +{ + local result ; + + local has_regex_header_only = [ configure.builds /boost/log/regex-header-only//regex_header_only : $(properties) : "Boost.Regex is header-only" ] ; + if ! $(has_regex_header_only) + { + result = /boost/regex//boost_regex ; + } + + return $(result) ; +} + +rule check-atomic-int32 ( properties * ) +{ + local result ; + + local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : "native atomic int32 supported" ] ; + if ! $(has_atomic_int32) + { + result = BOOST_LOG_WITHOUT_IPC ; + } + + return $(result) ; +} + +rule check-pthread-mutex-robust ( properties * ) +{ + local result ; + + local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : "pthread supports robust mutexes" ] ; + if $(has_pthread_mutex_robust) + { + result = BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST ; + } + + return $(result) ; +} + +rule check-native-syslog ( properties * ) +{ + local result ; + + if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] + { + local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : "native syslog supported" ] ; + if $(has_native_syslog) + { + result = BOOST_LOG_USE_NATIVE_SYSLOG ; + } + } + + return $(result) ; +} + +rule check-message-compiler ( properties * ) +{ + local result ; + + if windows in $(properties) + { + if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] + { + local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : "has message compiler" ] ; + if ! $(has_mc) + { + result = BOOST_LOG_WITHOUT_EVENT_LOG ; + } + } + else + { + # This branch is needed to fix building with MinGW + result = BOOST_LOG_WITHOUT_EVENT_LOG ; + } + } + else + { + result = BOOST_LOG_WITHOUT_EVENT_LOG ; + } + + return $(result) ; +} + +rule select-regex-backend ( properties * ) +{ + local result ; + + # Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching. + if ! ( + [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] || + [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_DEFAULT_FACTORIES : $(properties) ] || + [ log-build-config.has-config-flag BOOST_LOG_USE_STD_REGEX : $(properties) ] || + [ log-build-config.has-config-flag BOOST_LOG_USE_BOOST_XPRESSIVE : $(properties) ] ) + { + result = @log-build-config.check-regex-header-only ; + } + + return $(result) ; +} diff --git a/config/regex-header-only/Jamfile.jam b/config/regex-header-only/Jamfile.jam new file mode 100644 index 0000000000..90d28e94fc --- /dev/null +++ b/config/regex-header-only/Jamfile.jam @@ -0,0 +1,19 @@ +# +# Copyright Andrey Semashev 2023. +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) +# + +import project ; +import log-platform-config ; + +project /boost/log/regex-header-only + : source-location . + : requirements + @log-platform-config.set-platform-defines + off + ; + +obj regex_header_only : regex_header_only.cpp ; +explicit regex_header_only ; diff --git a/config/regex-header-only/regex_header_only.cpp b/config/regex-header-only/regex_header_only.cpp new file mode 100644 index 0000000000..d584227708 --- /dev/null +++ b/config/regex-header-only/regex_header_only.cpp @@ -0,0 +1,17 @@ +/* + * Copyright Andrey Semashev 2023. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include + +#if defined(BOOST_REGEX_CXX03) +#error Boost.Log: Boost.Regex is in C++03 mode and is not header-only +#endif + +int main(int, char*[]) +{ + return 0; +} diff --git a/doc/changelog.qbk b/doc/changelog.qbk index e46cc2bfb4..5d526c8b2d 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -12,6 +12,7 @@ [heading 2.28, Boost 1.84] * C++03 is no longer supported. A C++11 or later compiler is required. +* When built with C++11 compilers that are conforming enough for Boost.Regex v5 to be used, Boost.Log no longer links with Boost.Regex prebuilt library, since Boost.Regex v5 is header-only. [heading 2.27, Boost 1.83] diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 73107a27f7..34a8324fbb 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -11,10 +11,12 @@ import path ; import regex ; import os ; import ../build/log-platform-config ; +import ../build/log-build-config ; project : requirements @log-platform-config.set-platform-defines + @log-build-config.check-regex-header-only common @@ -50,7 +52,6 @@ project /boost/log//boost_log /boost/log//boost_log_setup - /boost/regex//boost_regex /boost/filesystem//boost_filesystem /boost/test//boost_unit_test_framework single:BOOST_LOG_NO_THREADS From 2352b7eacfdf7993db67698679272f01c4b00606 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Oct 2023 17:31:06 +0300 Subject: [PATCH 222/309] Updated cxxstd to 11 in library metadata. --- meta/libraries.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/meta/libraries.json b/meta/libraries.json index 6b2ea363fc..ee35c7b0fc 100644 --- a/meta/libraries.json +++ b/meta/libraries.json @@ -11,5 +11,5 @@ "maintainers": [ "Andrey Semashev " ], - "cxxstd": "03" + "cxxstd": "11" } From 9d726cc5fe0ed59ab98cc367a50956f802d3cca1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Oct 2023 17:47:29 +0300 Subject: [PATCH 223/309] Switch to C++11 static_assert. --- CMakeLists.txt | 11 ++++++++++- include/boost/log/attributes/counter.hpp | 3 +-- include/boost/log/attributes/function.hpp | 3 +-- include/boost/log/attributes/mutable_constant.hpp | 3 +-- include/boost/log/detail/thread_specific.hpp | 3 +-- .../log/expressions/formatters/char_decorator.hpp | 3 +-- .../boost/log/expressions/formatters/named_scope.hpp | 9 ++++----- include/boost/log/sinks/async_frontend.hpp | 3 +-- include/boost/log/sinks/sync_frontend.hpp | 3 +-- include/boost/log/sinks/unlocked_frontend.hpp | 3 +-- include/boost/log/sources/severity_feature.hpp | 3 +-- .../utility/type_dispatch/static_type_dispatcher.hpp | 3 +-- .../log/utility/type_dispatch/type_dispatcher.hpp | 5 ++--- src/posix/ipc_reliable_message_queue.cpp | 1 - src/windows/ipc_reliable_message_queue.cpp | 1 - test/compile/current_function_support.cpp | 3 +-- 16 files changed, 27 insertions(+), 33 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2ce9546974..cdec5d7306 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2021-2022 Andrey Semashev +# Copyright 2021-2023 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt @@ -442,6 +442,10 @@ endif() set(boost_log_install_targets boost_log) add_library(Boost::log ALIAS boost_log) +target_compile_features(boost_log PUBLIC + cxx_static_assert +) + target_include_directories(boost_log PUBLIC include @@ -580,6 +584,11 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) endif() list(APPEND boost_log_install_targets boost_log_setup) + target_compile_features(boost_log_setup PUBLIC + cxx_static_assert + cxx_uniform_initialization + ) + target_include_directories(boost_log_setup PUBLIC include diff --git a/include/boost/log/attributes/counter.hpp b/include/boost/log/attributes/counter.hpp index b7d9994027..fa3522a887 100644 --- a/include/boost/log/attributes/counter.hpp +++ b/include/boost/log/attributes/counter.hpp @@ -15,7 +15,6 @@ #ifndef BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_ #define BOOST_LOG_ATTRIBUTES_COUNTER_HPP_INCLUDED_ -#include #include #include #include @@ -48,7 +47,7 @@ template< typename T > class counter : public attribute { - BOOST_STATIC_ASSERT_MSG(is_integral< T >::value, "Boost.Log: Only integral types are supported by the counter attribute"); + static_assert(is_integral< T >::value, "Boost.Log: Only integral types are supported by the counter attribute"); public: //! A counter value type diff --git a/include/boost/log/attributes/function.hpp b/include/boost/log/attributes/function.hpp index 488416c5df..409a604d68 100644 --- a/include/boost/log/attributes/function.hpp +++ b/include/boost/log/attributes/function.hpp @@ -15,7 +15,6 @@ #ifndef BOOST_LOG_ATTRIBUTES_FUNCTION_HPP_INCLUDED_ #define BOOST_LOG_ATTRIBUTES_FUNCTION_HPP_INCLUDED_ -#include #include #include #include @@ -49,7 +48,7 @@ template< typename R > class function : public attribute { - BOOST_STATIC_ASSERT_MSG(!is_void< R >::value, "Boost.Log: Function object return type must not be void"); + static_assert(!is_void< R >::value, "Boost.Log: Function object return type must not be void"); public: //! The attribute value type diff --git a/include/boost/log/attributes/mutable_constant.hpp b/include/boost/log/attributes/mutable_constant.hpp index 9357dafa02..ca659f56a2 100644 --- a/include/boost/log/attributes/mutable_constant.hpp +++ b/include/boost/log/attributes/mutable_constant.hpp @@ -15,7 +15,6 @@ #ifndef BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_ #define BOOST_LOG_ATTRIBUTES_MUTABLE_CONSTANT_HPP_INCLUDED_ -#include #include #include #include @@ -99,7 +98,7 @@ class mutable_constant : typedef ScopedReadLockT scoped_read_lock; //! Exclusive lock type typedef ScopedWriteLockT scoped_write_lock; - BOOST_STATIC_ASSERT_MSG(!(is_void< mutex_type >::value || is_void< scoped_read_lock >::value || is_void< scoped_write_lock >::value), "Boost.Log: Mutex and both lock types either must not be void or must all be void"); + static_assert(!(is_void< mutex_type >::value || is_void< scoped_read_lock >::value || is_void< scoped_write_lock >::value), "Boost.Log: Mutex and both lock types either must not be void or must all be void"); //! Attribute value wrapper typedef attribute_value_impl< value_type > attr_value; diff --git a/include/boost/log/detail/thread_specific.hpp b/include/boost/log/detail/thread_specific.hpp index 7e38be5aab..badcbb9370 100644 --- a/include/boost/log/detail/thread_specific.hpp +++ b/include/boost/log/detail/thread_specific.hpp @@ -16,7 +16,6 @@ #ifndef BOOST_LOG_DETAIL_THREAD_SPECIFIC_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_THREAD_SPECIFIC_HPP_INCLUDED_ -#include #include #include @@ -62,7 +61,7 @@ template< typename T > class thread_specific : public thread_specific_base { - BOOST_STATIC_ASSERT_MSG(sizeof(T) <= sizeof(void*) && is_pod< T >::value, "Boost.Log: Thread-specific values must be PODs and must not exceed the size of a pointer"); + static_assert(sizeof(T) <= sizeof(void*) && is_pod< T >::value, "Boost.Log: Thread-specific values must be PODs and must not exceed the size of a pointer"); //! Union to perform type casting union value_storage diff --git a/include/boost/log/expressions/formatters/char_decorator.hpp b/include/boost/log/expressions/formatters/char_decorator.hpp index 229e72ae89..7dca657fae 100644 --- a/include/boost/log/expressions/formatters/char_decorator.hpp +++ b/include/boost/log/expressions/formatters/char_decorator.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -561,7 +560,7 @@ class char_decorator_gen2 typedef typename boost::log::aux::deduce_char_type< typename range_value< FromRangeT >::type >::type from_char_type; typedef typename boost::log::aux::deduce_char_type< typename range_value< ToRangeT >::type >::type to_char_type; - BOOST_STATIC_ASSERT_MSG((is_same< from_char_type, to_char_type >::value), "Boost.Log: character decorator cannot be instantiated with different character types for source and replacement strings"); + static_assert(is_same< from_char_type, to_char_type >::value, "Boost.Log: character decorator cannot be instantiated with different character types for source and replacement strings"); public: char_decorator_gen2(FromRangeT const& from, ToRangeT const& to) : m_from(from), m_to(to) diff --git a/include/boost/log/expressions/formatters/named_scope.hpp b/include/boost/log/expressions/formatters/named_scope.hpp index ae140b1956..e4b754f568 100644 --- a/include/boost/log/expressions/formatters/named_scope.hpp +++ b/include/boost/log/expressions/formatters/named_scope.hpp @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -524,7 +523,7 @@ template< typename DescriptorT, template< typename > class ActorT, typename Char BOOST_FORCEINLINE format_named_scope_actor< fallback_to_none, CharT, ActorT > format_named_scope(attribute_keyword< DescriptorT, ActorT > const& keyword, const CharT* element_format) { - BOOST_STATIC_ASSERT_MSG((is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value),\ + static_assert(is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef format_named_scope_actor< fallback_to_none, CharT, ActorT > actor_type; @@ -544,7 +543,7 @@ template< typename DescriptorT, template< typename > class ActorT, typename Char BOOST_FORCEINLINE format_named_scope_actor< fallback_to_none, CharT, ActorT > format_named_scope(attribute_keyword< DescriptorT, ActorT > const& keyword, std::basic_string< CharT > const& element_format) { - BOOST_STATIC_ASSERT_MSG((is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value),\ + static_assert(is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef format_named_scope_actor< fallback_to_none, CharT, ActorT > actor_type; @@ -564,7 +563,7 @@ template< typename T, typename FallbackPolicyT, typename TagT, template< typenam BOOST_FORCEINLINE format_named_scope_actor< FallbackPolicyT, CharT, ActorT > format_named_scope(attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& placeholder, const CharT* element_format) { - BOOST_STATIC_ASSERT_MSG((is_same< T, attributes::named_scope::value_type >::value),\ + static_assert(is_same< T, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef format_named_scope_actor< FallbackPolicyT, CharT, ActorT > actor_type; @@ -584,7 +583,7 @@ template< typename T, typename FallbackPolicyT, typename TagT, template< typenam BOOST_FORCEINLINE format_named_scope_actor< FallbackPolicyT, CharT, ActorT > format_named_scope(attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& placeholder, std::basic_string< CharT > const& element_format) { - BOOST_STATIC_ASSERT_MSG((is_same< T, attributes::named_scope::value_type >::value),\ + static_assert(is_same< T, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef format_named_scope_actor< FallbackPolicyT, CharT, ActorT > actor_type; diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 3d20718978..79fade5b68 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -26,7 +26,6 @@ #error Boost.Log: Asynchronous sink frontend is only supported in multithreaded environment #endif -#include #include #include #include @@ -221,7 +220,7 @@ class asynchronous_sink : //! Sink implementation type typedef SinkBackendT sink_backend_type; //! \cond - BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value), "Asynchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); + static_assert(has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value, "Asynchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); //! \endcond #ifndef BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/sync_frontend.hpp b/include/boost/log/sinks/sync_frontend.hpp index d92df8d971..738b688055 100644 --- a/include/boost/log/sinks/sync_frontend.hpp +++ b/include/boost/log/sinks/sync_frontend.hpp @@ -25,7 +25,6 @@ #error Boost.Log: Synchronous sink frontend is only supported in multithreaded environment #endif -#include #include #include #include @@ -82,7 +81,7 @@ class synchronous_sink : //! Sink implementation type typedef SinkBackendT sink_backend_type; //! \cond - BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value), "Synchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); + static_assert(has_requirement< typename sink_backend_type::frontend_requirements, synchronized_feeding >::value, "Synchronous sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); //! \endcond #ifndef BOOST_LOG_DOXYGEN_PASS diff --git a/include/boost/log/sinks/unlocked_frontend.hpp b/include/boost/log/sinks/unlocked_frontend.hpp index 0b8c7570c6..472a9624bd 100644 --- a/include/boost/log/sinks/unlocked_frontend.hpp +++ b/include/boost/log/sinks/unlocked_frontend.hpp @@ -15,7 +15,6 @@ #ifndef BOOST_LOG_SINKS_UNLOCKED_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_UNLOCKED_FRONTEND_HPP_INCLUDED_ -#include #include #include #include @@ -72,7 +71,7 @@ class unlocked_sink : //! Sink implementation type typedef SinkBackendT sink_backend_type; //! \cond - BOOST_STATIC_ASSERT_MSG((has_requirement< typename sink_backend_type::frontend_requirements, concurrent_feeding >::value), "Unlocked sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); + static_assert(has_requirement< typename sink_backend_type::frontend_requirements, concurrent_feeding >::value, "Unlocked sink frontend is incompatible with the specified backend: thread synchronization requirements are not met"); //! \endcond //! Type of pointer to the backend diff --git a/include/boost/log/sources/severity_feature.hpp b/include/boost/log/sources/severity_feature.hpp index 2fdd21235e..a7db0d92c9 100644 --- a/include/boost/log/sources/severity_feature.hpp +++ b/include/boost/log/sources/severity_feature.hpp @@ -16,7 +16,6 @@ #define BOOST_LOG_SOURCES_SEVERITY_FEATURE_HPP_INCLUDED_ #include -#include #include #include #include @@ -60,7 +59,7 @@ namespace aux { public: //! Stored level type typedef LevelT value_type; - BOOST_STATIC_ASSERT_MSG(sizeof(value_type) <= sizeof(uintmax_t), "Boost.Log: Unsupported severity level type, the severity level must fit into uintmax_t"); + static_assert(sizeof(value_type) <= sizeof(uintmax_t), "Boost.Log: Unsupported severity level type, the severity level must fit into uintmax_t"); protected: //! Factory implementation diff --git a/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp b/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp index dcf2cd033d..c78852024d 100644 --- a/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp +++ b/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp @@ -20,7 +20,6 @@ #include #include #include -#include #include #include #include @@ -82,7 +81,7 @@ struct dispatching_map_initializer p->first = typeindex::type_id< T >(); typedef void (*trampoline_t)(void*, T const&); - BOOST_STATIC_ASSERT_MSG(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); + static_assert(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); union { void* as_pvoid; diff --git a/include/boost/log/utility/type_dispatch/type_dispatcher.hpp b/include/boost/log/utility/type_dispatch/type_dispatcher.hpp index 148595fcf3..ca633aa16c 100644 --- a/include/boost/log/utility/type_dispatch/type_dispatcher.hpp +++ b/include/boost/log/utility/type_dispatch/type_dispatcher.hpp @@ -16,7 +16,6 @@ #define BOOST_LOG_TYPE_DISPATCHER_HPP_INCLUDED_ #include -#include #include #include #include @@ -59,7 +58,7 @@ class type_dispatcher m_pVisitor(visitor) { typedef void (*trampoline_t)(void*, ValueT const&); - BOOST_STATIC_ASSERT_MSG(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); + static_assert(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); union { void* as_pvoid; @@ -100,7 +99,7 @@ class type_dispatcher void operator() (T const& value) const { - BOOST_STATIC_ASSERT_MSG(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); + static_assert(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); union { void* as_pvoid; diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index 39333834b5..c3b1cb6582 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -35,7 +35,6 @@ #include #endif #include -#include #include #include #include diff --git a/src/windows/ipc_reliable_message_queue.cpp b/src/windows/ipc_reliable_message_queue.cpp index aa12a68cad..146ae34739 100644 --- a/src/windows/ipc_reliable_message_queue.cpp +++ b/src/windows/ipc_reliable_message_queue.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include diff --git a/test/compile/current_function_support.cpp b/test/compile/current_function_support.cpp index cdcd1051ad..3367d4b0d2 100644 --- a/test/compile/current_function_support.cpp +++ b/test/compile/current_function_support.cpp @@ -20,13 +20,12 @@ #define BOOST_TEST_MODULE current_function_support #include -#include #include template< typename T > void check(T& param) { - BOOST_STATIC_ASSERT(boost::is_array< T >::value); + static_assert(boost::is_array< T >::value, "T must be an array"); } int main(int, char*[]) From c7c0aa7acb726a30b05bfccc685bf75d93df4bbf Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Oct 2023 23:11:51 +0300 Subject: [PATCH 224/309] Added Boost.Build requirements on C++11 features we use. --- build/Jamfile.v2 | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index f3fcb58fa2..1feef1cf04 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -1,5 +1,5 @@ # -# Copyright Andrey Semashev 2007 - 2020. +# Copyright Andrey Semashev 2007 - 2023. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) @@ -12,6 +12,7 @@ import path ; import project ; import feature ; import configure ; +import config : requires ; import log-arch-config ; import log-platform-config ; import log-build-config ; @@ -39,6 +40,15 @@ lib nsl ; lib ipv6 ; explicit rt socket nsl ipv6 ; +local log_cxx_requirements = [ requires + cxx11_static_assert + ] ; + +local log_setup_cxx_requirements = [ requires + cxx11_static_assert + cxx11_unified_initialization_syntax + ] ; + project boost/log : source-location ../src : requirements @@ -280,10 +290,12 @@ lib boost_log @select-platform-specific-sources shared:BOOST_LOG_DLL BOOST_LOG_BUILDING_THE_LIB=1 + $(log_cxx_requirements) : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_DYN_LINK=1 single:BOOST_LOG_NO_THREADS + $(log_cxx_requirements) ; @@ -319,11 +331,13 @@ lib boost_log_setup shared:BOOST_LOG_DYN_LINK=1 shared:BOOST_LOG_SETUP_DLL BOOST_LOG_SETUP_BUILDING_THE_LIB=1 + $(log_setup_cxx_requirements) boost_log : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_SETUP_DYN_LINK=1 single:BOOST_LOG_NO_THREADS + $(log_setup_cxx_requirements) ; boost-install boost_log boost_log_setup ; From 3df6ed0b05602e0386ebdff305456cfdf9ea9c05 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Oct 2023 23:15:52 +0300 Subject: [PATCH 225/309] Updated include path. --- include/boost/log/utility/setup/settings.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/boost/log/utility/setup/settings.hpp b/include/boost/log/utility/setup/settings.hpp index 24a8998fcd..3798cf6ade 100644 --- a/include/boost/log/utility/setup/settings.hpp +++ b/include/boost/log/utility/setup/settings.hpp @@ -31,7 +31,7 @@ #include #endif #if defined(BOOST_LOG_TYPEOF) && defined(BOOST_NO_CXX11_TRAILING_RESULT_TYPES) -#include +#include #endif #include From d1f54da1c028bc213a8023b55c38b208b1efe8dd Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 1 Oct 2023 23:20:55 +0300 Subject: [PATCH 226/309] Removed dummy boost_log_setup_is_empty export. This should no longer be needed, now that b3ffed4ec2cdb376e9355a17d5e89ec2f3bc893a is merged. --- src/setup/settings_parser.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/src/setup/settings_parser.cpp b/src/setup/settings_parser.cpp index b1e54b46d2..9a0634564d 100644 --- a/src/setup/settings_parser.cpp +++ b/src/setup/settings_parser.cpp @@ -258,30 +258,4 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include -#else // BOOST_LOG_WITHOUT_SETTINGS_PARSERS - -#include - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -BOOST_LOG_SETUP_API void boost_log_setup_is_empty() -{ - // This dummy export exists to that boost_log_setup library is not empty and is created even if settings parsers are disabled. - // MSVC is known to not generate the library if it contains no exports (https://github.com/boostorg/log/issues/164), which breaks - // install targets as Boost.Build cannot find the library file to install. - // We use this dummy export instead of disabling building boost_log_setup in the first place because of this Boost.Build bug: - // - // https://github.com/bfgroup/b2/issues/104 - // - // After this bug is fixed, we can consider removing this dummy export and disabling building the library proper. -} - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#include - #endif // BOOST_LOG_WITHOUT_SETTINGS_PARSERS From 3ff5b0d8ba4836baf4ae3063cb097efc5ee5b654 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 2 Oct 2023 00:26:36 +0300 Subject: [PATCH 227/309] Removed dependency on Boost.Bind. --- CMakeLists.txt | 16 +++++++++++----- build/Jamfile.v2 | 22 ++++++++++++++++------ src/setup/init_from_settings.cpp | 8 +++++--- src/severity_level.cpp | 4 +--- src/text_file_backend.cpp | 32 ++++++++++++++++++++++++++------ 5 files changed, 59 insertions(+), 23 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cdec5d7306..bb41d46c2b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -442,8 +442,11 @@ endif() set(boost_log_install_targets boost_log) add_library(Boost::log ALIAS boost_log) -target_compile_features(boost_log PUBLIC - cxx_static_assert +target_compile_features(boost_log + PUBLIC + cxx_static_assert + PRIVATE + cxx_lambdas ) target_include_directories(boost_log @@ -584,9 +587,12 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) endif() list(APPEND boost_log_install_targets boost_log_setup) - target_compile_features(boost_log_setup PUBLIC - cxx_static_assert - cxx_uniform_initialization + target_compile_features(boost_log_setup + PUBLIC + cxx_static_assert + cxx_uniform_initialization + PRIVATE + cxx_lambdas ) target_include_directories(boost_log_setup diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 1feef1cf04..4657fdfb14 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -40,15 +40,23 @@ lib nsl ; lib ipv6 ; explicit rt socket nsl ipv6 ; -local log_cxx_requirements = [ requires +local log_cxx_public_requirements = [ requires cxx11_static_assert ] ; -local log_setup_cxx_requirements = [ requires +local log_cxx_private_requirements = [ requires + cxx11_lambdas + ] ; + +local log_setup_cxx_public_requirements = [ requires cxx11_static_assert cxx11_unified_initialization_syntax ] ; +local log_setup_cxx_public_requirements = [ requires + cxx11_lambdas + ] ; + project boost/log : source-location ../src : requirements @@ -290,12 +298,13 @@ lib boost_log @select-platform-specific-sources shared:BOOST_LOG_DLL BOOST_LOG_BUILDING_THE_LIB=1 - $(log_cxx_requirements) + $(log_cxx_public_requirements) + $(log_cxx_private_requirements) : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_DYN_LINK=1 single:BOOST_LOG_NO_THREADS - $(log_cxx_requirements) + $(log_cxx_public_requirements) ; @@ -331,13 +340,14 @@ lib boost_log_setup shared:BOOST_LOG_DYN_LINK=1 shared:BOOST_LOG_SETUP_DLL BOOST_LOG_SETUP_BUILDING_THE_LIB=1 - $(log_setup_cxx_requirements) + $(log_setup_cxx_public_requirements) + $(log_setup_cxx_private_requirements) boost_log : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_SETUP_DYN_LINK=1 single:BOOST_LOG_NO_THREADS - $(log_setup_cxx_requirements) + $(log_setup_cxx_public_requirements) ; boost-install boost_log boost_log_setup ; diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 91c46ab642..978a6a2052 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -841,7 +840,8 @@ BOOST_LOG_SETUP_API void init_from_settings(basic_settings_section< CharT > cons if (section sink_params = setts["Sinks"]) { sinks_repo_t& sinks_repo = sinks_repo_t::get(); - std::vector< shared_ptr< sinks::sink > > new_sinks; + typedef std::vector< shared_ptr< sinks::sink > > sink_list_t; + sink_list_t new_sinks; for (typename section::const_iterator it = sink_params.begin(), end = sink_params.end(); it != end; ++it) { @@ -854,7 +854,9 @@ BOOST_LOG_SETUP_API void init_from_settings(basic_settings_section< CharT > cons } } - std::for_each(new_sinks.begin(), new_sinks.end(), boost::bind(&core::add_sink, core::get(), boost::placeholders::_1)); + core_ptr core = boost::log::core::get(); + for (sink_list_t::const_iterator it = new_sinks.begin(), end = new_sinks.end(); it != end; ++it) + core->add_sink(*it); } } diff --git a/src/severity_level.cpp b/src/severity_level.cpp index 03f8ebbd4c..9ba01cc287 100644 --- a/src/severity_level.cpp +++ b/src/severity_level.cpp @@ -18,8 +18,6 @@ #include #if !defined(BOOST_LOG_NO_THREADS) && !defined(BOOST_LOG_USE_COMPILER_TLS) -#include -#include #include // at_thread_exit #include #include @@ -66,7 +64,7 @@ BOOST_LOG_API uintmax_t& get_severity_level() log::aux::unique_ptr< uintmax_t > ptr(new uintmax_t(0)); tss.set(ptr.get()); p = ptr.release(); - boost::this_thread::at_thread_exit(boost::bind(checked_deleter< uintmax_t >(), p)); + boost::this_thread::at_thread_exit([p]() { delete p; }); } return *p; } diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 0df9a3722d..bc14713eae 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -30,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -569,19 +568,40 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { if (counter_found) { // Both counter and date/time placeholder in the pattern - file_name_generator = boost::bind(date_and_time_formatter(), - boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1), boost::placeholders::_1); +#if !defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES) + file_name_generator = [date_and_time_fmt = date_and_time_formatter(), file_counter_fmt = file_counter_formatter(counter_pos, width), name_pattern](unsigned int counter) + { return date_and_time_fmt(file_counter_fmt(name_pattern, counter), counter); }; +#else + date_and_time_formatter date_and_time_fmt; + file_counter_formatter file_counter_fmt(counter_pos, width); + file_name_generator = [date_and_time_fmt, file_counter_fmt, name_pattern](unsigned int counter) + { return date_and_time_fmt(file_counter_fmt(name_pattern, counter), counter); }; +#endif } else { // Only date/time placeholders in the pattern - file_name_generator = boost::bind(date_and_time_formatter(), name_pattern, boost::placeholders::_1); +#if !defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES) + file_name_generator = [date_and_time_fmt = date_and_time_formatter(), name_pattern](unsigned int counter) + { return date_and_time_fmt(name_pattern, counter); }; +#else + date_and_time_formatter date_and_time_fmt; + file_name_generator = [date_and_time_fmt, name_pattern](unsigned int counter) + { return date_and_time_fmt(name_pattern, counter); }; +#endif } } else if (counter_found) { // Only counter placeholder in the pattern - file_name_generator = boost::bind(file_counter_formatter(counter_pos, width), name_pattern, boost::placeholders::_1); +#if !defined(BOOST_NO_CXX14_INITIALIZED_LAMBDA_CAPTURES) + file_name_generator = [file_counter_fmt = file_counter_formatter(counter_pos, width), name_pattern](unsigned int counter) + { return file_counter_fmt(name_pattern, counter); }; +#else + file_counter_formatter file_counter_fmt(counter_pos, width); + file_name_generator = [file_counter_fmt, name_pattern](unsigned int counter) + { return file_counter_fmt(name_pattern, counter); }; +#endif } else { @@ -1027,7 +1047,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) file_collectors::iterator it = std::find_if(m_Collectors.begin(), m_Collectors.end(), - boost::bind(&file_collector::is_governed, boost::placeholders::_1, boost::cref(target_dir))); + [&target_dir](file_collector const& collector) { return collector.is_governed(target_dir); }); shared_ptr< file_collector > p; if (it != m_Collectors.end()) try { From a0811c24989bba74c1e72e73a4dcc8854fb90b4a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 2 Oct 2023 01:26:08 +0300 Subject: [PATCH 228/309] Removed dependency on Boost.Array. --- .../type_dispatch/static_type_dispatcher.hpp | 26 ++++++++----------- src/attribute_set_impl.hpp | 18 ++++++------- src/attribute_value_set.cpp | 11 ++++---- 3 files changed, 24 insertions(+), 31 deletions(-) diff --git a/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp b/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp index c78852024d..00fc1ed884 100644 --- a/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp +++ b/include/boost/log/utility/type_dispatch/static_type_dispatcher.hpp @@ -19,7 +19,6 @@ #include #include #include -#include #include #include #include @@ -97,7 +96,7 @@ struct dispatching_map_initializer class type_sequence_dispatcher_base : public type_dispatcher { -private: +protected: //! Dispatching map element type typedef std::pair< typeindex::type_index, void* > dispatching_map_element_type; @@ -155,11 +154,8 @@ class type_sequence_dispatcher : typedef TypeSequenceT supported_types; private: - //! The dispatching map - typedef array< - std::pair< typeindex::type_index, void* >, - mpl::size< supported_types >::value - > dispatching_map; + //! Number of entries in the dispatching map + static BOOST_CONSTEXPR_OR_CONST std::size_t dispatching_map_size = mpl::size< supported_types >::value; public: /*! @@ -167,33 +163,33 @@ class type_sequence_dispatcher : */ template< typename VisitorT > explicit type_sequence_dispatcher(VisitorT& visitor) : - type_sequence_dispatcher_base(get_dispatching_map< VisitorT >().data(), dispatching_map::static_size, (void*)boost::addressof(visitor)) + type_sequence_dispatcher_base(get_dispatching_map< VisitorT >(), dispatching_map_size, (void*)boost::addressof(visitor)) { } private: //! The method returns the dispatching map instance template< typename VisitorT > - static dispatching_map const& get_dispatching_map() + static const dispatching_map_element_type* get_dispatching_map() { - static const dispatching_map* pinstance = NULL; + static const dispatching_map_element_type* pinstance = NULL; BOOST_LOG_ONCE_BLOCK() { - static dispatching_map instance; - typename dispatching_map::value_type* p = &*instance.begin(); + static dispatching_map_element_type instance[dispatching_map_size]; + dispatching_map_element_type* p = instance; typedef typename mpl::begin< supported_types >::type begin_iterator_type; typedef typename mpl::end< supported_types >::type end_iterator_type; typedef dispatching_map_initializer< VisitorT > initializer; initializer::init(static_cast< begin_iterator_type* >(0), static_cast< end_iterator_type* >(0), p); - std::sort(instance.begin(), instance.end(), dispatching_map_order()); + std::sort(instance, instance + dispatching_map_size, dispatching_map_order()); - pinstance = &instance; + pinstance = instance; } - return *pinstance; + return pinstance; } // Copying and assignment closed diff --git a/src/attribute_set_impl.hpp b/src/attribute_set_impl.hpp index 044a8e764f..2cf62f21df 100644 --- a/src/attribute_set_impl.hpp +++ b/src/attribute_set_impl.hpp @@ -17,14 +17,13 @@ #define BOOST_LOG_ATTRIBUTE_SET_IMPL_HPP_INCLUDED_ #include +#include #include #include #include #include #include -#include #include -#include #include #include #include @@ -72,7 +71,7 @@ class pool_allocator : typedef value_type const& const_reference; private: - array< pointer, BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE > m_Pool; + pointer m_Pool[BOOST_LOG_ATTRIBUTE_SET_MAX_POOL_SIZE]; size_type m_PooledCount; public: @@ -130,7 +129,7 @@ class pool_allocator : void deallocate(pointer p, size_type n) { - if (BOOST_LIKELY(m_PooledCount < m_Pool.size())) + if (BOOST_LIKELY(m_PooledCount < (sizeof(m_Pool) / sizeof(*m_Pool)))) { m_Pool[m_PooledCount] = p; ++m_PooledCount; @@ -199,9 +198,6 @@ struct attribute_set::implementation bucket() : first(NULL), last(NULL) {} }; - //! A list of buckets - typedef boost::array< bucket, 1u << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets; - //! Cleanup function object used to erase elements from the container struct disposer { @@ -225,8 +221,10 @@ struct attribute_set::implementation node_list m_Nodes; //! Node allocator node_allocator m_Allocator; + //! Number of buckets in the hash table + static BOOST_CONSTEXPR_OR_CONST std::size_t bucket_count = static_cast< std::size_t >(1u) << BOOST_LOG_HASH_TABLE_SIZE_LOG; //! Hash table buckets - buckets m_Buckets; + bucket m_Buckets[bucket_count]; public: implementation() @@ -262,7 +260,7 @@ struct attribute_set::implementation void clear() { m_Nodes.clear_and_dispose(disposer(m_Allocator)); - std::fill_n(m_Buckets.begin(), m_Buckets.size(), bucket()); + std::fill_n(m_Buckets, bucket_count, bucket()); } std::pair< iterator, bool > insert(key_type key, mapped_type const& data) @@ -365,7 +363,7 @@ struct attribute_set::implementation //! The function returns a bucket for the specified element bucket& get_bucket(id_type id) { - return m_Buckets[id & (buckets::static_size - 1)]; + return m_Buckets[id & (bucket_count - 1u)]; } //! Attempts to find an element with the specified key in the bucket diff --git a/src/attribute_value_set.cpp b/src/attribute_value_set.cpp index 14d9752a73..1db418a623 100644 --- a/src/attribute_value_set.cpp +++ b/src/attribute_value_set.cpp @@ -14,9 +14,9 @@ */ #include +#include #include #include -#include #include #include #include @@ -94,9 +94,6 @@ struct attribute_value_set::implementation bucket() : first(NULL), last(NULL) {} }; - //! A list of buckets - typedef boost::array< bucket, 1u << BOOST_LOG_HASH_TABLE_SIZE_LOG > buckets; - //! Element disposer struct disposer { @@ -125,8 +122,10 @@ struct attribute_value_set::implementation //! The pointer to the end of storage node* m_pEOS; + //! Number of buckets in the hash table + static BOOST_CONSTEXPR_OR_CONST std::size_t bucket_count = static_cast< std::size_t >(1u) << BOOST_LOG_HASH_TABLE_SIZE_LOG; //! Hash table buckets - buckets m_Buckets; + bucket m_Buckets[bucket_count]; private: //! Constructor @@ -318,7 +317,7 @@ struct attribute_value_set::implementation //! The function returns a bucket for the specified element bucket& get_bucket(id_type id) { - return m_Buckets[id & (buckets::static_size - 1u)]; + return m_Buckets[id & (bucket_count - 1u)]; } //! Attempts to find an element with the specified key in the bucket From 9cb9046d2a4ddd2248002a6c8c4ae1c2086fb497 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 2 Oct 2023 01:47:39 +0300 Subject: [PATCH 229/309] Switch to allocator_traits from Boost.Core. --- include/boost/log/detail/allocator_traits.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/include/boost/log/detail/allocator_traits.hpp b/include/boost/log/detail/allocator_traits.hpp index 7716c9ca60..371b802960 100644 --- a/include/boost/log/detail/allocator_traits.hpp +++ b/include/boost/log/detail/allocator_traits.hpp @@ -19,7 +19,8 @@ #include #include #if defined(BOOST_NO_CXX11_ALLOCATOR) -#include +#include +#include #endif #include #include @@ -38,15 +39,14 @@ namespace aux { #if !defined(BOOST_NO_CXX11_ALLOCATOR) using std::allocator_traits; #else -using boost::container::allocator_traits; +using boost::allocator_traits; #endif /*! * \brief A standalone trait to rebind an allocator to another type. * - * The important difference from std::allocator_traits<Alloc>::rebind_alloc<U> is that this - * trait does not require template aliases and thus is compatible with C++03. There is - * boost::container::allocator_traits<Alloc>::portable_rebind_alloc<U>, but it is not present in std::allocator_traits. + * This trait mostly exists to hide differences between std::allocator_traits and boost::allocator_traits + * in terms of allocator rebinding and also provide custom behavior in some cases. */ template< typename Allocator, typename U > struct rebind_alloc @@ -54,7 +54,7 @@ struct rebind_alloc #if !defined(BOOST_NO_CXX11_ALLOCATOR) typedef typename std::allocator_traits< Allocator >::BOOST_NESTED_TEMPLATE rebind_alloc< U > type; #else - typedef typename boost::container::allocator_traits< Allocator >::BOOST_NESTED_TEMPLATE portable_rebind_alloc< U >::type type; + typedef typename boost::allocator_rebind< Allocator, U >::type type; #endif }; From ae9bf80017b881ca7b1575093ec98cf130619492 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 8 Oct 2023 20:51:55 +0300 Subject: [PATCH 230/309] Added a note about deprecation of Windows versions prior to 10. --- doc/changelog.qbk | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 5d526c8b2d..f930816778 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -13,6 +13,7 @@ * C++03 is no longer supported. A C++11 or later compiler is required. * When built with C++11 compilers that are conforming enough for Boost.Regex v5 to be used, Boost.Log no longer links with Boost.Regex prebuilt library, since Boost.Regex v5 is header-only. +* Support for Windows versions older than Windows 10 is deprecated and will be removed in Boost 1.87. [heading 2.27, Boost 1.83] From 07edd2faa33a23c96f6a1c2329c22fcd5b51fd3f Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 Nov 2023 15:05:19 +0300 Subject: [PATCH 231/309] Updated b2 executable name in docs. --- doc/log.qbk | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/log.qbk b/doc/log.qbk index 2cae856362..99e0c42f2b 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -186,7 +186,7 @@ Boost.Log should be compatible with all hardware architectures supported by Boos GCC versions since 4.5 support link time optimization (LTO), when most of optimizations and binary code generation happen at linking stage. This allows to perform more advanced optimizations and produce faster code. Unfortunately, it does not play well with projects containing source files that need to be compiled with different compiler options. Boost.Log is one of such projects, some parts of its sources contain optimizations for modern CPUs and will not run on older CPUs. Enabling LTO for Boost.Log will produce binaries incompatible with older CPUs (GCC bugs [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61043 61043], [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77845 77845]), which will likely result in crashes at run time. For this reason LTO is not supported in Boost.Log. -There is a GCC [@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60607 bug] which may cause compilation failures when `-march=native` command line argument is used. It is recommended to avoid using `-march=native` argument (or `instruction-set=native` bjam property) and instead explicitly specify the target CPU (e.g. `instruction-set=sandy-bridge`). +There is a GCC [@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60607 bug] which may cause compilation failures when `-march=native` command line argument is used. It is recommended to avoid using `-march=native` argument (or `instruction-set=native` b2 property) and instead explicitly specify the target CPU (e.g. `instruction-set=sandy-bridge`). [heading Notes for MinGW, Cygwin and Visual Studio Express Edition users] @@ -194,7 +194,7 @@ In order to compile the library with these compilers special preparations are ne Second, at some point the library will require a Message Compiler tool (`mc.exe`), which is not available in MinGW, Cygwin and some versions of MSVC Express Edition. Typically the library build scripts will automatically detect if message compiler is present on the system and disable Event log related portion of the library if it's not. If Event log support is required and it is not found on the system, you have three options to settle the problem. The recommended solution is to obtain the original `mc.exe`. This tool is available in Windows SDK, which can be downloaded from the Microsoft site freely (for example, [@http://www.microsoft.com/downloads/details.aspx?FamilyID=71deb800-c591-4f97-a900-bea146e4fae1&displaylang=en here]). Also, this tool should be available in Visual Studio 2010 Express Edition. During the compilation, `mc.exe` should be accessible through one of the directories in your `PATH` environment variable. -Another way is to attempt to use the `windmc.exe` tool distributed with MinGW and Cygwin, which is the analogue of the original `mc.exe`. In order to do that you will have to patch Boost.Build files (in particular, the `tools/build/tools/mc.jam` file) as described in [@https://svn.boost.org/trac/boost/ticket/4111 this] ticket. After that you will be able to specify the `mc-compiler=windmc` option to bjam to build the library. +Another way is to attempt to use the `windmc.exe` tool distributed with MinGW and Cygwin, which is the analogue of the original `mc.exe`. In order to do that you will have to patch Boost.Build files (in particular, the `tools/build/tools/mc.jam` file) as described in [@https://svn.boost.org/trac/boost/ticket/4111 this] ticket. After that you will be able to specify the `mc-compiler=windmc` option to b2 to build the library. In case if message compiler detection fails for some reason, you can explicitly disable support for event log backend by defining the `BOOST_LOG_WITHOUT_EVENT_LOG` configuration macro when building the library. This will remove the need for the message compiler. See [link log.installation.config this section] for more configuration options. @@ -233,10 +233,10 @@ The library supports a number of configuration macros: [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.] [Instead of definitng one of these macros, use `BOOST_LOG_USE_REGEX_BACKEND` string option with one of the following values: "std::regex", "Boost.Regex" or "Boost.Xpressive". The macros will be defined accordingly by CMake.]] ] -You can define configuration macros in the `bjam` command line, like this: +You can define configuration macros in the `b2` command line, like this: [pre - bjam --with-log variant=release define=BOOST_LOG_WITHOUT_EVENT_LOG define=BOOST_USE_WINAPI_VERSION=0x0600 stage + b2 --with-log variant=release define=BOOST_LOG_WITHOUT_EVENT_LOG define=BOOST_USE_WINAPI_VERSION=0x0600 stage ] With CMake, the configuration macros can be specified as CMake options in the command line like this: From 8b921b6352e76ff54f5674c864d1f4f749c9158b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 Nov 2023 15:51:14 +0300 Subject: [PATCH 232/309] Removed gcc-4.8 and 4.9 from GHA CI. Added gcc-11 toolchain for clang. Boost.ASIO does not compile in C++11 mode on gcc prior to 5 as it uses std::align. Clang prior to 16 does not support libstdc++13 that is installed in GHA ubuntu-22.04 image by default in C++20 mode. Use libstdc++11 instead. --- .github/workflows/ci.yml | 24 +++++++++++------------- doc/log.qbk | 2 +- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f19f6253c8..2a04eb95ef 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,25 +35,13 @@ jobs: matrix: include: # Linux, gcc - - toolset: gcc-4.8 - cxxstd: "11" - os: ubuntu-latest - container: ubuntu:18.04 - install: - - g++-4.8 - - toolset: gcc-4.9 - cxxstd: "11" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - g++-4.9 - extra_tests: 1 - toolset: gcc-5 cxxstd: "11,14,1z" os: ubuntu-latest container: ubuntu:16.04 install: - g++-5 + extra_tests: 1 - toolset: gcc-6 cxxstd: "11,14,1z" os: ubuntu-latest @@ -193,30 +181,40 @@ jobs: os: ubuntu-22.04 install: - clang-11 + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-12 cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-12 + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-13 cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-13 + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-14 cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-14 + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-15 cxxstd: "11,14,17,20,2b" os: ubuntu-22.04 install: - clang-15 + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-16 cxxstd: "11,14,17,20,2b" diff --git a/doc/log.qbk b/doc/log.qbk index 99e0c42f2b..f5e4fef54f 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -167,7 +167,7 @@ The library should build and work with a reasonably compliant C++11 compiler. Th * Windows 10. MSVC 14.0 and newer. MinGW32 with gcc 5.x and MinGW-w64 with gcc 6.x and newer. * Cygwin and Cygwin64 with gcc 7.x and newer. -* Linux. GCC 4.8 and newer. +* Linux. GCC 5.x and newer. * Linux. Clang 3.5 and newer. The following compilers/platforms are not supported and will likely fail to compile the library: From 609b700a5b139210b9317e4d1153064c43ad7822 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Jan 2024 22:14:53 +0300 Subject: [PATCH 233/309] Removed unneeded Boost.Filesystem include. --- src/text_file_backend.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index bc14713eae..a147518ed0 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include #include From 500d05cb9e55aa43bc22357503d4e3da02cec0e7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Jan 2024 22:27:18 +0300 Subject: [PATCH 234/309] Added Windows jobs to GitHub Actions CI. --- .github/workflows/ci.yml | 93 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a04eb95ef..0646cc84d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# Copyright 2021-2022 Andrey Semashev +# Copyright 2021-2024 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -482,3 +482,94 @@ jobs: cmake -DBUILD_SHARED_LIBS=On ../libs/$LIBRARY/test/test_cmake cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS cmake --build . --target boost_${LIBRARY}_setup_cmake_self_test -j $BUILD_JOBS + + windows: + defaults: + run: + shell: cmd + + strategy: + fail-fast: false + matrix: + include: + - toolset: msvc-14.0 + cxxstd: "14" + os: windows-2019 + extra_tests: 1 + - toolset: msvc-14.2 + cxxstd: "14,17,20,latest" + os: windows-2019 + - toolset: msvc-14.3 + cxxstd: "14,17,20,latest" + os: windows-2022 + - toolset: clang-win + cxxstd: "14,17,latest" + os: windows-2022 + - toolset: gcc + cxxstd: "11-gnu,14-gnu,17-gnu,2a-gnu" + os: windows-2019 + + - name: CMake tests + cmake_tests: 1 + os: windows-2022 + + timeout-minutes: 120 + runs-on: ${{matrix.os}} + + steps: + - uses: actions/checkout@v3 + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% + for /f %%i in ("%GITHUB_REPOSITORY%") do set LIBRARY=%%~nxi + echo LIBRARY: %LIBRARY% + echo LIBRARY=%LIBRARY%>>%GITHUB_ENV% + echo GITHUB_BASE_REF: %GITHUB_BASE_REF% + echo GITHUB_REF: %GITHUB_REF% + if "%GITHUB_BASE_REF%" == "" set GITHUB_BASE_REF=%GITHUB_REF% + set BOOST_BRANCH=develop + for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master + echo BOOST_BRANCH: %BOOST_BRANCH% + cd .. + git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root + cd boost-root + xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + git submodule update --init tools/boostdep + if not "${{matrix.extra_tests}}" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include=example" + python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" %LIBRARY% + if "${{matrix.cmake_tests}}" == "" ( + cmd /c bootstrap + b2 -d0 headers + ) + + - name: Run tests + if: matrix.cmake_tests == '' + run: | + cd ../boost-root + set "B2_ARGS=-j %NUMBER_OF_PROCESSORS% toolset=${{matrix.toolset}} embed-manifest-via=linker" + if not "${{matrix.cxxstd}}" == "" set "B2_ARGS=%B2_ARGS% ^"cxxstd=${{matrix.cxxstd}}^"" + if not "${{matrix.build_variant}}" == "" ( set "B2_ARGS=%B2_ARGS% variant=${{matrix.build_variant}}" ) else ( set "B2_ARGS=%B2_ARGS% variant=%DEFAULT_BUILD_VARIANT%" ) + if not "${{matrix.cxxflags}}" == "" set "B2_ARGS=%B2_ARGS% ^"cxxflags=${{matrix.cxxflags}}^"" + if not "${{matrix.linkflags}}" == "" set "B2_ARGS=%B2_ARGS% ^"linkflags=${{matrix.linkflags}}^"" + if "${{matrix.extra_tests}}" == "" ( + set BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 + set BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 + ) + b2 %B2_ARGS% libs/%LIBRARY%/test + + - name: Run CMake tests + if: matrix.cmake_tests + run: | + cd ../boost-root + mkdir __build_static__ + cd __build_static__ + cmake ../libs/%LIBRARY%/test/test_cmake + cmake --build . --target boost_%LIBRARY%_cmake_self_test -j %NUMBER_OF_PROCESSORS% + cmake --build . --target boost_%LIBRARY%_setup_cmake_self_test -j %NUMBER_OF_PROCESSORS% + cd .. + mkdir __build_shared__ + cd __build_shared__ + cmake -DBUILD_SHARED_LIBS=On ../libs/%LIBRARY%/test/test_cmake + cmake --build . --target boost_%LIBRARY%_cmake_self_test -j %NUMBER_OF_PROCESSORS% + cmake --build . --target boost_%LIBRARY%_setup_cmake_self_test -j %NUMBER_OF_PROCESSORS% From 6bb218f22e32a7af3a3a1bb424fc4920998a393c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 14 Jan 2024 22:36:44 +0300 Subject: [PATCH 235/309] Added clang-17 GHA jobs. --- .github/workflows/ci.yml | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0646cc84d3..6b3a08243f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -226,15 +226,25 @@ jobs: source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang - compiler: clang++-16 - cxxstd: "11,14,17,20,2b" + compiler: clang++-17 + cxxstd: "11,14,17,20,23" os: ubuntu-22.04 install: - - clang-16 - - libc++-16-dev - - libc++abi-16-dev + - clang-17 sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + source_keys: + - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - toolset: clang + compiler: clang++-17 + cxxstd: "11,14,17,20,23" + os: ubuntu-22.04 + install: + - clang-17 + - libc++-17-dev + - libc++abi-17-dev + sources: + - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" cxxflags: -stdlib=libc++ From d30bc4e500f72acadcd3f876e03b1c695240c043 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 6 Feb 2024 00:49:12 +0300 Subject: [PATCH 236/309] Added gcc-13 CI job. --- .github/workflows/ci.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 6b3a08243f..474e825f32 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -80,6 +80,12 @@ jobs: os: ubuntu-22.04 install: - g++-12 + - toolset: gcc-13 + cxxstd: "11,14,17,20,23" + os: ubuntu-latest + container: ubuntu:23.04 + install: + - g++-13 - name: UBSAN toolset: gcc-11 cxxstd: "11,14,17,20,23" From 8d1605728e85ca62fe2d36412df0711075dec777 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 6 Feb 2024 00:50:36 +0300 Subject: [PATCH 237/309] Reduced CI job timeouts. --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 474e825f32..f1c288a696 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -277,7 +277,7 @@ jobs: cmake_tests: 1 os: ubuntu-20.04 - timeout-minutes: 120 + timeout-minutes: 60 runs-on: ${{matrix.os}} container: ${{matrix.container}} @@ -529,7 +529,7 @@ jobs: cmake_tests: 1 os: windows-2022 - timeout-minutes: 120 + timeout-minutes: 60 runs-on: ${{matrix.os}} steps: From b9c4024c0dbf376c30f877d8a502ef066fd6316a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 6 Feb 2024 00:54:48 +0300 Subject: [PATCH 238/309] Replaced actions/checkout usage with manual download commands. This fixes the deprecation warnings for actions/checkout@v3. actions/checkout@v4 is not functional because of the upstream bug: https://github.com/actions/checkout/issues/1590 --- .github/workflows/ci.yml | 46 ++++++++++++++++++++++++++++++---------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f1c288a696..0d418a4a03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -306,8 +306,6 @@ jobs: fi git config --global pack.threads 0 - - uses: actions/checkout@v3 - - name: Install packages if: matrix.install run: | @@ -422,11 +420,25 @@ jobs: then DEPINST_ARGS+=("--git_args" "--jobs $GIT_FETCH_JOBS") fi + mkdir -p snapshot + cd snapshot + echo "Downloading library snapshot: https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" + curl -L --retry "$NET_RETRY_COUNT" -o "${LIBRARY}-${GITHUB_SHA}.tar.gz" "https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" + tar -xf "${LIBRARY}-${GITHUB_SHA}.tar.gz" + if [ ! -d "${LIBRARY}-${GITHUB_SHA}" ] + then + echo "Library snapshot does not contain the library directory ${LIBRARY}-${GITHUB_SHA}:" + ls -la + exit 1 + fi + rm -f "${LIBRARY}-${GITHUB_SHA}.tar.gz" cd .. git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" cd boost-root - mkdir -p libs/$LIBRARY - cp -r $GITHUB_WORKSPACE/* libs/$LIBRARY + mkdir -p libs + rm -rf "libs/$LIBRARY" + mv -f "../snapshot/${LIBRARY}-${GITHUB_SHA}" "libs/$LIBRARY" + rm -rf "../snapshot" git submodule update --init tools/boostdep if [ -n "${{matrix.extra_tests}}" ] then @@ -452,7 +464,7 @@ jobs: - name: Run tests if: matrix.cmake_tests == '' run: | - cd ../boost-root + cd boost-root if [ -z "${{matrix.extra_tests}}" ] then export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 @@ -488,7 +500,7 @@ jobs: - name: Run CMake tests if: matrix.cmake_tests run: | - cd ../boost-root + cd boost-root mkdir __build_static__ && cd __build_static__ cmake ../libs/$LIBRARY/test/test_cmake cmake --build . --target boost_${LIBRARY}_cmake_self_test -j $BUILD_JOBS @@ -533,8 +545,6 @@ jobs: runs-on: ${{matrix.os}} steps: - - uses: actions/checkout@v3 - - name: Setup Boost run: | echo GITHUB_REPOSITORY: %GITHUB_REPOSITORY% @@ -547,10 +557,24 @@ jobs: set BOOST_BRANCH=develop for /f %%i in ("%GITHUB_BASE_REF%") do if "%%~nxi" == "master" set BOOST_BRANCH=master echo BOOST_BRANCH: %BOOST_BRANCH% + mkdir snapshot + cd snapshot + echo Downloading library snapshot: https://github.com/%GITHUB_REPOSITORY%/archive/%GITHUB_SHA%.zip + curl -L --retry %NET_RETRY_COUNT% -o "%LIBRARY%-%GITHUB_SHA%.zip" "https://github.com/%GITHUB_REPOSITORY%/archive/%GITHUB_SHA%.zip" + tar -xf "%LIBRARY%-%GITHUB_SHA%.zip" + if not exist "%LIBRARY%-%GITHUB_SHA%\" ( + echo Library snapshot does not contain the library directory %LIBRARY%-%GITHUB_SHA%: + dir + exit /b 1 + ) + del /f "%LIBRARY%-%GITHUB_SHA%.zip" cd .. git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root cd boost-root - xcopy /s /e /q %GITHUB_WORKSPACE% libs\%LIBRARY%\ + if not exist "libs\" mkdir libs + if exist "libs\%LIBRARY%\" rmdir /s /q "libs\%LIBRARY%" + move /Y "..\snapshot\%LIBRARY%-%GITHUB_SHA%" "libs\%LIBRARY%" + rmdir /s /q "..\snapshot" git submodule update --init tools/boostdep if not "${{matrix.extra_tests}}" == "" set DEPINST_ARG_INCLUDE_EXAMPLES="--include=example" python tools/boostdep/depinst/depinst.py %DEPINST_ARG_INCLUDE_EXAMPLES% --git_args "--jobs %GIT_FETCH_JOBS%" %LIBRARY% @@ -562,7 +586,7 @@ jobs: - name: Run tests if: matrix.cmake_tests == '' run: | - cd ../boost-root + cd boost-root set "B2_ARGS=-j %NUMBER_OF_PROCESSORS% toolset=${{matrix.toolset}} embed-manifest-via=linker" if not "${{matrix.cxxstd}}" == "" set "B2_ARGS=%B2_ARGS% ^"cxxstd=${{matrix.cxxstd}}^"" if not "${{matrix.build_variant}}" == "" ( set "B2_ARGS=%B2_ARGS% variant=${{matrix.build_variant}}" ) else ( set "B2_ARGS=%B2_ARGS% variant=%DEFAULT_BUILD_VARIANT%" ) @@ -577,7 +601,7 @@ jobs: - name: Run CMake tests if: matrix.cmake_tests run: | - cd ../boost-root + cd boost-root mkdir __build_static__ cd __build_static__ cmake ../libs/%LIBRARY%/test/test_cmake From 0b09e69c45454b0e3427dfa46fd59a46b7106baa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 7 Feb 2024 00:01:09 +0300 Subject: [PATCH 239/309] Removed MinGW32 AppVeyor job. This compiler is no longer supported by Boost.System. https://github.com/boostorg/system/issues/116 --- appveyor.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 18a79c9834..417b06c001 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -70,11 +70,6 @@ environment: CXXSTD: 11 ADDPATH: C:\cygwin\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - - TOOLSET: gcc - ADDRESS_MODEL: 32 - CXXSTD: 11 - ADDPATH: C:\mingw\bin - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 32 CXXSTD: 11,14 From d9d1f59375465a26f0a878365e29a2cadb40ba84 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 2 Mar 2024 15:25:41 +0300 Subject: [PATCH 240/309] Moved How to read and Definitions to the front page of the docs. This makes these sections better exposed to an impatient reader, as that information is useful for better understanding of the rest of the docs. Also extracted installation sections to a separate file. Related to https://github.com/boostorg/log/issues/226. --- doc/install.qbk | 138 +++++++++++++++++++++++++++++++++ doc/intro.qbk | 71 +++++++++++++++++ doc/log.qbk | 193 +--------------------------------------------- doc/rationale.qbk | 2 +- 4 files changed, 213 insertions(+), 191 deletions(-) create mode 100644 doc/install.qbk create mode 100644 doc/intro.qbk diff --git a/doc/install.qbk b/doc/install.qbk new file mode 100644 index 0000000000..eecad7e4b6 --- /dev/null +++ b/doc/install.qbk @@ -0,0 +1,138 @@ +[/ + Copyright Andrey Semashev 2024. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + This document is a part of Boost.Log library documentation. +/] + +[section:installation Installation and compatibility] + +[section:supported_compilers Supported compilers and platforms] + +The library should build and work with a reasonably compliant C++11 compiler. The library was successfully built and tested on the following platforms: + +* Windows 10. MSVC 14.0 and newer. MinGW32 with gcc 5.x and MinGW-w64 with gcc 6.x and newer. +* Cygwin and Cygwin64 with gcc 7.x and newer. +* Linux. GCC 5.x and newer. +* Linux. Clang 3.5 and newer. + +The following compilers/platforms are not supported and will likely fail to compile the library: + +* Compilers that do not support C++11. +* C++11 compilers with non-C++11 standard libraries (like Clang with libstdc++ from GCC 4.2). Please, use a C++11 standard library in C++11 mode. +* MSVC 12.0 and older. +* GCC 4.4 and older. +* Borland C++ 5.5.1 (free version). Newer versions might or might not work. +* Solaris Studio 12.3 and older. +* Windows 9x, ME, NT4, 2000 and older are not supported. + +Boost.Log should be compatible with all hardware architectures supported by Boost. However, in case of 32 bit x86 architecture the library requires at least i586 class CPU to run. + +[heading Notes for GCC users] + +GCC versions since 4.5 support link time optimization (LTO), when most of optimizations and binary code generation happen at linking stage. This allows to perform more advanced optimizations and produce faster code. Unfortunately, it does not play well with projects containing source files that need to be compiled with different compiler options. Boost.Log is one of such projects, some parts of its sources contain optimizations for modern CPUs and will not run on older CPUs. Enabling LTO for Boost.Log will produce binaries incompatible with older CPUs (GCC bugs [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61043 61043], [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77845 77845]), which will likely result in crashes at run time. For this reason LTO is not supported in Boost.Log. + +There is a GCC [@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60607 bug] which may cause compilation failures when `-march=native` command line argument is used. It is recommended to avoid using `-march=native` argument (or `instruction-set=native` b2 property) and instead explicitly specify the target CPU (e.g. `instruction-set=sandy-bridge`). + +[heading Notes for MinGW, Cygwin and Visual Studio Express Edition users] + +In order to compile the library with these compilers special preparations are needed. First, in case of MinGW or Cygwin make sure you have installed the latest GCC version. The library will most likely fail to compile with GCC 3.x. + +Second, at some point the library will require a Message Compiler tool (`mc.exe`), which is not available in MinGW, Cygwin and some versions of MSVC Express Edition. Typically the library build scripts will automatically detect if message compiler is present on the system and disable Event log related portion of the library if it's not. If Event log support is required and it is not found on the system, you have three options to settle the problem. The recommended solution is to obtain the original `mc.exe`. This tool is available in Windows SDK, which can be downloaded from the Microsoft site freely (for example, [@http://www.microsoft.com/downloads/details.aspx?FamilyID=71deb800-c591-4f97-a900-bea146e4fae1&displaylang=en here]). Also, this tool should be available in Visual Studio 2010 Express Edition. During the compilation, `mc.exe` should be accessible through one of the directories in your `PATH` environment variable. + +Another way is to attempt to use the `windmc.exe` tool distributed with MinGW and Cygwin, which is the analogue of the original `mc.exe`. In order to do that you will have to patch Boost.Build files (in particular, the `tools/build/tools/mc.jam` file) as described in [@https://svn.boost.org/trac/boost/ticket/4111 this] ticket. After that you will be able to specify the `mc-compiler=windmc` option to b2 to build the library. + +In case if message compiler detection fails for some reason, you can explicitly disable support for event log backend by defining the `BOOST_LOG_WITHOUT_EVENT_LOG` configuration macro when building the library. This will remove the need for the message compiler. See [link log.installation.config this section] for more configuration options. + +MinGW users on Windows XP may be affected by the [@http://sourceforge.net/p/mingw-w64/bugs/307/ bug] in msvcrt.dll that is bundled with the operating system. The bug manifests itself as crashes while the library formats log records. This problem is not specific to Boost.Log and may also show in different contexts related to locale and IO-streams management. + +[heading Additional notes for Cygwin users] + +Cygwin support is very preliminary. The default GCC version available in Cygwin (4.5.3 as of this writing) is unable to compile the library because of compiler errors. You will have to build a newer GCC from sources. Even then some Boost.Log functionality is not available. In particular, the socket-based syslog backend is not supported, as it is based on __boost_asio__, which doesn't compile on this platform. However, the native syslog support is still in place. + +[endsect] + +[section:config Configuring and building the library] + +The library has a separately compiled part which should be built as described in the [@http://www.boost.org/doc/libs/release/more/getting_started/ Getting Started guide]. One thing should be noted, though. If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library _must_ be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library. + +The library supports a number of configuration macros: + +[table Configuration macros + [[Macro name] [Effect] [CMake notes]] + [[`BOOST_LOG_DYN_LINK`] [If defined in user code, the library will assume the binary is built as a dynamically loaded library ("dll" or "so"). Otherwise it is assumed that the library is built in static mode. This macro must be either defined or not defined for all translation units of user application that uses logging. This macro can help with auto-linking on platforms that support it.] [Defined automatically depending on `BUILD_SHARED_LIBS` CMake option.]] + [[`BOOST_ALL_DYN_LINK`] [Same as `BOOST_LOG_DYN_LINK` but also affects other Boost libraries the same way.] []] + [[`BOOST_USE_WINAPI_VERSION`] [Affects compilation of both the library and user's code. This macro is Windows-specific. Selects the target Windows version for various Boost libraries, including Boost.Log. Code compiled for a particular Windows version will likely fail to run on the older Windows versions, but may improve performance because of using newer OS features. The macro is expected to have an integer value equivalent to [@https://msdn.microsoft.com/en-us/library/6sehtctf.aspx `_WIN32_WINNT`].] []] + [[`BOOST_LOG_NO_THREADS`] [If defined, disables multithreading support. Affects the compilation of both the library and users' code. The macro is automatically defined if no threading support is detected.] []] + [[`BOOST_LOG_WITHOUT_CHAR`] [If defined, disables support for narrow character logging. Affects the compilation of both the library and users' code.] []] + [[`BOOST_LOG_WITHOUT_WCHAR_T`] [If defined, disables support for wide character logging. Affects the compilation of both the library and users' code.] []] + [[`BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER`] [This macro is only useful on Windows. It affects the compilation of both the library and users' code. If defined, disables support for the `QueryPerformanceCounter` API in the `timer` attribute. This will result in significantly less accurate time readings. The macro is intended to solve possible problems with earlier revisions of AMD Athlon CPU, described [@http://support.microsoft.com/?scid=kb;en-us;895980 here] and [@http://support.microsoft.com/?id=896256 here]. There are also known chipset hardware failures that may prevent this API from functioning properly (see [@http://support.microsoft.com/kb/274323 here]).] []] + [[`BOOST_LOG_USE_NATIVE_SYSLOG`] [Affects only compilation of the library. If for some reason support for the native SysLog API is not detected automatically, define this macro to forcibly enable it.] []] + [[`BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`] [Affects only compilation of the library. If defined, the parsers for settings will be built without any default factories for filters and formatters. The user will have to register all attributes in the library before parsing any filters or formatters from strings. This can substantially reduce the binary size.] []] + [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.] [Disables compilation of the `boost_log_setup` library.]] + [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only compilation of the library. If defined, the support for debugger output on Windows will not be built.] []] + [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.] []] + [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for syslog backend will not be built.] []] + [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for interprocess queues will not be built.] []] + [[`BOOST_LOG_NO_SHORTHAND_NAMES`] [Affects only compilation of users' code. If defined, some deprecated shorthand macro names will not be available.] [Not a CMake configuration option.]] + [[`BOOST_LOG_USE_COMPILER_TLS`] [Affects only compilation of the library. This macro enables support for compiler intrinsics for thread-local storage. Defining it may improve performance of Boost.Log if certain usage limitations are acceptable. See below for more comments.] []] + [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.] [Instead of definitng one of these macros, use `BOOST_LOG_USE_REGEX_BACKEND` string option with one of the following values: "std::regex", "Boost.Regex" or "Boost.Xpressive". The macros will be defined accordingly by CMake.]] +] + +You can define configuration macros in the `b2` command line, like this: + +[pre + b2 --with-log variant=release define=BOOST_LOG_WITHOUT_EVENT_LOG define=BOOST_USE_WINAPI_VERSION=0x0600 stage +] + +With CMake, the configuration macros can be specified as CMake options in the command line like this: + +[pre + cmake .. -DCMAKE_BUILD_TYPE=Release -DBOOST_LOG_WITHOUT_EVENT_LOG=On +] + +However, it may be more convenient to define configuration macros in the "boost/config/user.hpp" file in order to automatically define them both for the library and user's projects. If none of the options are specified, the library will try to support the most comprehensive setup, including support for all character types and features available for the target platform. + +The logging library uses several other Boost libraries that require building too. These are __boost_filesystem__, __boost_system__, __boost_date_time__, __boost_thread__ and in some configurations __boost_regex__. Refer to their documentation for detailed instructions on the building procedure. + +One final thing should be added. The library requires run-time type information (RTTI) to be enabled for both the library compilation and user's code compilation. Normally, this won't need anything from you except to verify that RTTI support is not disabled in your project. + +[heading Notes about compiler-supplied intrinsics for TLS] + +Many widely used compilers support builtin intrinsics for managing thread-local storage, which is used in several parts of the library. This feature is also included in the C++11 standard. Generally, these intrinsics allow for a much more efficient access to the storage than any surrogate implementation, be that __boost_thread__ or even native operating system API. However, this feature has several caveats: + +* Some operating systems don't support the use of these intrinsics in case if the TLS is defined in a shared library that is dynamically loaded during the application run time. These systems include Linux and Windows prior to Vista. Windows Vista and later do not have this issue. +* The TLS may not be reliably accessed from global constructors and destructors. At least MSVC 8.0 on Windows is known to have this problem. + +The library provides the `BOOST_LOG_USE_COMPILER_TLS` configuration macro that allows to enable the use of this feature, which will improve the library performance at the cost of these limitations: + +* The application executable must be linked with the Boost.Log library. It should not be loaded dynamically during run time. +* The application must not use logging in global constructors or destructors. + +Note that the `BOOST_LOG_USE_COMPILER_TLS` macro only controls use of TLS in Boost.Log but not in other libraries used by Boost.Log. For example, __boost_asio__ uses compiler-supplied TLS by default. In order to build Boost.Log binaries completely free from use of compiler-supplied TLS, this feature has to be disabled in those other libraries as well (in case of __boost_asio__ this can be achieved by defining `BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION` when building and using Boost). + +Also note that enabling builtin compiler support for TLS does not remove the dependency on __boost_thread__ or lower level OS threading primitives, including those implementing TLS. The purpose of using compiler intrinsics for TLS is better performance rather than reducing dependencies. + +[heading Notes about native `wchar_t` support] + +Some compilers, most notably MSVC, have an option to disable the native `wchar_t` type, emulating it with a typedef for one of the standard integral types. From the C++ language perspective this behavior is not conforming but it may be useful for compatibility with some legacy code which is difficult to update. + +By default, Boost (and Boost.Log being part of it) is built with native `wchar_t` enabled. At the time of this writing, user will have to modify Boost.Build to enable the emulation mode. It is possible to build Boost.Log in this mode, but there are several caveats that have to be kept in mind: + +* The compiled Boost.Log binaries will be exporting symbols corresponding to the configuration chosen at build time. The user's code will have to use the same setting as was used when building Boost.Log, otherwise linking errors will appear. +* Since in emulation mode `wchar_t` is undistinguishable from one of the integer types, certain parts of the library may behave differently from the normal mode with native `wchar_t`. In particular, wide-character literals may be rejected or formatted differently. +* The emulation mode is not tested, so unexpected breakages are possible. + +Because of that using the emulation mode is discouraged and should be avoided. In future releases of the library its support may be removed completely. + +[heading Notes for CMake users on Windows] + +In order to compile Boost.Log with event log support on Windows using CMake, the initial CMake configuration should be performed with resource (`rc.exe` or `windres.exe`) and message compiler tools (`mc.exe` or `windmc.exe`) available in `PATH` environment variable. With MSVC, it is recommended to run CMake in the Visual Studio command line or otherwise ensure that Windows SDK environment variables are set. + +Alternatively, users may set `RC` and `MC` environment variables to paths of the resource and message compiler executables, respectively, or set `CMAKE_RC_COMPILER` and `CMAKE_MC_COMPILER` CMake options to the corresponding paths in the command line. + +[endsect] + +[endsect] diff --git a/doc/intro.qbk b/doc/intro.qbk new file mode 100644 index 0000000000..337307747c --- /dev/null +++ b/doc/intro.qbk @@ -0,0 +1,71 @@ +[/ + Copyright Andrey Semashev 2024. + Distributed under the Boost Software License, Version 1.0. + (See accompanying file LICENSE_1_0.txt or copy at + http://www.boost.org/LICENSE_1_0.txt) + + This document is a part of Boost.Log library documentation. +/] + +[section:intro Introduction] + +[section:moti Motivation] + +Today applications grow rapidly, becoming complicated and difficult to test and debug. Most of the time applications run on a remote site, leaving the developer little chance to monitor their execution and figure out the reasons for their failure, once it should happen. Moreover, even the local debugging may become problematic if the application behavior depends heavily on asynchronous side events, such as a device feedback or another process activity. + +This is where logging can help. The application stores all essential information about its execution to a log, and when something goes wrong this information can be used to analyze the program behavior and make the necessary corrections. There are other very useful applications of logging, such as gathering statistical information and highlighting events (i.e. indicating that some situation has occurred or that the application is experiencing some problems). These tasks have proved to be vital for many real-world industrial applications. + +This library aims to make logging significantly easier for the application developer. It provides a wide range of out-of-the-box tools along with public interfaces for extending the library. The main goals of the library are: + +* Simplicity. A small example code snippet should be enough to get the feel of the library and be ready to use its basic features. +* Extensibility. A user should be able to extend functionality of the library for collecting and storing information into logs. +* Performance. The library should have as little performance impact on the user's application as possible. + +[endsect] + +[section:how_to_read How to read the documentation] + +The documentation is oriented to both new and experienced library users. However, users are expected to be familiar with commonly used Boost components, such as `shared_ptr`, `make_shared` (see __boost_smart_ptr__), and `function` (__boost_function__). Some parts of the documentation will refer to other Boost libraries, as needed. + +If this is your first experience with the library, it is recommended to read the [link log.design Design overview] section for a first glance at the library's capabilities and architecture. The [link log.installation Installation] and [link log.tutorial Tutorial] sections will help to get started experimenting with the library. The tutorial gives an overview of the library features with sample code snippets. Some tutorial steps are presented in two forms: simple and advanced. The simple form typically describes the most common and easy way to do the task and it is being recommended to be read by new users. The advanced form usually gives an expanded way to do the same thing but with an in-depth explanation and the ability to do some extra customization. This form may come in handy for more experienced users and should generally be read if the easy way does not satisfy your needs. + +Besides the tutorial there is a [link log.detailed Detailed features description] chapter. This part describes other tools provided by the library that were not covered by the tutorial. This chapter is best read on a case by case basis. + +Last, but not least, there is a [link log.reference Reference] section which gives the formal description of library component interfaces. + +To keep the code snippets in this documentation simple, the following namespace aliases are assumed to be defined: + + namespace logging = boost::log; + namespace sinks = boost::log::sinks; + namespace src = boost::log::sources; + namespace expr = boost::log::expressions; + namespace attrs = boost::log::attributes; + namespace keywords = boost::log::keywords; + +Note that most of the examples are followed by a link to a complete compilable code sample, with all the necessary includes and auxiliary code, if any, that was stripped from the documentation for brevity. Relevant includes are also listed at the beginning of sections. + +[endsect] + +[section:defs Definitions] + +Here are definitions of some terms that will be used widely throughout the documentation: + +[variablelist + [[Log record][A single bundle of information, collected from the user's application, that is a candidate to be put into the log. In a simple case the log record will be represented as a line of text in the log file after being processed by the logging library.]] + [[Attribute][An "attribute" is a piece of meta-information that can be used to specialize a log record. In Boost.Log, attributes are represented by function objects with a specific interface, which return the actual attribute value when invoked. Some example of attributes are a function returning current clock time, a function returning a monotonously increading log record counter, etc.]] + [[Attribute value][Attribute values are the actual data acquired from attributes. This data is attached to the specific log record and processed by the library. Values can have different types (integers, strings and more complex, including user defined types). Some examples of attribute values: current time stamp value, file name, line number, current scope name, etc. Attribute values are enveloped in a type erasing wrapper, so the actual type of the attribute is not visible in the interface. The actual (erased) type of the value is sometimes called the stored type.]] + [[(Attribute) value visitation][A way of processing the attribute value. This approach involves a function object (a visitor) which is applied to the attribute value. The visitor should know the stored type of the attribute value in order to process it.]] + [[(Attribute) value extraction][A way of processing the attribute value when the caller attempts to obtain a reference to the stored value. The caller should know the stored type of the attribute value in order to be able to extract it.]] + [[Log source][An entry point for the user's application to put log records to. In a simple case it is an object (logger) which maintains a set of attributes that will be used to form a log record upon the user's request. However, one can surely create a source that would emit log records on some side events (for example, by intercepting and parsing console output of another application).]] + [[Log sink][A target, to which all log records are fed after being collected from the user's application. The sink defines where and how the log records are going to be stored or processed.]] + [[Log filter][A predicate that takes a log record and tells whether this record should be passed through for further processing or discarded. The predicate typically forms its decision based on the attribute values attached to the record.]] + [[Log formatter][A function object that generates the final textual output from a log record. Some sinks, e.g. a binary logging sink, may not need it, although almost any text-based sink would use a formatter to compose its output.]] + [[Logging core][A global entity that maintains a list of sinks and applies filters to records generated by log sources. In the user's application, it is mainly used when the logging library is configured. There is only one instance of the logging core in an application.]] + [[i18n][Internationalization. The ability to manipulate wide characters.]] + [[TLS][Thread-local storage. The concept of having a variable that has independent values for each thread that attempts to access it.]] + [[RTTI][Run-time type information. This is the C++ language support data structures required for `dynamic_cast` and `typeid` operators to function properly.]] +] + +[endsect] + +[endsect] diff --git a/doc/log.qbk b/doc/log.qbk index f5e4fef54f..64b7557fc4 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -2,7 +2,7 @@ [quickbook 1.5] [version v2] [authors [Semashev, Andrey]] - [copyright 2007 - 2022 Andrey Semashev] + [copyright 2007 - 2024 Andrey Semashev] [license Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -10,7 +10,6 @@ ] [id log] [source-mode c++] - [last-revision $Date$] ] [c++] @@ -124,195 +123,9 @@ [import ../example/wide_char/main.cpp] [import ../example/event_log/main.cpp] -[section:moti Motivation] - -Today applications grow rapidly, becoming complicated and difficult to test and debug. Most of the time applications run on a remote site, leaving the developer little chance to monitor their execution and figure out the reasons for their failure, once it should happen. Moreover, even the local debugging may become problematic if the application behavior depends heavily on asynchronous side events, such as a device feedback or another process activity. - -This is where logging can help. The application stores all essential information about its execution to a log, and when something goes wrong this information can be used to analyze the program behavior and make the necessary corrections. There are other very useful applications of logging, such as gathering statistical information and highlighting events (i.e. indicating that some situation has occurred or that the application is experiencing some problems). These tasks have proved to be vital for many real-world industrial applications. - -This library aims to make logging significantly easier for the application developer. It provides a wide range of out-of-the-box tools along with public interfaces for extending the library. The main goals of the library are: - -* Simplicity. A small example code snippet should be enough to get the feel of the library and be ready to use its basic features. -* Extensibility. A user should be able to extend functionality of the library for collecting and storing information into logs. -* Performance. The library should have as little performance impact on the user's application as possible. - -[endsect] - -[section:how_to_read How to read the documentation] - -The documentation is oriented to both new and experienced library users. However, users are expected to be familiar with commonly used Boost components, such as `shared_ptr`, `make_shared` (see __boost_smart_ptr__), and `function` (__boost_function__). Some parts of the documentation will refer to other Boost libraries, as needed. - -If this is your first experience with the library, it is recommended to read the [link log.design Design overview] section for a first glance at the library's capabilities and architecture. The [link log.installation Installation] and [link log.tutorial Tutorial] sections will help to get started experimenting with the library. The tutorial gives an overview of the library features with sample code snippets. Some tutorial steps are presented in two forms: simple and advanced. The simple form typically describes the most common and easy way to do the task and it is being recommended to be read by new users. The advanced form usually gives an expanded way to do the same thing but with an in-depth explanation and the ability to do some extra customization. This form may come in handy for more experienced users and should generally be read if the easy way does not satisfy your needs. - -Besides the tutorial there is a [link log.detailed Detailed features description] chapter. This part describes other tools provided by the library that were not covered by the tutorial. This chapter is best read on a case by case basis. - -Last, but not least, there is a reference which gives the formal description of library components. - -To keep the code snippets in this documentation simple, the following namespace aliases are assumed to be defined: - - namespace logging = boost::log; - namespace sinks = boost::log::sinks; - namespace src = boost::log::sources; - namespace expr = boost::log::expressions; - namespace attrs = boost::log::attributes; - namespace keywords = boost::log::keywords; - -[endsect] - -[section:installation Installation and compatibility] - -[section:supported_compilers Supported compilers and platforms] - -The library should build and work with a reasonably compliant C++11 compiler. The library was successfully built and tested on the following platforms: - -* Windows 10. MSVC 14.0 and newer. MinGW32 with gcc 5.x and MinGW-w64 with gcc 6.x and newer. -* Cygwin and Cygwin64 with gcc 7.x and newer. -* Linux. GCC 5.x and newer. -* Linux. Clang 3.5 and newer. - -The following compilers/platforms are not supported and will likely fail to compile the library: - -* Compilers that do not support C++11. -* C++11 compilers with non-C++11 standard libraries (like Clang with libstdc++ from GCC 4.2). Please, use a C++11 standard library in C++11 mode. -* MSVC 12.0 and older. -* GCC 4.4 and older. -* Borland C++ 5.5.1 (free version). Newer versions might or might not work. -* Solaris Studio 12.3 and older. -* Windows 9x, ME, NT4, 2000 and older are not supported. - -Boost.Log should be compatible with all hardware architectures supported by Boost. However, in case of 32 bit x86 architecture the library requires at least i586 class CPU to run. - -[heading Notes for GCC users] - -GCC versions since 4.5 support link time optimization (LTO), when most of optimizations and binary code generation happen at linking stage. This allows to perform more advanced optimizations and produce faster code. Unfortunately, it does not play well with projects containing source files that need to be compiled with different compiler options. Boost.Log is one of such projects, some parts of its sources contain optimizations for modern CPUs and will not run on older CPUs. Enabling LTO for Boost.Log will produce binaries incompatible with older CPUs (GCC bugs [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61043 61043], [@https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77845 77845]), which will likely result in crashes at run time. For this reason LTO is not supported in Boost.Log. - -There is a GCC [@http://gcc.gnu.org/bugzilla/show_bug.cgi?id=60607 bug] which may cause compilation failures when `-march=native` command line argument is used. It is recommended to avoid using `-march=native` argument (or `instruction-set=native` b2 property) and instead explicitly specify the target CPU (e.g. `instruction-set=sandy-bridge`). - -[heading Notes for MinGW, Cygwin and Visual Studio Express Edition users] - -In order to compile the library with these compilers special preparations are needed. First, in case of MinGW or Cygwin make sure you have installed the latest GCC version. The library will most likely fail to compile with GCC 3.x. - -Second, at some point the library will require a Message Compiler tool (`mc.exe`), which is not available in MinGW, Cygwin and some versions of MSVC Express Edition. Typically the library build scripts will automatically detect if message compiler is present on the system and disable Event log related portion of the library if it's not. If Event log support is required and it is not found on the system, you have three options to settle the problem. The recommended solution is to obtain the original `mc.exe`. This tool is available in Windows SDK, which can be downloaded from the Microsoft site freely (for example, [@http://www.microsoft.com/downloads/details.aspx?FamilyID=71deb800-c591-4f97-a900-bea146e4fae1&displaylang=en here]). Also, this tool should be available in Visual Studio 2010 Express Edition. During the compilation, `mc.exe` should be accessible through one of the directories in your `PATH` environment variable. - -Another way is to attempt to use the `windmc.exe` tool distributed with MinGW and Cygwin, which is the analogue of the original `mc.exe`. In order to do that you will have to patch Boost.Build files (in particular, the `tools/build/tools/mc.jam` file) as described in [@https://svn.boost.org/trac/boost/ticket/4111 this] ticket. After that you will be able to specify the `mc-compiler=windmc` option to b2 to build the library. - -In case if message compiler detection fails for some reason, you can explicitly disable support for event log backend by defining the `BOOST_LOG_WITHOUT_EVENT_LOG` configuration macro when building the library. This will remove the need for the message compiler. See [link log.installation.config this section] for more configuration options. - -MinGW users on Windows XP may be affected by the [@http://sourceforge.net/p/mingw-w64/bugs/307/ bug] in msvcrt.dll that is bundled with the operating system. The bug manifests itself as crashes while the library formats log records. This problem is not specific to Boost.Log and may also show in different contexts related to locale and IO-streams management. - -[heading Additional notes for Cygwin users] - -Cygwin support is very preliminary. The default GCC version available in Cygwin (4.5.3 as of this writing) is unable to compile the library because of compiler errors. You will have to build a newer GCC from sources. Even then some Boost.Log functionality is not available. In particular, the socket-based syslog backend is not supported, as it is based on __boost_asio__, which doesn't compile on this platform. However, the native syslog support is still in place. - -[endsect] - -[section:config Configuring and building the library] - -The library has a separately compiled part which should be built as described in the [@http://www.boost.org/doc/libs/release/more/getting_started/ Getting Started guide]. One thing should be noted, though. If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library _must_ be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library. - -The library supports a number of configuration macros: - -[table Configuration macros - [[Macro name] [Effect] [CMake notes]] - [[`BOOST_LOG_DYN_LINK`] [If defined in user code, the library will assume the binary is built as a dynamically loaded library ("dll" or "so"). Otherwise it is assumed that the library is built in static mode. This macro must be either defined or not defined for all translation units of user application that uses logging. This macro can help with auto-linking on platforms that support it.] [Defined automatically depending on `BUILD_SHARED_LIBS` CMake option.]] - [[`BOOST_ALL_DYN_LINK`] [Same as `BOOST_LOG_DYN_LINK` but also affects other Boost libraries the same way.] []] - [[`BOOST_USE_WINAPI_VERSION`] [Affects compilation of both the library and user's code. This macro is Windows-specific. Selects the target Windows version for various Boost libraries, including Boost.Log. Code compiled for a particular Windows version will likely fail to run on the older Windows versions, but may improve performance because of using newer OS features. The macro is expected to have an integer value equivalent to [@https://msdn.microsoft.com/en-us/library/6sehtctf.aspx `_WIN32_WINNT`].] []] - [[`BOOST_LOG_NO_THREADS`] [If defined, disables multithreading support. Affects the compilation of both the library and users' code. The macro is automatically defined if no threading support is detected.] []] - [[`BOOST_LOG_WITHOUT_CHAR`] [If defined, disables support for narrow character logging. Affects the compilation of both the library and users' code.] []] - [[`BOOST_LOG_WITHOUT_WCHAR_T`] [If defined, disables support for wide character logging. Affects the compilation of both the library and users' code.] []] - [[`BOOST_LOG_NO_QUERY_PERFORMANCE_COUNTER`] [This macro is only useful on Windows. It affects the compilation of both the library and users' code. If defined, disables support for the `QueryPerformanceCounter` API in the `timer` attribute. This will result in significantly less accurate time readings. The macro is intended to solve possible problems with earlier revisions of AMD Athlon CPU, described [@http://support.microsoft.com/?scid=kb;en-us;895980 here] and [@http://support.microsoft.com/?id=896256 here]. There are also known chipset hardware failures that may prevent this API from functioning properly (see [@http://support.microsoft.com/kb/274323 here]).] []] - [[`BOOST_LOG_USE_NATIVE_SYSLOG`] [Affects only compilation of the library. If for some reason support for the native SysLog API is not detected automatically, define this macro to forcibly enable it.] []] - [[`BOOST_LOG_WITHOUT_DEFAULT_FACTORIES`] [Affects only compilation of the library. If defined, the parsers for settings will be built without any default factories for filters and formatters. The user will have to register all attributes in the library before parsing any filters or formatters from strings. This can substantially reduce the binary size.] []] - [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.] [Disables compilation of the `boost_log_setup` library.]] - [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only compilation of the library. If defined, the support for debugger output on Windows will not be built.] []] - [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.] []] - [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for syslog backend will not be built.] []] - [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for interprocess queues will not be built.] []] - [[`BOOST_LOG_NO_SHORTHAND_NAMES`] [Affects only compilation of users' code. If defined, some deprecated shorthand macro names will not be available.] [Not a CMake configuration option.]] - [[`BOOST_LOG_USE_COMPILER_TLS`] [Affects only compilation of the library. This macro enables support for compiler intrinsics for thread-local storage. Defining it may improve performance of Boost.Log if certain usage limitations are acceptable. See below for more comments.] []] - [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.] [Instead of definitng one of these macros, use `BOOST_LOG_USE_REGEX_BACKEND` string option with one of the following values: "std::regex", "Boost.Regex" or "Boost.Xpressive". The macros will be defined accordingly by CMake.]] -] - -You can define configuration macros in the `b2` command line, like this: - -[pre - b2 --with-log variant=release define=BOOST_LOG_WITHOUT_EVENT_LOG define=BOOST_USE_WINAPI_VERSION=0x0600 stage -] - -With CMake, the configuration macros can be specified as CMake options in the command line like this: - -[pre - cmake .. -DCMAKE_BUILD_TYPE=Release -DBOOST_LOG_WITHOUT_EVENT_LOG=On -] - -However, it may be more convenient to define configuration macros in the "boost/config/user.hpp" file in order to automatically define them both for the library and user's projects. If none of the options are specified, the library will try to support the most comprehensive setup, including support for all character types and features available for the target platform. - -The logging library uses several other Boost libraries that require building too. These are __boost_filesystem__, __boost_system__, __boost_date_time__, __boost_thread__ and in some configurations __boost_regex__. Refer to their documentation for detailed instructions on the building procedure. - -One final thing should be added. The library requires run-time type information (RTTI) to be enabled for both the library compilation and user's code compilation. Normally, this won't need anything from you except to verify that RTTI support is not disabled in your project. - -[heading Notes about compiler-supplied intrinsics for TLS] - -Many widely used compilers support builtin intrinsics for managing thread-local storage, which is used in several parts of the library. This feature is also included in the C++11 standard. Generally, these intrinsics allow for a much more efficient access to the storage than any surrogate implementation, be that __boost_thread__ or even native operating system API. However, this feature has several caveats: - -* Some operating systems don't support the use of these intrinsics in case if the TLS is defined in a shared library that is dynamically loaded during the application run time. These systems include Linux and Windows prior to Vista. Windows Vista and later do not have this issue. -* The TLS may not be reliably accessed from global constructors and destructors. At least MSVC 8.0 on Windows is known to have this problem. - -The library provides the `BOOST_LOG_USE_COMPILER_TLS` configuration macro that allows to enable the use of this feature, which will improve the library performance at the cost of these limitations: - -* The application executable must be linked with the Boost.Log library. It should not be loaded dynamically during run time. -* The application must not use logging in global constructors or destructors. - -Note that the `BOOST_LOG_USE_COMPILER_TLS` macro only controls use of TLS in Boost.Log but not in other libraries used by Boost.Log. For example, __boost_asio__ uses compiler-supplied TLS by default. In order to build Boost.Log binaries completely free from use of compiler-supplied TLS, this feature has to be disabled in those other libraries as well (in case of __boost_asio__ this can be achieved by defining `BOOST_ASIO_DISABLE_THREAD_KEYWORD_EXTENSION` when building and using Boost). - -Also note that enabling builtin compiler support for TLS does not remove the dependency on __boost_thread__ or lower level OS threading primitives, including those implementing TLS. The purpose of using compiler intrinsics for TLS is better performance rather than reducing dependencies. - -[heading Notes about native `wchar_t` support] - -Some compilers, most notably MSVC, have an option to disable the native `wchar_t` type, emulating it with a typedef for one of the standard integral types. From the C++ language perspective this behavior is not conforming but it may be useful for compatibility with some legacy code which is difficult to update. - -By default, Boost (and Boost.Log being part of it) is built with native `wchar_t` enabled. At the time of this writing, user will have to modify Boost.Build to enable the emulation mode. It is possible to build Boost.Log in this mode, but there are several caveats that have to be kept in mind: - -* The compiled Boost.Log binaries will be exporting symbols corresponding to the configuration chosen at build time. The user's code will have to use the same setting as was used when building Boost.Log, otherwise linking errors will appear. -* Since in emulation mode `wchar_t` is undistinguishable from one of the integer types, certain parts of the library may behave differently from the normal mode with native `wchar_t`. In particular, wide-character literals may be rejected or formatted differently. -* The emulation mode is not tested, so unexpected breakages are possible. - -Because of that using the emulation mode is discouraged and should be avoided. In future releases of the library its support may be removed completely. - -[heading Notes for CMake users on Windows] - -In order to compile Boost.Log with event log support on Windows using CMake, the initial CMake configuration should be performed with resource (`rc.exe` or `windres.exe`) and message compiler tools (`mc.exe` or `windmc.exe`) available in `PATH` environment variable. With MSVC, it is recommended to run CMake in the Visual Studio command line or otherwise ensure that Windows SDK environment variables are set. - -Alternatively, users may set `RC` and `MC` environment variables to paths of the resource and message compiler executables, respectively, or set `CMAKE_RC_COMPILER` and `CMAKE_MC_COMPILER` CMake options to the corresponding paths in the command line. - -[endsect] - -[endsect] - -[section:defs Definitions] - -Here are definitions of some terms that will be used widely throughout the documentation: - -[variablelist - [[Log record][A single bundle of information, collected from the user's application, that is a candidate to be put into the log. In a simple case the log record will be represented as a line of text in the log file after being processed by the logging library.]] - [[Attribute][An "attribute" is a piece of meta-information that can be used to specialize a log record. In Boost.Log attributes are represented by function objects with a specific interface, which return the actual attribute value when invoked.]] - [[Attribute value][Attribute values are the actual data acquired from attributes. This data is attached to the specific log record and processed by the library. Values can have different types (integers, strings and more complex, including user defined types). Some examples of attribute values: current time stamp value, file name, line number, current scope name, etc.. Attribute values are enveloped in a type erasing wrapper, so the actual type of the attribute is not visible in the interface. The actual (erased) type of the value is sometimes called the stored type.]] - [[(Attribute) value visitation][A way of processing the attribute value. This approach involves a function object (a visitor) which is applied to the attribute value. The visitor should know the stored type of the attribute value in order to process it.]] - [[(Attribute) value extraction][A way of processing the attribute value when the caller attempts to obtain a reference to the stored value. The caller should know the stored type of the attribute value in order to be able to extract it.]] - [[Log sink][A target, to which all log records are fed after being collected from the user's application. The sink defines where and how the log records are going to be stored or processed.]] - [[Log source][An entry point for the user's application to put log records to. In a simple case it is an object (logger) which maintains a set of attributes that will be used to form a log record upon the user's request. However, one can surely create a source that would emit log records on some side events (for example, by intercepting and parsing console output of another application).]] - [[Log filter][A predicate that takes a log record and tells whether this record should be passed through or discarded. The predicate typically forms its decision based on the attribute values attached to the record.]] - [[Log formatter][A function object that generates the final textual output from a log record. Some sinks, e.g. a binary logging sink, may not need it, although almost any text-based sink would use a formatter to compose its output.]] - [[Logging core][The global entity that maintains connections between sources and sinks and applies filters to records. It is mainly used when the logging library is initialized.]] - [[i18n][Internationalization. The ability to manipulate wide characters.]] - [[TLS][Thread-local storage. The concept of having a variable that has independent values for each thread that attempts to access it.]] - [[RTTI][Run-time type information. This is the C++ language support data structures required for `dynamic_cast` and `typeid` operators to function properly.]] -] - -[endsect] - +[include:log intro.qbk] +[include:log install.qbk] [include:log design.qbk] - [include:log tutorial.qbk] [section:detailed Detailed features description] diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 304bd94106..83b76be467 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -95,7 +95,7 @@ Although the library guarantees that log records made in a given thread are alwa There are few possible ways to cope with the problem: -* Enforce strict serialization of log record being made throughout the application. This solution implies a severe performance impact in multithreaded applications because log records that otherwise could be processed concurrently would have to go serial. Since this controverses one of the [link log.moti main library goals], it was rejected. +* Enforce strict serialization of log record being made throughout the application. This solution implies a severe performance impact in multithreaded applications because log records that otherwise could be processed concurrently would have to go serial. Since this controverses one of the [link log.intro.moti main library goals], it was rejected. * Attempt to maintain log record ordering on the sink level. This solution is more or less viable. On the downside, it would introduce log record buffering, which in turn would compromise logs reliability. In the case of application crash all buffered records would be lost. * Bear with the problem and let mis-ordered records appear in log files occasionally. Order log records upon reading the files, if needed. From 433aa87b8cd6ad3f2f402f4fac3bca26117241d6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 2 Mar 2024 16:01:59 +0300 Subject: [PATCH 241/309] Minor wording improvement. --- doc/design.qbk | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/design.qbk b/doc/design.qbk index a0f6afcaf6..ac9d1b7978 100644 --- a/doc/design.qbk +++ b/doc/design.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2022. + Copyright Andrey Semashev 2007 - 2024. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -35,13 +35,13 @@ There are three kinds of attribute sets: You can see in the figure that the former two sets are maintained by the logging core and thus need not be passed by the log source in order to initiate logging. Attributes that participate in the global attribute set are attached to any log record ever made. Obviously, thread-specific attributes are attached only to the records made from the thread in which they were registered in the set. The source-specific attribute set is maintained by the source that initiates logging, these attributes are attached only to the records being made through that particular source. -When a source initiates logging, attribute values are acquired from attributes of all three attribute sets. These attribute values then form a single set of named attribute values, which is processed further. You can add more attribute values to the set; these values will only be attached to the particular log record and will not be associated with the logging source or logging core. As you may notice, it is possible for a same-named attribute to appear in several attribute sets. Such conflicts are solved on priority basis: global attributes have the least priority, source-specific attributes have the highest; the lower priority attributes are discarded from consideration in case of conflicts. +When a source initiates logging, attribute values are acquired from attributes of all three attribute sets. These attribute values then form a single set of named attribute values, which is processed further. You can add more attribute values to the set; these values will only be attached to the particular log record and will not be associated with the logging source or logging core. As you may notice, it is possible for a same-named attribute to appear in several attribute sets. Such conflicts are solved on precedence basis: global attributes have the least precedence, source-specific attributes have the highest; the lower precedence attributes are discarded from consideration in case of conflicts. [heading Logging core and filtering] When the set of attribute values is composed, the logging core decides if this log record is going to be processed in sinks. This is called filtering. There are two layers of filtering available: the global filtering is applied first within the logging core itself and allows quickly wiping away unneeded log records; the sink-specific filtering is applied second, for each sink separately. The sink-specific filtering allows directing log records to particular sinks. Note that at this point it is not significant which logging source emitted the record, the filtering relies solely on the set of attribute values attached to the record. -It must be mentioned that for a given log record filtering is performed only once. Obviously, only those attribute values attached to the record before filtering starts can participate in filtering. Some attribute values, like log record message, are typically attached to the record after the filtering is done; such values cannot be used in filters, they can only be used by formatters and sinks themselves. +It must be mentioned that for a given log record filtering is performed only once. Obviously, only the attribute values that were attached to the record before filtering starts can participate in filtering. Some attribute values, like log record message, are typically attached to the record after the filtering is done; such values cannot be used in filters, they can only be used by formatters and sinks themselves. [heading Sinks and formatting] From 5f84f9130c51f901c615bb29f09fe69260cf8bfb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 2 Mar 2024 17:48:10 +0300 Subject: [PATCH 242/309] Expanded leading explanation for attributes. Related to https://github.com/boostorg/log/issues/226. --- doc/attributes.qbk | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/doc/attributes.qbk b/doc/attributes.qbk index 275756f40d..96a5df8e53 100644 --- a/doc/attributes.qbk +++ b/doc/attributes.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2022. + Copyright Andrey Semashev 2007 - 2024. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,7 +13,9 @@ #include <``[boost_log_attributes_attribute_cast_hpp]``> #include <``[boost_log_attributes_attribute_value_hpp]``> -All attributes in the library are implemented using the [@http://c2.com/cgi/wiki?PimplIdiom pimpl idiom], or more specifically - shared pimpl idiom. Every attribute provides an interface class which derives from the [class_log_attribute] class and an implementation class that derives from [class_log_attribute_impl]. The interface class only holds a reference counted pointer to the actual implementation of the attribute; this pointer is a member of the [class_log_attribute] class, so derived interface classes don't have any data members. When the interface class is default constructed, it creates the corresponding implementation object and initializes the [class_log_attribute] base class with a pointer to the implementation. Therefore the pimpl nature of attributes is transparent for users in a typical workflow. +As described in the [link log.design Design overview], attributes in Boost.Log represent information to be associated with log records. An attribute is essentially a function that produces an attribute value upon being invoked. The function may produce a different value each time it is called, or always produce the same value on every call. For example, the [link log.detailed.attributes.clock `local_clock`] attribute produces timestamp values according to the local wall time clock, and [link log.detailed.attributes.constant `constant`] always produces the same value every time. + +All attributes in the library are implemented using the [@https://en.cppreference.com/w/cpp/language/pimpl pimpl idiom], or more specifically - shared pimpl idiom. Every attribute provides an interface class which derives from the [class_log_attribute] class and an implementation class that derives from [class_log_attribute_impl]. The interface class only holds a reference counted pointer to the actual implementation of the attribute; this pointer is a member of the [class_log_attribute] class, so derived interface classes don't have any data members. When the interface class is default constructed, it creates the corresponding implementation object and initializes the [class_log_attribute] base class with a pointer to the implementation. Therefore the pimpl nature of attributes is transparent for users in a typical workflow. The shared pimpl design comes significant in a few cases though. One such case is copying the attribute. The copy operation is shallow, so multiple interface objects may refer to a single implementation object. There is no way to deep copy an attribute. Another case is default construction of [class_log_attribute] which creates an empty object that does not refer to an implementation. Attributes in such empty state should not be passed to the library but can be useful in some cases, e.g. when a delayed variable initialization is needed. @@ -24,9 +26,9 @@ It is possible to upcast the attribute interface from [class_log_attribute] to t In this example, the cast will succeed (i.e. the `const_attr` will be non-empty) if the attribute `attr` was originally created as `attrs::constant< int >`. Since all data is stored in the implementation object, no data is lost in the casting process. -The main purpose of attributes is to generate attribute values. Values are semantically distinct from the attributes. Such separation allows implementing attributes that can return different values at different time points (like clock-related attributes, for example) and, on the other hand, allows using different values of the same attribute independently. The [class_log_attribute] interface has a method named `get_value` that returns the actual attribute value. Attribute values are also implemented using the shared pimpl approach, the interface class is [class_log_attribute_value] and implementation classes derive from [class_log_attribute_value_impl]. +As it was said, the main purpose of attributes is to generate attribute values. Values are semantically distinct from the attributes. Such separation allows implementing attributes that can return different values at different times and, on the other hand, allows using different values of the same attribute independently. The [class_log_attribute] interface has a method named `get_value` that returns the actual attribute value. Attribute values are also implemented using the shared pimpl approach, the interface class is [class_log_attribute_value] and implementation classes derive from [class_log_attribute_value_impl]. -The attribute value object is mostly intended to store the actual attribute value and implement type dispatching in order to be able to extract the stored value. One should not confuse the attribute value object type and the stored value type. The former is in most cases not needed by users and provides type erasure, but the latter is needed to be able to extract the value. For brevity we call the stored attribute value type simply the attribute value type in this documentation. +The attribute value object is intended to store the actual attribute value and implement type dispatching in order to be able to extract the stored value. One should not confuse the attribute value implementation type and the stored value type. The former is in most cases not important to users and provides type erasure, but the latter is needed to be able to extract the value. In the example above, the `constant< int >` type is the attribute type, its `get_value()` method produces an object of type [class_log_attribute_value], which is a pimpl wrapper for the [classref boost::log::attributes::attribute_value_impl `attribute_value_impl< int >`] implementation type. The actual stored attribute value type here is `int`, which is what the attribute generates, and what is needed by the user in order to be able to extract the value from [class_log_attribute_value]. For brevity we call the stored attribute value type simply the attribute value type in this documentation. [section:constant Constants] From e79cfd841f90e4f0d7f4729440e7ef92ef7495da Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 2 Mar 2024 18:38:56 +0300 Subject: [PATCH 243/309] Explicitly specify TOC depth. --- doc/Jamfile.v2 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 7d95b40956..adc588260e 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -268,6 +268,8 @@ boostbook log "nav.layout=none" "boost.image=Boost" "navig.graphics=1" + "toc.max.depth=2" + "toc.section.depth=2" "chunk.section.depth=2" "boost.compact.function=0" pdf:"boost.url.prefix=http://www.boost.org/doc/libs/release/libs/log/doc/html" From ea643a6f1de5cf951ce520dfb3e68c783329fe58 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Apr 2024 20:13:57 +0300 Subject: [PATCH 244/309] Updated URL to Boost.System docs. --- doc/log.qbk | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/log.qbk b/doc/log.qbk index 64b7557fc4..12b84e2045 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -20,7 +20,7 @@ [def __boost_smart_ptr__ [@http://www.boost.org/doc/libs/release/libs/smart_ptr/smart_ptr.htm Boost.SmartPtr]] [def __boost_function__ [@http://www.boost.org/doc/libs/release/doc/html/function.html Boost.Function]] [def __boost_filesystem__ [@http://www.boost.org/doc/libs/release/libs/filesystem/doc/index.htm Boost.Filesystem]] -[def __boost_system__ [@http://www.boost.org/doc/libs/release/libs/system/doc/index.html Boost.System]] +[def __boost_system__ [@http://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] [def __boost_date_time__ [@http://www.boost.org/doc/libs/release/doc/html/date_time.html Boost.DateTime]] [def __boost_date_time_format__ [@http://www.boost.org/doc/libs/release/doc/html/date_time/date_time_io.html#date_time.format_flags Boost.DateTime]] [def __boost_thread__ [@http://www.boost.org/doc/libs/release/doc/html/thread.html Boost.Thread]] From e5e4e9554fea980edc0efc2026f316205550172c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Apr 2024 20:15:07 +0300 Subject: [PATCH 245/309] Changed http to https in Boost URLs. --- doc/install.qbk | 2 +- doc/log.qbk | 72 ++++++++++++++++++++++++------------------------- 2 files changed, 37 insertions(+), 37 deletions(-) diff --git a/doc/install.qbk b/doc/install.qbk index eecad7e4b6..0909f9a403 100644 --- a/doc/install.qbk +++ b/doc/install.qbk @@ -56,7 +56,7 @@ Cygwin support is very preliminary. The default GCC version available in Cygwin [section:config Configuring and building the library] -The library has a separately compiled part which should be built as described in the [@http://www.boost.org/doc/libs/release/more/getting_started/ Getting Started guide]. One thing should be noted, though. If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library _must_ be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library. +The library has a separately compiled part which should be built as described in the [@https://www.boost.org/doc/libs/release/more/getting_started/ Getting Started guide]. One thing should be noted, though. If your application consists of more than one module (e.g. an exe and one or several dll's) that use Boost.Log, the library _must_ be built as a shared object. If you have a single executable or a single module that works with Boost.Log, you may build the library as a static library. The library supports a number of configuration macros: diff --git a/doc/log.qbk b/doc/log.qbk index 12b84e2045..1786d19476 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -15,42 +15,42 @@ [c++] [/ Links to external resources /] -[def __boost_config__ [@http://www.boost.org/doc/libs/release/libs/config/doc/html/index.html Boost.Config]] -[def __boost_atomic__ [@http://www.boost.org/doc/libs/release/doc/html/atomic.html Boost.Atomic]] -[def __boost_smart_ptr__ [@http://www.boost.org/doc/libs/release/libs/smart_ptr/smart_ptr.htm Boost.SmartPtr]] -[def __boost_function__ [@http://www.boost.org/doc/libs/release/doc/html/function.html Boost.Function]] -[def __boost_filesystem__ [@http://www.boost.org/doc/libs/release/libs/filesystem/doc/index.htm Boost.Filesystem]] -[def __boost_system__ [@http://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] -[def __boost_date_time__ [@http://www.boost.org/doc/libs/release/doc/html/date_time.html Boost.DateTime]] -[def __boost_date_time_format__ [@http://www.boost.org/doc/libs/release/doc/html/date_time/date_time_io.html#date_time.format_flags Boost.DateTime]] -[def __boost_thread__ [@http://www.boost.org/doc/libs/release/doc/html/thread.html Boost.Thread]] -[def __boost_regex__ [@http://www.boost.org/doc/libs/release/libs/regex/index.html Boost.Regex]] -[def __boost_xpressive__ [@http://www.boost.org/doc/libs/release/doc/html/xpressive.html Boost.Xpressive]] -[def __boost_parameter__ [@http://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html Boost.Parameter]] -[def __boost_format__ [@http://www.boost.org/doc/libs/release/libs/format/index.html Boost.Format]] -[def __boost_preprocessor__ [@http://www.boost.org/doc/libs/release/libs/preprocessor/doc/index.html Boost.Preprocessor]] -[def __boost_bind__ [@http://www.boost.org/doc/libs/release/libs/bind/bind.html Boost.Bind]] -[def __boost_lambda__ [@http://www.boost.org/doc/libs/release/doc/html/lambda.html Boost.Lambda]] -[def __boost_phoenix__ [@http://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html Boost.Phoenix]] -[def __boost_spirit__ [@http://www.boost.org/doc/libs/release/libs/spirit/classic/index.html Boost.Spirit]] -[def __boost_spirit2__ [@http://www.boost.org/doc/libs/release/libs/spirit/doc/html/index.html Boost.Spirit2]] -[def __boost_optional__ [@http://www.boost.org/doc/libs/release/libs/optional/index.html Boost.Optional]] -[def __boost_variant__ [@http://www.boost.org/doc/libs/release/doc/html/variant.html Boost.Variant]] -[def __boost_intrusive__ [@http://www.boost.org/doc/libs/release/doc/html/intrusive.html Boost.Intrusive]] -[def __boost_range__ [@http://www.boost.org/doc/libs/release/libs/range/index.html Boost.Range]] -[def __boost_iostreams__ [@http://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html Boost.IOStreams]] -[def __boost_fusion__ [@http://www.boost.org/doc/libs/release/libs/fusion/index.html Boost.Fusion]] -[def __boost_mpl__ [@http://www.boost.org/doc/libs/release/libs/mpl/doc/index.html Boost.MPL]] -[def __boost_exception__ [@http://www.boost.org/doc/libs/release/libs/exception/doc/boost-exception.html Boost.Exception]] -[def __boost_scope_exit__ [@http://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] -[def __boost_any__ [@http://www.boost.org/doc/libs/release/doc/html/any.html Boost.Any]] -[def __boost_property_tree__ [@http://www.boost.org/doc/libs/release/doc/html/property_tree.html Boost.PropertyTree]] -[def __boost_asio__ [@http://www.boost.org/doc/libs/release/doc/html/boost_asio.html Boost.ASIO]] -[def __boost_move__ [@http://www.boost.org/doc/libs/release/doc/html/move.html Boost.Move]] -[def __boost_locale__ [@http://www.boost.org/doc/libs/release/libs/locale/doc/html/index.html Boost.Locale]] -[def __boost_type_index__ [@http://www.boost.org/doc/libs/release/doc/html/boost_typeindex.html Boost.TypeIndex]] -[def __boost_utility__ [@http://www.boost.org/doc/libs/release/libs/utility/utility.htm Boost.Utility]] -[def __boost_quickbook__ [@http://www.boost.org/doc/libs/release/doc/html/quickbook.html Boost.Quickbook]] +[def __boost_config__ [@https://www.boost.org/doc/libs/release/libs/config/doc/html/index.html Boost.Config]] +[def __boost_atomic__ [@https://www.boost.org/doc/libs/release/doc/html/atomic.html Boost.Atomic]] +[def __boost_smart_ptr__ [@https://www.boost.org/doc/libs/release/libs/smart_ptr/smart_ptr.htm Boost.SmartPtr]] +[def __boost_function__ [@https://www.boost.org/doc/libs/release/doc/html/function.html Boost.Function]] +[def __boost_filesystem__ [@https://www.boost.org/doc/libs/release/libs/filesystem/doc/index.htm Boost.Filesystem]] +[def __boost_system__ [@https://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] +[def __boost_date_time__ [@https://www.boost.org/doc/libs/release/doc/html/date_time.html Boost.DateTime]] +[def __boost_date_time_format__ [@https://www.boost.org/doc/libs/release/doc/html/date_time/date_time_io.html#date_time.format_flags Boost.DateTime]] +[def __boost_thread__ [@https://www.boost.org/doc/libs/release/doc/html/thread.html Boost.Thread]] +[def __boost_regex__ [@https://www.boost.org/doc/libs/release/libs/regex/index.html Boost.Regex]] +[def __boost_xpressive__ [@https://www.boost.org/doc/libs/release/doc/html/xpressive.html Boost.Xpressive]] +[def __boost_parameter__ [@https://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html Boost.Parameter]] +[def __boost_format__ [@https://www.boost.org/doc/libs/release/libs/format/index.html Boost.Format]] +[def __boost_preprocessor__ [@https://www.boost.org/doc/libs/release/libs/preprocessor/doc/index.html Boost.Preprocessor]] +[def __boost_bind__ [@https://www.boost.org/doc/libs/release/libs/bind/bind.html Boost.Bind]] +[def __boost_lambda__ [@https://www.boost.org/doc/libs/release/doc/html/lambda.html Boost.Lambda]] +[def __boost_phoenix__ [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html Boost.Phoenix]] +[def __boost_spirit__ [@https://www.boost.org/doc/libs/release/libs/spirit/classic/index.html Boost.Spirit]] +[def __boost_spirit2__ [@https://www.boost.org/doc/libs/release/libs/spirit/doc/html/index.html Boost.Spirit2]] +[def __boost_optional__ [@https://www.boost.org/doc/libs/release/libs/optional/index.html Boost.Optional]] +[def __boost_variant__ [@https://www.boost.org/doc/libs/release/doc/html/variant.html Boost.Variant]] +[def __boost_intrusive__ [@https://www.boost.org/doc/libs/release/doc/html/intrusive.html Boost.Intrusive]] +[def __boost_range__ [@https://www.boost.org/doc/libs/release/libs/range/index.html Boost.Range]] +[def __boost_iostreams__ [@https://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html Boost.IOStreams]] +[def __boost_fusion__ [@https://www.boost.org/doc/libs/release/libs/fusion/index.html Boost.Fusion]] +[def __boost_mpl__ [@https://www.boost.org/doc/libs/release/libs/mpl/doc/index.html Boost.MPL]] +[def __boost_exception__ [@https://www.boost.org/doc/libs/release/libs/exception/doc/boost-exception.html Boost.Exception]] +[def __boost_scope_exit__ [@https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] +[def __boost_any__ [@https://www.boost.org/doc/libs/release/doc/html/any.html Boost.Any]] +[def __boost_property_tree__ [@https://www.boost.org/doc/libs/release/doc/html/property_tree.html Boost.PropertyTree]] +[def __boost_asio__ [@https://www.boost.org/doc/libs/release/doc/html/boost_asio.html Boost.ASIO]] +[def __boost_move__ [@https://www.boost.org/doc/libs/release/doc/html/move.html Boost.Move]] +[def __boost_locale__ [@https://www.boost.org/doc/libs/release/libs/locale/doc/html/index.html Boost.Locale]] +[def __boost_type_index__ [@https://www.boost.org/doc/libs/release/doc/html/boost_typeindex.html Boost.TypeIndex]] +[def __boost_utility__ [@https://www.boost.org/doc/libs/release/libs/utility/utility.htm Boost.Utility]] +[def __boost_quickbook__ [@https://www.boost.org/doc/libs/release/doc/html/quickbook.html Boost.Quickbook]] [template ticket[key]'''#'''[key]''''''] [template github_issue[key]'''GH#'''[key]''''''] From 2d932ddcb5b05a9b2cc0a9df2d8a6ff88883f2b3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 7 Apr 2024 23:58:00 +0300 Subject: [PATCH 246/309] Updated links to Boost libraries docs. --- doc/log.qbk | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/doc/log.qbk b/doc/log.qbk index 1786d19476..325dd0ab66 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -16,30 +16,30 @@ [/ Links to external resources /] [def __boost_config__ [@https://www.boost.org/doc/libs/release/libs/config/doc/html/index.html Boost.Config]] -[def __boost_atomic__ [@https://www.boost.org/doc/libs/release/doc/html/atomic.html Boost.Atomic]] -[def __boost_smart_ptr__ [@https://www.boost.org/doc/libs/release/libs/smart_ptr/smart_ptr.htm Boost.SmartPtr]] +[def __boost_atomic__ [@https://www.boost.org/doc/libs/release/libs/atomic/doc/html/index.html Boost.Atomic]] +[def __boost_smart_ptr__ [@https://www.boost.org/doc/libs/release/libs/smart_ptr/doc/html/smart_ptr.html Boost.SmartPtr]] [def __boost_function__ [@https://www.boost.org/doc/libs/release/doc/html/function.html Boost.Function]] [def __boost_filesystem__ [@https://www.boost.org/doc/libs/release/libs/filesystem/doc/index.htm Boost.Filesystem]] [def __boost_system__ [@https://www.boost.org/doc/libs/release/libs/system/doc/html/system.html Boost.System]] [def __boost_date_time__ [@https://www.boost.org/doc/libs/release/doc/html/date_time.html Boost.DateTime]] [def __boost_date_time_format__ [@https://www.boost.org/doc/libs/release/doc/html/date_time/date_time_io.html#date_time.format_flags Boost.DateTime]] [def __boost_thread__ [@https://www.boost.org/doc/libs/release/doc/html/thread.html Boost.Thread]] -[def __boost_regex__ [@https://www.boost.org/doc/libs/release/libs/regex/index.html Boost.Regex]] +[def __boost_regex__ [@https://www.boost.org/doc/libs/release/libs/regex/doc/html/index.html Boost.Regex]] [def __boost_xpressive__ [@https://www.boost.org/doc/libs/release/doc/html/xpressive.html Boost.Xpressive]] [def __boost_parameter__ [@https://www.boost.org/doc/libs/release/libs/parameter/doc/html/index.html Boost.Parameter]] [def __boost_format__ [@https://www.boost.org/doc/libs/release/libs/format/index.html Boost.Format]] [def __boost_preprocessor__ [@https://www.boost.org/doc/libs/release/libs/preprocessor/doc/index.html Boost.Preprocessor]] -[def __boost_bind__ [@https://www.boost.org/doc/libs/release/libs/bind/bind.html Boost.Bind]] +[def __boost_bind__ [@https://www.boost.org/doc/libs/release/libs/bind/doc/html/bind.html Boost.Bind]] [def __boost_lambda__ [@https://www.boost.org/doc/libs/release/doc/html/lambda.html Boost.Lambda]] [def __boost_phoenix__ [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/index.html Boost.Phoenix]] [def __boost_spirit__ [@https://www.boost.org/doc/libs/release/libs/spirit/classic/index.html Boost.Spirit]] [def __boost_spirit2__ [@https://www.boost.org/doc/libs/release/libs/spirit/doc/html/index.html Boost.Spirit2]] -[def __boost_optional__ [@https://www.boost.org/doc/libs/release/libs/optional/index.html Boost.Optional]] +[def __boost_optional__ [@https://www.boost.org/doc/libs/release/libs/optional/doc/html/index.html Boost.Optional]] [def __boost_variant__ [@https://www.boost.org/doc/libs/release/doc/html/variant.html Boost.Variant]] [def __boost_intrusive__ [@https://www.boost.org/doc/libs/release/doc/html/intrusive.html Boost.Intrusive]] -[def __boost_range__ [@https://www.boost.org/doc/libs/release/libs/range/index.html Boost.Range]] +[def __boost_range__ [@https://www.boost.org/doc/libs/release/libs/range/doc/html/index.html Boost.Range]] [def __boost_iostreams__ [@https://www.boost.org/doc/libs/release/libs/iostreams/doc/index.html Boost.IOStreams]] -[def __boost_fusion__ [@https://www.boost.org/doc/libs/release/libs/fusion/index.html Boost.Fusion]] +[def __boost_fusion__ [@https://www.boost.org/doc/libs/release/libs/fusion/doc/html/index.html Boost.Fusion]] [def __boost_mpl__ [@https://www.boost.org/doc/libs/release/libs/mpl/doc/index.html Boost.MPL]] [def __boost_exception__ [@https://www.boost.org/doc/libs/release/libs/exception/doc/boost-exception.html Boost.Exception]] [def __boost_scope_exit__ [@https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] @@ -49,7 +49,7 @@ [def __boost_move__ [@https://www.boost.org/doc/libs/release/doc/html/move.html Boost.Move]] [def __boost_locale__ [@https://www.boost.org/doc/libs/release/libs/locale/doc/html/index.html Boost.Locale]] [def __boost_type_index__ [@https://www.boost.org/doc/libs/release/doc/html/boost_typeindex.html Boost.TypeIndex]] -[def __boost_utility__ [@https://www.boost.org/doc/libs/release/libs/utility/utility.htm Boost.Utility]] +[def __boost_utility__ [@https://www.boost.org/doc/libs/release/libs/utility/doc/html/index.html Boost.Utility]] [def __boost_quickbook__ [@https://www.boost.org/doc/libs/release/doc/html/quickbook.html Boost.Quickbook]] [template ticket[key]'''#'''[key]''''''] From 38bf38e835d968ac306800b6f46f4d63a04346bb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 13 Apr 2024 17:50:11 +0300 Subject: [PATCH 247/309] Use _xgetbv intrinsic on Windows for AVX2 detection. The intrinsic is supported since VS2010 SP1, which is below our minimum supported MSVC version. The intrinsic is the proper way to detect support for AVX register state by the OS instead of the undocumented GetEnabledExtendedFeatures WinAPI function. --- src/dump.cpp | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/src/dump.cpp b/src/dump.cpp index 812687931a..5bdba7c8c3 100644 --- a/src/dump.cpp +++ b/src/dump.cpp @@ -18,8 +18,8 @@ #include #include #if defined(_MSC_VER) && (defined(BOOST_LOG_USE_SSSE3) || defined(BOOST_LOG_USE_AVX2)) -#include #include // __cpuid +#include // _xgetbv #endif #include @@ -180,19 +180,8 @@ struct function_pointer_initializer : "c" (0) ); mmstate = (eax & 6u) == 6u; -#elif defined(BOOST_WINDOWS) - // MSVC does not have an intrinsic for xgetbv, we have to query OS - boost::winapi::HMODULE_ hKernel32 = boost::winapi::GetModuleHandleW(L"kernel32.dll"); - if (hKernel32) - { - typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_enabled_extended_features_t)(uint64_t); - get_enabled_extended_features_t get_enabled_extended_features = (get_enabled_extended_features_t)boost::winapi::get_proc_address(hKernel32, "GetEnabledExtendedFeatures"); - if (get_enabled_extended_features) - { - // XSTATE_MASK_LEGACY_SSE | XSTATE_MASK_GSSE == 6 - mmstate = get_enabled_extended_features(6u) == 6u; - } - } +#elif defined(_MSC_VER) + mmstate = (_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 6u) == 6u; #endif if (mmstate) From 901600febfb9baf4536af7451b9a3712d3e39f93 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 21 May 2024 01:20:30 +0300 Subject: [PATCH 248/309] Replaced macos-11 GHA image with 12, 13 and 14 since 11 is being removed. --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0d418a4a03..b376a9f4fd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -270,8 +270,14 @@ jobs: - libc++abi-15-dev - toolset: clang - cxxstd: "11,14,17,2a" - os: macos-11 + cxxstd: "11,14,17,20,2b" + os: macos-12 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-13 + - toolset: clang + cxxstd: "11,14,17,20,2b" + os: macos-14 - name: CMake tests cmake_tests: 1 From 32d0ebf3fe37e390eb07f15dc96f71cebdf36c47 Mon Sep 17 00:00:00 2001 From: ik Date: Sat, 8 Jun 2024 23:18:03 +0800 Subject: [PATCH 249/309] Fixed compilation error on MinGW-w64. The default behavior of windres.exe to read the output of the preprocessor is using popen. However, the popen implementation may be buggy on some non-English hosts, which would cause a compilation error like this: windres.exe: can't open file `page:': Invalid argument Fix by adding '--use-temp-file' option and windres.exe will use a temporary file to read instead of using opoen. Signed-off-by: ik --- CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index bb41d46c2b..2d9de58001 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,6 +272,10 @@ if (WIN32) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" PROPERTIES GENERATED TRUE) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" PROPERTIES GENERATED TRUE) + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + list(APPEND CMAKE_RC_FLAGS "--use-temp-file") + endif() + list(APPEND boost_log_sources "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" From 0843c5877e4f7cf6a301365810af99751367cb2d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 13 Jun 2024 21:09:27 +0300 Subject: [PATCH 250/309] Added a comment to reference windres.exe issue. --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2d9de58001..b26c893c11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,6 +273,7 @@ if (WIN32) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" PROPERTIES GENERATED TRUE) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + # Workaround for a windres.exe issue: https://github.com/boostorg/log/pull/231 list(APPEND CMAKE_RC_FLAGS "--use-temp-file") endif() From 8c8124c73098ce33b5ca9129454fb82baa681e48 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 13 Jun 2024 21:14:11 +0300 Subject: [PATCH 251/309] Added a changelog entry for the windres.exe workaround. --- doc/changelog.qbk | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index f930816778..f3d937bc72 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2023. + Copyright Andrey Semashev 2007 - 2024. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.29, Boost 1.86] + +* Added a workaround for `windres.exe` issue, when it is used in CMake to compile event log resource files on MinGW-w64. ([pull_request 231]) + [heading 2.28, Boost 1.84] * C++03 is no longer supported. A C++11 or later compiler is required. From 9a906e2f540680ff35a20207f9a1a9a3b889f52b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 13 Jun 2024 21:25:00 +0300 Subject: [PATCH 252/309] Expanded comment re. windres.exe workaround. --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b26c893c11..ba2f46fd2f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -273,7 +273,14 @@ if (WIN32) set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" PROPERTIES GENERATED TRUE) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - # Workaround for a windres.exe issue: https://github.com/boostorg/log/pull/231 + # Workaround for a windres.exe issue on MinGW-w64: by default, it uses popen to pipe preprocessed + # output from the preprocessor, but popen is buggy on non-English Windows systems and causes + # compilation errors such as: + # + # windres.exe: can't open file `page:': Invalid argument + # + # This option forces windres.exe to use a temporary file instead. + # https://github.com/boostorg/log/pull/231 list(APPEND CMAKE_RC_FLAGS "--use-temp-file") endif() From 26c93dc061558c3cc4137e262eafd028e70d74aa Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 16 Aug 2024 16:19:03 +0300 Subject: [PATCH 253/309] Replaced Boost.Thread synchronization primitives with std equivalents. This replaces boost::thread and most mutexes and condition variables with std equivalents. It also adds support for std lock types to the strictest_lock type trait. This significantly, although not completely, reduces the dependency on Boost.Thread. Refs https://github.com/boostorg/log/issues/232. --- build/Jamfile.v2 | 4 + doc/changelog.qbk | 9 ++ example/advanced_usage/Jamfile.v2 | 1 - example/async_log/Jamfile.v2 | 1 - example/async_log/main.cpp | 24 +++-- example/basic_usage/Jamfile.v2 | 1 - example/bounded_async_log/Jamfile.v2 | 1 - example/bounded_async_log/main.cpp | 24 +++-- example/doc/extension_app_launcher.cpp | 4 +- example/doc/extension_record_tagger.cpp | 4 +- example/doc/sinks_async_ordering.cpp | 4 +- example/doc/util_dynamic_type_disp.cpp | 4 + example/doc/util_static_type_disp.cpp | 4 + example/event_log/Jamfile.v2 | 1 - example/keywords/Jamfile.v2 | 1 - example/multiple_files/Jamfile.v2 | 1 - example/multiple_files/main.cpp | 13 +-- example/multiple_threads/Jamfile.v2 | 1 - example/multiple_threads/main.cpp | 19 ++-- example/native_syslog/Jamfile.v2 | 1 - example/rotating_file/Jamfile.v2 | 1 - example/settings_file/Jamfile.v2 | 1 - .../settings_file_custom_factories/Jamfile.v2 | 1 - example/syslog/Jamfile.v2 | 1 - example/trivial/Jamfile.v2 | 1 - example/wide_char/Jamfile.v2 | 1 - include/boost/log/detail/adaptive_mutex.hpp | 18 ++-- include/boost/log/detail/enqueued_record.hpp | 6 +- include/boost/log/detail/event.hpp | 10 +-- include/boost/log/detail/locking_ptr.hpp | 4 +- include/boost/log/detail/locks.hpp | 31 +++++++ include/boost/log/sinks/async_frontend.hpp | 51 +++++------ .../boost/log/sinks/basic_sink_frontend.hpp | 33 ------- include/boost/log/sinks/block_on_overflow.hpp | 4 +- .../boost/log/sinks/bounded_fifo_queue.hpp | 19 ++-- .../log/sinks/bounded_ordering_queue.hpp | 50 +++++------ include/boost/log/sinks/sync_frontend.hpp | 4 +- .../log/sinks/unbounded_ordering_queue.hpp | 50 +++++------ .../log/sources/exception_handler_feature.hpp | 15 ---- include/boost/log/utility/strictest_lock.hpp | 31 +++++++ src/core.cpp | 44 +-------- src/default_sink.cpp | 6 +- src/default_sink.hpp | 4 +- src/event.cpp | 6 +- src/global_logger_storage.cpp | 7 +- src/once_block.cpp | 15 ++-- src/setup/init_from_settings.cpp | 2 +- src/syslog_backend.cpp | 17 ++-- src/text_file_backend.cpp | 17 ++-- src/thread_id.cpp | 2 +- src/timer.cpp | 7 +- test/Jamfile.v2 | 1 - test/common/test_barrier.hpp | 62 +++++++++++++ test/performance/record_emission.cpp | 34 ++++--- test/run/core.cpp | 4 +- test/run/util_ipc_reliable_mq.cpp | 23 +++-- test/run/util_once_block.cpp | 89 ++++++++++--------- 57 files changed, 407 insertions(+), 387 deletions(-) create mode 100644 test/common/test_barrier.hpp diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 4657fdfb14..dfb6a65a4a 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -132,6 +132,10 @@ project boost/log : usage-requirements clang:-Wno-bind-to-temporary-copy clang:-Wno-unused-function + + single:BOOST_LOG_NO_THREADS + multi:/boost/atomic//boost_atomic + multi:/boost/thread//boost_thread ; local BOOST_LOG_COMMON_SRC = diff --git a/doc/changelog.qbk b/doc/changelog.qbk index f3d937bc72..15fe4c29a8 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,15 @@ [section:changelog Changelog] +[heading 2.30, Boost 1.87] + +* Replaced __boost_thread__ synchronization primitives with equivalents from the C++ standard library. This may improve multithreaded performance, but also has user-facing consequences: + * __boost_thread__ thread interruption is no longer supported. Boost.Log no longer has special treatment for the `thread_interrupted` exception that is used by Boost.Thread to implement thread interruption. This exception will be handled like any other exception. + In particular, user-specified exception handlers may now be invoked with the `thread_interrupted` pending exception. + * For timed waiting operations, timeouts are now using std::chrono time units. This means that the `ordering_window` named parameter that is supported by the [class_sinks_bounded_ordering_queue] and [class_sinks_unbounded_ordering_queue] now expects an `std::chrono::duration` value instead of `boost::posix_time::time_duration` from __boost_date_time__. + * In case of errors indicated by thread synchronization primitives, `std::system_error` exception is thrown instead of __boost_thread__ exception types. +* Added support for C++ standard library lock types to [class_log_strictest_lock]. + [heading 2.29, Boost 1.86] * Added a workaround for `windres.exe` issue, when it is used in CMake to compile event log resource files on MinGW-w64. ([pull_request 231]) diff --git a/example/advanced_usage/Jamfile.v2 b/example/advanced_usage/Jamfile.v2 index 7fd1692335..2bebc7a6a1 100644 --- a/example/advanced_usage/Jamfile.v2 +++ b/example/advanced_usage/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/async_log/Jamfile.v2 b/example/async_log/Jamfile.v2 index d8506ff24d..393086ff4f 100644 --- a/example/async_log/Jamfile.v2 +++ b/example/async_log/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/async_log/main.cpp b/example/async_log/main.cpp index 7f7a19509f..99a0687382 100644 --- a/example/async_log/main.cpp +++ b/example/async_log/main.cpp @@ -15,16 +15,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include -#include #include #include -#include -#include +#include #include #include @@ -51,13 +48,13 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Here we go. First, identify the thread. - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -95,7 +92,7 @@ int main(int argc, char* argv[]) expr::format("%1%: [%2%] [%3%] - %4%") % expr::attr< unsigned int >("RecordID") % expr::attr< boost::posix_time::ptime >("TimeStamp") - % expr::attr< boost::thread::id >("ThreadID") + % expr::attr< std::thread::id >("ThreadID") % expr::smessage ); @@ -107,13 +104,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); // Flush all buffered records sink->stop(); diff --git a/example/basic_usage/Jamfile.v2 b/example/basic_usage/Jamfile.v2 index ea7dab52e9..8f4acd7dd5 100644 --- a/example/basic_usage/Jamfile.v2 +++ b/example/basic_usage/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe basic_usage diff --git a/example/bounded_async_log/Jamfile.v2 b/example/bounded_async_log/Jamfile.v2 index 052aabab04..4ed0294b3d 100644 --- a/example/bounded_async_log/Jamfile.v2 +++ b/example/bounded_async_log/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/bounded_async_log/main.cpp b/example/bounded_async_log/main.cpp index 50e347d328..9bbd8cc86a 100644 --- a/example/bounded_async_log/main.cpp +++ b/example/bounded_async_log/main.cpp @@ -15,16 +15,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include -#include #include #include -#include -#include +#include #include #include @@ -51,13 +48,13 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Here we go. First, identify the thread. - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -97,7 +94,7 @@ int main(int argc, char* argv[]) expr::format("%1%: [%2%] [%3%] - %4%") % expr::attr< unsigned int >("RecordID") % expr::attr< boost::posix_time::ptime >("TimeStamp") - % expr::attr< boost::thread::id >("ThreadID") + % expr::attr< std::thread::id >("ThreadID") % expr::smessage ); @@ -109,13 +106,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); // Flush all buffered records sink->stop(); diff --git a/example/doc/extension_app_launcher.cpp b/example/doc/extension_app_launcher.cpp index eafa0bd044..a72e1a4a39 100644 --- a/example/doc/extension_app_launcher.cpp +++ b/example/doc/extension_app_launcher.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -47,7 +48,8 @@ class app_launcher : // The function consumes the log records that come from the frontend void app_launcher::consume(logging::record_view const& rec, string_type const& command_line) { - std::system(command_line.c_str()); + int res = std::system(command_line.c_str()); + boost::ignore_unused(res); } //] diff --git a/example/doc/extension_record_tagger.cpp b/example/doc/extension_record_tagger.cpp index 99cc7cd0db..e7fbfbf52a 100644 --- a/example/doc/extension_record_tagger.cpp +++ b/example/doc/extension_record_tagger.cpp @@ -5,6 +5,7 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#include #include #include #include @@ -13,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -65,7 +65,7 @@ class record_tagger_feature : // The method will require locking, so we have to define locking requirements for it. // We use the strictest_lock trait in order to choose the most restricting lock type. typedef typename logging::strictest_lock< - boost::lock_guard< threading_model >, + std::lock_guard< threading_model >, typename BaseT::open_record_lock, typename BaseT::add_attribute_lock, typename BaseT::remove_attribute_lock diff --git a/example/doc/sinks_async_ordering.cpp b/example/doc/sinks_async_ordering.cpp index 3f72ee8499..3c2fd10663 100644 --- a/example/doc/sinks_async_ordering.cpp +++ b/example/doc/sinks_async_ordering.cpp @@ -5,13 +5,13 @@ * http://www.boost.org/LICENSE_1_0.txt) */ +#include #include #include #include #include #include #include -#include #include #include #include @@ -62,7 +62,7 @@ boost::shared_ptr< sink_t > init_logging() backend, /*< pointer to the pre-initialized backend >*/ keywords::order = logging::make_attr_ordering< unsigned int >( /*< log record ordering predicate >*/ "LineID", std::less< unsigned int >()), - keywords::ordering_window = boost::posix_time::seconds(1) /*< latency of log record processing >*/ + keywords::ordering_window = std::chrono::seconds(1) /*< latency of log record processing >*/ )); core->add_sink(sink); diff --git a/example/doc/util_dynamic_type_disp.cpp b/example/doc/util_dynamic_type_disp.cpp index 7f0e3caf3d..b0ad722700 100644 --- a/example/doc/util_dynamic_type_disp.cpp +++ b/example/doc/util_dynamic_type_disp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include namespace logging = boost::log; @@ -85,13 +86,16 @@ int main(int, char*[]) // These two attributes are supported by the dispatcher bool res = print(my_value< std::string >("Hello world!")); assert(res); + boost::ignore_unused(res); res = print(my_value< double >(1.2)); assert(res); + boost::ignore_unused(res); // This one is not res = print(my_value< float >(-4.3f)); assert(!res); + boost::ignore_unused(res); return 0; } diff --git a/example/doc/util_static_type_disp.cpp b/example/doc/util_static_type_disp.cpp index a0adda130e..82862c6d31 100644 --- a/example/doc/util_static_type_disp.cpp +++ b/example/doc/util_static_type_disp.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -82,13 +83,16 @@ int main(int, char*[]) // These two attributes are supported by the dispatcher bool res = print(my_value< std::string >("Hello world!")); assert(res); + boost::ignore_unused(res); res = print(my_value< double >(1.2)); assert(res); + boost::ignore_unused(res); // This one is not res = print(my_value< float >(-4.3f)); assert(!res); + boost::ignore_unused(res); return 0; } diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index d876ec7a73..ab80036d4f 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -79,7 +79,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/keywords/Jamfile.v2 b/example/keywords/Jamfile.v2 index b53e1ede47..5742e17325 100644 --- a/example/keywords/Jamfile.v2 +++ b/example/keywords/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe keywords diff --git a/example/multiple_files/Jamfile.v2 b/example/multiple_files/Jamfile.v2 index 3edecd7ac2..a3f2d3f274 100644 --- a/example/multiple_files/Jamfile.v2 +++ b/example/multiple_files/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/multiple_files/main.cpp b/example/multiple_files/main.cpp index 0a1ce47d54..3605d6736d 100644 --- a/example/multiple_files/main.cpp +++ b/example/multiple_files/main.cpp @@ -19,10 +19,10 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include #include #include @@ -53,7 +53,7 @@ BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(my_logger, src::logger_mt) // This function is executed in a separate thread void thread_foo() { - BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); + BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", std::this_thread::get_id()); for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) { BOOST_LOG(my_logger::get()) << "Log record " << i; @@ -70,7 +70,7 @@ int main(int argc, char* argv[]) // Set up how the file names will be generated sink->locked_backend()->set_file_name_composer(sinks::file::as_file_name_composer( - expr::stream << "logs/" << expr::attr< boost::thread::id >("ThreadID") << ".log")); + expr::stream << "logs/" << expr::attr< std::thread::id >("ThreadID") << ".log")); // Set the log record formatter sink->set_formatter @@ -89,11 +89,12 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("RecordID", attrs::counter< unsigned int >()); // Create threads and make some logs - boost::thread_group threads; + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(&thread_foo); + threads[i] = std::thread(&thread_foo); - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); return 0; } diff --git a/example/multiple_threads/Jamfile.v2 b/example/multiple_threads/Jamfile.v2 index 6e1c9b70ee..330f1276e3 100644 --- a/example/multiple_threads/Jamfile.v2 +++ b/example/multiple_threads/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/multiple_threads/main.cpp b/example/multiple_threads/main.cpp index 2b005237ff..44f3640110 100644 --- a/example/multiple_threads/main.cpp +++ b/example/multiple_threads/main.cpp @@ -18,15 +18,13 @@ // #define BOOST_LOG_DYN_LINK 1 #include +#include #include #include #include -#include -#include #include #include -#include -#include +#include #include #include @@ -52,10 +50,10 @@ enum BOOST_LOG_INLINE_GLOBAL_LOGGER_DEFAULT(test_lg, src::logger_mt) //! This function is executed in multiple threads -void thread_fun(boost::barrier& bar) +void thread_fun(boost::compat::latch& latch) { // Wait until all threads are created - bar.wait(); + latch.arrive_and_wait(); // Now, do some logging for (unsigned int i = 0; i < LOG_RECORDS_TO_WRITE; ++i) @@ -97,13 +95,14 @@ int main(int argc, char* argv[]) logging::core::get()->add_global_attribute("ThreadID", attrs::current_thread_id()); // Create logging threads - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + boost::compat::latch latch(THREAD_COUNT); + std::thread threads[THREAD_COUNT]; for (unsigned int i = 0; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&thread_fun, boost::ref(bar))); + threads[i] = std::thread([&latch]() { thread_fun(latch); }); // Wait until all action ends - threads.join_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); return 0; } diff --git a/example/native_syslog/Jamfile.v2 b/example/native_syslog/Jamfile.v2 index 293d6900b8..de6c572a77 100644 --- a/example/native_syslog/Jamfile.v2 +++ b/example/native_syslog/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/rotating_file/Jamfile.v2 b/example/rotating_file/Jamfile.v2 index 4ea7f656fb..32f62ed9ab 100644 --- a/example/rotating_file/Jamfile.v2 +++ b/example/rotating_file/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/settings_file/Jamfile.v2 b/example/settings_file/Jamfile.v2 index 0eec5cf665..fc4af4d96b 100644 --- a/example/settings_file/Jamfile.v2 +++ b/example/settings_file/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe settings_file diff --git a/example/settings_file_custom_factories/Jamfile.v2 b/example/settings_file_custom_factories/Jamfile.v2 index 7c682a057e..72edb991b1 100644 --- a/example/settings_file_custom_factories/Jamfile.v2 +++ b/example/settings_file_custom_factories/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe settings_file_custom_factories diff --git a/example/syslog/Jamfile.v2 b/example/syslog/Jamfile.v2 index 3ed4362e55..4c8d181847 100644 --- a/example/syslog/Jamfile.v2 +++ b/example/syslog/Jamfile.v2 @@ -41,7 +41,6 @@ project /boost/log//boost_log /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem - /boost/thread//boost_thread multi ; diff --git a/example/trivial/Jamfile.v2 b/example/trivial/Jamfile.v2 index 1d89159ff1..aef9de78e8 100644 --- a/example/trivial/Jamfile.v2 +++ b/example/trivial/Jamfile.v2 @@ -42,7 +42,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread ; exe trivial diff --git a/example/wide_char/Jamfile.v2 b/example/wide_char/Jamfile.v2 index dab6836fe7..2a7477d6cf 100644 --- a/example/wide_char/Jamfile.v2 +++ b/example/wide_char/Jamfile.v2 @@ -43,7 +43,6 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem /boost/locale//boost_locale - /boost/thread//boost_thread multi # does not build on VxWorks due to lack of boost::locale support diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index acfc5f3cf0..fa06a0bdbf 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -24,10 +24,6 @@ #ifndef BOOST_LOG_NO_THREADS -#include -#include -#include - #if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first #define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD #elif defined(BOOST_WINDOWS) @@ -144,7 +140,10 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #elif defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD) #include +#include +#include #include +#include #include #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) @@ -177,7 +176,7 @@ class adaptive_mutex const int err = pthread_mutex_init(&m_State, NULL); #endif if (BOOST_UNLIKELY(err != 0)) - throw_exception< thread_resource_error >(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__); + throw_system_error(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__); } ~adaptive_mutex() @@ -191,7 +190,7 @@ class adaptive_mutex if (err == 0) return true; if (BOOST_UNLIKELY(err != EBUSY)) - throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__); + throw_system_error(err, "Failed to lock an adaptive mutex", "adaptive_mutex::try_lock()", __FILE__, __LINE__); return false; } @@ -199,7 +198,7 @@ class adaptive_mutex { const int err = pthread_mutex_lock(&m_State); if (BOOST_UNLIKELY(err != 0)) - throw_exception< lock_error >(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__); + throw_system_error(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__); } void unlock() @@ -212,10 +211,9 @@ class adaptive_mutex BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&)) private: - template< typename ExceptionT > - static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_exception(int err, const char* descr, const char* func, const char* file, int line) + static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_system_error(int err, const char* descr, const char* func, const char* file, int line) { - boost::throw_exception(ExceptionT(err, descr), boost::source_location(file, line, func)); + boost::throw_exception(std::system_error(std::error_code(err, std::system_category()), descr), boost::source_location(file, line, func)); } }; diff --git a/include/boost/log/detail/enqueued_record.hpp b/include/boost/log/detail/enqueued_record.hpp index a5c6e01811..e1926a68bf 100644 --- a/include/boost/log/detail/enqueued_record.hpp +++ b/include/boost/log/detail/enqueued_record.hpp @@ -17,10 +17,10 @@ #ifndef BOOST_LOG_DETAIL_ENQUEUED_RECORD_HPP_INCLUDED_ #define BOOST_LOG_DETAIL_ENQUEUED_RECORD_HPP_INCLUDED_ +#include #include #include #include -#include #include #include @@ -60,7 +60,7 @@ class enqueued_record } }; - boost::log::aux::timestamp m_timestamp; + std::chrono::steady_clock::time_point m_timestamp; record_view m_record; enqueued_record(enqueued_record const& that) BOOST_NOEXCEPT : m_timestamp(that.m_timestamp), m_record(that.m_record) @@ -72,7 +72,7 @@ class enqueued_record { } explicit enqueued_record(record_view const& rec) : - m_timestamp(boost::log::aux::get_timestamp()), + m_timestamp(std::chrono::steady_clock::now()), m_record(rec) { } diff --git a/include/boost/log/detail/event.hpp b/include/boost/log/detail/event.hpp index ff9951af26..05716d1c33 100644 --- a/include/boost/log/detail/event.hpp +++ b/include/boost/log/detail/event.hpp @@ -37,9 +37,9 @@ #include #define BOOST_LOG_EVENT_USE_WINAPI #else -#include -#include -#define BOOST_LOG_EVENT_USE_BOOST_CONDITION_VARIABLE +#include +#include +#define BOOST_LOG_EVENT_USE_STD_CONDITION_VARIABLE #endif #include @@ -130,8 +130,8 @@ typedef winapi_based_event event; class generic_event { private: - boost::mutex m_mutex; - boost::condition_variable m_cond; + std::mutex m_mutex; + std::condition_variable m_cond; bool m_state; public: diff --git a/include/boost/log/detail/locking_ptr.hpp b/include/boost/log/detail/locking_ptr.hpp index 7790c4dceb..1596ad13ab 100644 --- a/include/boost/log/detail/locking_ptr.hpp +++ b/include/boost/log/detail/locking_ptr.hpp @@ -17,9 +17,9 @@ #define BOOST_LOG_DETAIL_LOCKING_PTR_HPP_INCLUDED_ #include +#include // try_to_lock_t #include #include -#include #include #include #include @@ -66,7 +66,7 @@ class locking_ptr m_pLock->lock(); } //! Constructor - locking_ptr(shared_ptr< element_type > const& p, lockable_type& l, try_to_lock_t const&) : m_pElement(p), m_pLock(&l) + locking_ptr(shared_ptr< element_type > const& p, lockable_type& l, std::try_to_lock_t) : m_pElement(p), m_pLock(&l) { if (!m_pLock->try_lock()) { diff --git a/include/boost/log/detail/locks.hpp b/include/boost/log/detail/locks.hpp index fcc32a2c68..c5aae25568 100644 --- a/include/boost/log/detail/locks.hpp +++ b/include/boost/log/detail/locks.hpp @@ -17,6 +17,37 @@ #define BOOST_LOG_DETAIL_LOCKS_HPP_INCLUDED_ #include + +#ifndef BOOST_LOG_NO_THREADS + +#include +BOOST_MOVE_STD_NS_BEG + +// Forward declaration of the standard locks. Specified to avoid including and . +#if !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename > +class lock_guard; +#else +// MSVC 14.0 has a non-confogrming lock_guard +template< typename... > +class lock_guard; +#endif +template< typename > +class unique_lock; +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) +template< typename > +class shared_lock; +#endif +#if defined(__cpp_lib_scoped_lock) && (__cpp_lib_scoped_lock >= 201703l) +template< typename... > +class scoped_lock; +#endif + +BOOST_MOVE_STD_NS_END +#include + +#endif // BOOST_LOG_NO_THREADS + #include #ifdef BOOST_HAS_PRAGMA_ONCE diff --git a/include/boost/log/sinks/async_frontend.hpp b/include/boost/log/sinks/async_frontend.hpp index 79fade5b68..3e4a1d77da 100644 --- a/include/boost/log/sinks/async_frontend.hpp +++ b/include/boost/log/sinks/async_frontend.hpp @@ -15,6 +15,9 @@ #ifndef BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_ASYNC_FRONTEND_HPP_INCLUDED_ +#include +#include +#include #include // std::terminate #include @@ -32,10 +35,6 @@ #include #include #include -#include -#include -#include -#include #include #include #include @@ -133,7 +132,7 @@ class asynchronous_sink : private: //! Backend synchronization mutex type - typedef boost::recursive_mutex backend_mutex_type; + typedef std::recursive_mutex backend_mutex_type; //! Frontend synchronization mutex type typedef typename base_type::mutex_type frontend_mutex_type; @@ -191,11 +190,11 @@ class asynchronous_sink : { private: frontend_mutex_type& m_Mutex; - condition_variable_any& m_Cond; + std::condition_variable_any& m_Cond; boost::atomic< bool >& m_Flag; public: - explicit scoped_flag(frontend_mutex_type& mut, condition_variable_any& cond, boost::atomic< bool >& f) : + explicit scoped_flag(frontend_mutex_type& mut, std::condition_variable_any& cond, boost::atomic< bool >& f) : m_Mutex(mut), m_Cond(cond), m_Flag(f) { } @@ -203,7 +202,7 @@ class asynchronous_sink : { try { - lock_guard< frontend_mutex_type > lock(m_Mutex); + std::lock_guard< frontend_mutex_type > lock(m_Mutex); m_Flag.store(false, boost::memory_order_relaxed); m_Cond.notify_all(); } @@ -242,9 +241,9 @@ class asynchronous_sink : const shared_ptr< sink_backend_type > m_pBackend; //! Dedicated record feeding thread - thread m_DedicatedFeedingThread; + std::thread m_DedicatedFeedingThread; //! Condition variable to implement blocking operations - condition_variable_any m_BlockCond; + std::condition_variable_any m_BlockCond; //! Currently active operation operation m_ActiveOperation; @@ -318,15 +317,7 @@ class asynchronous_sink : */ ~asynchronous_sink() BOOST_NOEXCEPT BOOST_OVERRIDE { - try - { - boost::this_thread::disable_interruption no_interrupts; - stop(); - } - catch (...) - { - std::terminate(); - } + stop(); } /*! @@ -344,7 +335,7 @@ class asynchronous_sink : { if (BOOST_UNLIKELY(m_FlushRequested.load(boost::memory_order_acquire))) { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); // Wait until flush is done while (m_FlushRequested.load(boost::memory_order_acquire)) m_BlockCond.wait(lock); @@ -358,9 +349,7 @@ class asynchronous_sink : bool try_consume(record_view const& rec) BOOST_OVERRIDE { if (!m_FlushRequested.load(boost::memory_order_acquire)) - { return queue_base_type::try_enqueue(rec); - } else return false; } @@ -368,7 +357,7 @@ class asynchronous_sink : /*! * The method starts record feeding loop and effectively blocks until either of this happens: * - * \li the thread is interrupted due to either standard thread interruption or a call to \c stop + * \li the thread is interrupted due to a call to \c stop * \li an exception is thrown while processing a log record in the backend, and the exception is * not terminated by the exception handler, if one is installed * @@ -378,7 +367,7 @@ class asynchronous_sink : { // First check that no other thread is running { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (start_feeding_operation(lock, feeding_records)) return; } @@ -426,9 +415,9 @@ class asynchronous_sink : */ void stop() { - boost::thread feeding_thread; + std::thread feeding_thread; { - lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); m_StopRequested.store(true, boost::memory_order_release); queue_base_type::interrupt_dequeue(); @@ -449,7 +438,7 @@ class asynchronous_sink : { // First check that no other thread is running { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (start_feeding_operation(lock, feeding_records)) return; } @@ -468,7 +457,7 @@ class asynchronous_sink : void flush() BOOST_OVERRIDE { { - unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::unique_lock< frontend_mutex_type > lock(base_type::frontend_mutex()); if (static_cast< unsigned int >(m_ActiveOperation & feeding_records) != 0u) { // There is already a thread feeding records, let it do the job @@ -497,11 +486,11 @@ class asynchronous_sink : //! The method spawns record feeding thread void start_feeding_thread() { - boost::thread(run_func(this)).swap(m_DedicatedFeedingThread); + std::thread(run_func(this)).swap(m_DedicatedFeedingThread); } //! Starts record feeding operation. The method blocks or throws if another feeding operation is in progress. - bool start_feeding_operation(unique_lock< frontend_mutex_type >& lock, operation op) + bool start_feeding_operation(std::unique_lock< frontend_mutex_type >& lock, operation op) { while (m_ActiveOperation != idle) { @@ -527,7 +516,7 @@ class asynchronous_sink : { try { - lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); + std::lock_guard< frontend_mutex_type > lock(base_type::frontend_mutex()); m_ActiveOperation = idle; m_StopRequested.store(false, boost::memory_order_relaxed); m_BlockCond.notify_all(); diff --git a/include/boost/log/sinks/basic_sink_frontend.hpp b/include/boost/log/sinks/basic_sink_frontend.hpp index c446985e2b..b6409e317b 100644 --- a/include/boost/log/sinks/basic_sink_frontend.hpp +++ b/include/boost/log/sinks/basic_sink_frontend.hpp @@ -28,7 +28,6 @@ #if !defined(BOOST_LOG_NO_THREADS) #include #include -#include #include #include #include @@ -131,12 +130,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : { return m_Filter(attrs); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { if (m_ExceptionHandler.empty()) @@ -166,12 +159,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.consume(rec); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) @@ -191,10 +178,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : if (!backend_mutex.try_lock()) return false; } - catch (thread_interrupted&) - { - throw; - } catch (...) { boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); @@ -231,12 +214,6 @@ class BOOST_LOG_NO_VTABLE basic_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(m_Mutex);) @@ -464,12 +441,6 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : BOOST_LOG_EXPR_IF_MT(boost::log::aux::exclusive_lock_guard< BackendMutexT > lock(backend_mutex);) backend.consume(rec, context->m_FormattedRecord); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { BOOST_LOG_EXPR_IF_MT(boost::log::aux::shared_lock_guard< mutex_type > lock(this->frontend_mutex());) @@ -489,10 +460,6 @@ class BOOST_LOG_NO_VTABLE basic_formatting_sink_frontend : if (!backend_mutex.try_lock()) return false; } - catch (thread_interrupted&) - { - throw; - } catch (...) { boost::log::aux::shared_lock_guard< mutex_type > frontend_lock(this->frontend_mutex()); diff --git a/include/boost/log/sinks/block_on_overflow.hpp b/include/boost/log/sinks/block_on_overflow.hpp index 5bfcda2bcd..d5b3d1ff8a 100644 --- a/include/boost/log/sinks/block_on_overflow.hpp +++ b/include/boost/log/sinks/block_on_overflow.hpp @@ -26,10 +26,10 @@ #error Boost.Log: This header content is only supported in multithreaded environment #endif +#include #include #include #include -#include #include #include @@ -58,7 +58,7 @@ class block_on_overflow struct thread_context : public thread_context_hook_t { - condition_variable cond; + std::condition_variable cond; bool result; thread_context() : result(true) {} diff --git a/include/boost/log/sinks/bounded_fifo_queue.hpp b/include/boost/log/sinks/bounded_fifo_queue.hpp index 9a82b3ad39..227191e6d1 100644 --- a/include/boost/log/sinks/bounded_fifo_queue.hpp +++ b/include/boost/log/sinks/bounded_fifo_queue.hpp @@ -28,9 +28,8 @@ #include #include -#include -#include -#include +#include +#include #include #include @@ -64,13 +63,13 @@ class bounded_fifo_queue : private: typedef OverflowStrategyT overflow_strategy; typedef std::queue< record_view > queue_type; - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; private: //! Synchronization primitive mutex_type m_mutex; //! Condition to block the consuming thread on - condition_variable m_cond; + std::condition_variable m_cond; //! Log record queue queue_type m_queue; //! Interruption flag @@ -90,7 +89,7 @@ class bounded_fifo_queue : //! Enqueues log record to the queue void enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); std::size_t size = m_queue.size(); for (; size >= MaxQueueSizeV; size = m_queue.size()) { @@ -106,7 +105,7 @@ class bounded_fifo_queue : //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { const std::size_t size = m_queue.size(); @@ -133,7 +132,7 @@ class bounded_fifo_queue : //! Attempts to dequeue log record from the queue, does not block if the queue is empty bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { @@ -149,7 +148,7 @@ class bounded_fifo_queue : //! Dequeues log record from the queue, blocks if the queue is empty bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { @@ -174,7 +173,7 @@ class bounded_fifo_queue : //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; overflow_strategy::interrupt(); m_cond.notify_one(); diff --git a/include/boost/log/sinks/bounded_ordering_queue.hpp b/include/boost/log/sinks/bounded_ordering_queue.hpp index 157843f9ab..a457b4b3fd 100644 --- a/include/boost/log/sinks/bounded_ordering_queue.hpp +++ b/include/boost/log/sinks/bounded_ordering_queue.hpp @@ -29,13 +29,9 @@ #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -73,7 +69,7 @@ class bounded_ordering_queue : { private: typedef OverflowStrategyT overflow_strategy; - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; typedef sinks::aux::enqueued_record enqueued_record; typedef std::priority_queue< @@ -83,12 +79,12 @@ class bounded_ordering_queue : > queue_type; private: - //! Ordering window duration, in milliseconds - const uint64_t m_ordering_window; + //! Ordering window duration + const std::chrono::steady_clock::duration m_ordering_window; //! Synchronization primitive mutex_type m_mutex; //! Condition to block the consuming thread on - condition_variable m_cond; + std::condition_variable m_cond; //! Log record queue queue_type m_queue; //! Interruption flag @@ -98,16 +94,16 @@ class bounded_ordering_queue : /*! * Returns ordering window size specified during initialization */ - posix_time::time_duration get_ordering_window() const + std::chrono::steady_clock::duration get_ordering_window() const { - return posix_time::milliseconds(m_ordering_window); + return m_ordering_window; } /*! * Returns default ordering window size. * The default window size is specific to the operating system thread scheduling mechanism. */ - static posix_time::time_duration get_default_ordering_window() + static BOOST_CONSTEXPR std::chrono::steady_clock::duration get_default_ordering_window() BOOST_NOEXCEPT { // The main idea behind this parameter is that the ordering window should be large enough // to allow the frontend to order records from different threads on an attribute @@ -116,14 +112,14 @@ class bounded_ordering_queue : // For instance, on Windows it defaults to around 15-16 ms. // * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to // switch threads on any known OS. It can be tuned for other platforms as needed. - return posix_time::milliseconds(30); + return std::chrono::milliseconds(30); } protected: //! Initializing constructor template< typename ArgsT > explicit bounded_ordering_queue(ArgsT const& args) : - m_ordering_window(args[keywords::ordering_window || &bounded_ordering_queue::get_default_ordering_window].total_milliseconds()), + m_ordering_window(std::chrono::duration_cast< std::chrono::steady_clock::duration >(args[keywords::ordering_window || &bounded_ordering_queue::get_default_ordering_window])), m_queue(args[keywords::order]), m_interruption_requested(false) { @@ -132,7 +128,7 @@ class bounded_ordering_queue : //! Enqueues log record to the queue void enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); std::size_t size = m_queue.size(); for (; size >= MaxQueueSizeV; size = m_queue.size()) { @@ -148,7 +144,7 @@ class bounded_ordering_queue : //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { const std::size_t size = m_queue.size(); @@ -169,13 +165,13 @@ class bounded_ordering_queue : //! Attempts to dequeue a log record ready for processing from the queue, does not block if the queue is empty bool try_dequeue_ready(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window) + if ((now - elem.m_timestamp) >= m_ordering_window) { // We got a new element rec = elem.m_record; @@ -191,7 +187,7 @@ class bounded_ordering_queue : //! Attempts to dequeue log record from the queue, does not block if the queue is empty bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); const std::size_t size = m_queue.size(); if (size > 0) { @@ -208,16 +204,16 @@ class bounded_ordering_queue : //! Dequeues log record from the queue, blocks if the queue is empty bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { const std::size_t size = m_queue.size(); if (size > 0) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - const uint64_t difference = (now - elem.m_timestamp).milliseconds(); + const auto difference = now - elem.m_timestamp; if (difference >= m_ordering_window) { rec = elem.m_record; @@ -228,7 +224,7 @@ class bounded_ordering_queue : else { // Wait until the element becomes ready to be processed - m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference)); + m_cond.wait_for(lock, m_ordering_window - difference); } } else @@ -244,7 +240,7 @@ class bounded_ordering_queue : //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; overflow_strategy::interrupt(); m_cond.notify_one(); diff --git a/include/boost/log/sinks/sync_frontend.hpp b/include/boost/log/sinks/sync_frontend.hpp index 738b688055..a498cad14a 100644 --- a/include/boost/log/sinks/sync_frontend.hpp +++ b/include/boost/log/sinks/sync_frontend.hpp @@ -15,6 +15,7 @@ #ifndef BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_ #define BOOST_LOG_SINKS_SYNC_FRONTEND_HPP_INCLUDED_ +#include #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -29,7 +30,6 @@ #include #include #include -#include #include #include #include @@ -75,7 +75,7 @@ class synchronous_sink : private: //! Synchronization mutex type - typedef boost::recursive_mutex backend_mutex_type; + typedef std::recursive_mutex backend_mutex_type; public: //! Sink implementation type diff --git a/include/boost/log/sinks/unbounded_ordering_queue.hpp b/include/boost/log/sinks/unbounded_ordering_queue.hpp index c84d8fd4d8..df335f3220 100644 --- a/include/boost/log/sinks/unbounded_ordering_queue.hpp +++ b/include/boost/log/sinks/unbounded_ordering_queue.hpp @@ -28,13 +28,9 @@ #include #include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include #include #include #include @@ -69,7 +65,7 @@ template< typename OrderT > class unbounded_ordering_queue { private: - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; typedef sinks::aux::enqueued_record enqueued_record; typedef std::priority_queue< @@ -79,12 +75,12 @@ class unbounded_ordering_queue > queue_type; private: - //! Ordering window duration, in milliseconds - const uint64_t m_ordering_window; + //! Ordering window duration + const std::chrono::steady_clock::duration m_ordering_window; //! Synchronization mutex mutex_type m_mutex; //! Condition for blocking - condition_variable m_cond; + std::condition_variable m_cond; //! Thread-safe queue queue_type m_queue; //! Interruption flag @@ -94,16 +90,16 @@ class unbounded_ordering_queue /*! * Returns ordering window size specified during initialization */ - posix_time::time_duration get_ordering_window() const + std::chrono::steady_clock::duration get_ordering_window() const { - return posix_time::milliseconds(m_ordering_window); + return m_ordering_window; } /*! * Returns default ordering window size. * The default window size is specific to the operating system thread scheduling mechanism. */ - static posix_time::time_duration get_default_ordering_window() + static BOOST_CONSTEXPR std::chrono::steady_clock::duration get_default_ordering_window() BOOST_NOEXCEPT { // The main idea behind this parameter is that the ordering window should be large enough // to allow the frontend to order records from different threads on an attribute @@ -112,14 +108,14 @@ class unbounded_ordering_queue // For instance, on Windows it defaults to around 15-16 ms. // * No less than thread switching quant on the current OS. For now 30 ms is large enough window size to // switch threads on any known OS. It can be tuned for other platforms as needed. - return posix_time::milliseconds(30); + return std::chrono::milliseconds(30); } protected: //! Initializing constructor template< typename ArgsT > explicit unbounded_ordering_queue(ArgsT const& args) : - m_ordering_window(args[keywords::ordering_window || &unbounded_ordering_queue::get_default_ordering_window].total_milliseconds()), + m_ordering_window(std::chrono::duration_cast< std::chrono::steady_clock::duration >(args[keywords::ordering_window || &unbounded_ordering_queue::get_default_ordering_window])), m_queue(args[keywords::order]), m_interruption_requested(false) { @@ -128,14 +124,14 @@ class unbounded_ordering_queue //! Enqueues log record to the queue void enqueue(record_view const& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); enqueue_unlocked(rec); } //! Attempts to enqueue log record to the queue bool try_enqueue(record_view const& rec) { - unique_lock< mutex_type > lock(m_mutex, try_to_lock); + std::unique_lock< mutex_type > lock(m_mutex, std::try_to_lock); if (lock.owns_lock()) { enqueue_unlocked(rec); @@ -148,12 +144,12 @@ class unbounded_ordering_queue //! Attempts to dequeue a log record ready for processing from the queue, does not block if no log records are ready to be processed bool try_dequeue_ready(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - if (static_cast< uint64_t >((now - elem.m_timestamp).milliseconds()) >= m_ordering_window) + if ((now - elem.m_timestamp) >= m_ordering_window) { // We got a new element rec = elem.m_record; @@ -168,7 +164,7 @@ class unbounded_ordering_queue //! Attempts to dequeue log record from the queue, does not block. bool try_dequeue(record_view& rec) { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); if (!m_queue.empty()) { enqueued_record const& elem = m_queue.top(); @@ -183,14 +179,14 @@ class unbounded_ordering_queue //! Dequeues log record from the queue, blocks if no log records are ready to be processed bool dequeue_ready(record_view& rec) { - unique_lock< mutex_type > lock(m_mutex); + std::unique_lock< mutex_type > lock(m_mutex); while (!m_interruption_requested) { if (!m_queue.empty()) { - const boost::log::aux::timestamp now = boost::log::aux::get_timestamp(); + const auto now = std::chrono::steady_clock::now(); enqueued_record const& elem = m_queue.top(); - const uint64_t difference = (now - elem.m_timestamp).milliseconds(); + const auto difference = now - elem.m_timestamp; if (difference >= m_ordering_window) { // We got a new element @@ -201,7 +197,7 @@ class unbounded_ordering_queue else { // Wait until the element becomes ready to be processed - m_cond.timed_wait(lock, posix_time::milliseconds(m_ordering_window - difference)); + m_cond.wait_for(lock, m_ordering_window - difference); } } else @@ -218,7 +214,7 @@ class unbounded_ordering_queue //! Wakes a thread possibly blocked in the \c dequeue method void interrupt_dequeue() { - lock_guard< mutex_type > lock(m_mutex); + std::lock_guard< mutex_type > lock(m_mutex); m_interruption_requested = true; m_cond.notify_one(); } diff --git a/include/boost/log/sources/exception_handler_feature.hpp b/include/boost/log/sources/exception_handler_feature.hpp index feedc247d8..b2b1acde56 100644 --- a/include/boost/log/sources/exception_handler_feature.hpp +++ b/include/boost/log/sources/exception_handler_feature.hpp @@ -26,9 +26,6 @@ #include #include #include -#if !defined(BOOST_LOG_NO_THREADS) -#include -#endif #include #ifdef BOOST_HAS_PRAGMA_ONCE @@ -155,12 +152,6 @@ class basic_exception_handler_logger : { return base_type::open_record_unlocked(args); } -#ifndef BOOST_LOG_NO_THREADS - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { handle_exception(); @@ -177,12 +168,6 @@ class basic_exception_handler_logger : { base_type::push_record_unlocked(boost::move(rec)); } -#ifndef BOOST_LOG_NO_THREADS - catch (thread_interrupted&) - { - throw; - } -#endif catch (...) { handle_exception(); diff --git a/include/boost/log/utility/strictest_lock.hpp b/include/boost/log/utility/strictest_lock.hpp index e40e400f6e..2b5ac9fa0c 100644 --- a/include/boost/log/utility/strictest_lock.hpp +++ b/include/boost/log/utility/strictest_lock.hpp @@ -73,6 +73,37 @@ struct thread_access_mode_of< no_lock< MutexT > > : boost::integral_constant< lo #if !defined(BOOST_LOG_NO_THREADS) +#if !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename MutexT > +struct thread_access_mode_of< std::lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#else // !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) +template< typename... MutexesT > +struct thread_access_mode_of< std::lock_guard< MutexesT... > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#endif // !defined(BOOST_MSSTL_VERSION) || (BOOST_MSSTL_VERSION != 140) + +template< typename MutexT > +struct thread_access_mode_of< std::unique_lock< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; + +#if !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) +template< typename MutexT > +struct thread_access_mode_of< std::shared_lock< MutexT > > : boost::integral_constant< lock_access_mode, shared_access > +{ +}; +#endif // !defined(BOOST_NO_CXX14_HDR_SHARED_MUTEX) + +#if defined(__cpp_lib_scoped_lock) && (__cpp_lib_scoped_lock >= 201703l) +template< typename... MutexesT > +struct thread_access_mode_of< std::scoped_lock< MutexesT... > > : boost::integral_constant< lock_access_mode, exclusive_access > +{ +}; +#endif + template< typename MutexT > struct thread_access_mode_of< lock_guard< MutexT > > : boost::integral_constant< lock_access_mode, exclusive_access > { diff --git a/src/core.cpp b/src/core.cpp index 657de0eb8d..1da9d30728 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -26,7 +27,6 @@ #include #include #include -#include #include #include #include @@ -40,7 +40,6 @@ #include #include #include -#include #include #include #include @@ -250,7 +249,8 @@ struct core::implementation : //! Creates a seed for RNG static uint32_t get_random_seed() { - uint32_t seed = static_cast< uint32_t >(posix_time::microsec_clock::universal_time().time_of_day().ticks()); + uint64_t now = static_cast< uint64_t >(std::chrono::system_clock::now().time_since_epoch().count()); + uint32_t seed = static_cast< uint32_t >(now) ^ static_cast< uint32_t >(now >> 32u); #if !defined(BOOST_LOG_NO_THREADS) seed += static_cast< uint32_t >(log::aux::this_thread::get_id().native_id()); #endif @@ -369,14 +369,6 @@ struct core::implementation : } } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - if (rec_impl) - rec_impl->destroy(); - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (rec_impl) @@ -463,12 +455,6 @@ struct core::implementation : impl->push_back_accepting_sink(sink); } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_exception_handler.empty()) @@ -644,12 +630,6 @@ BOOST_LOG_API void core::flush() { it->get()->flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_impl->m_exception_handler.empty()) @@ -664,12 +644,6 @@ BOOST_LOG_API void core::flush() { m_impl->m_default_sink->flush(); } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { if (m_impl->m_exception_handler.empty()) @@ -762,12 +736,6 @@ BOOST_LOG_API void core::push_record_move(record& rec) else break; } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { // Lock the core to be safe against any attribute or sink set modifications @@ -782,12 +750,6 @@ BOOST_LOG_API void core::push_record_move(record& rec) end->swap(*it); } } -#if !defined(BOOST_LOG_NO_THREADS) - catch (thread_interrupted&) - { - throw; - } -#endif // !defined(BOOST_LOG_NO_THREADS) catch (...) { // Lock the core to be safe against any attribute or sink set modifications diff --git a/src/default_sink.cpp b/src/default_sink.cpp index 00188f35fb..72d0aa2173 100644 --- a/src/default_sink.cpp +++ b/src/default_sink.cpp @@ -17,7 +17,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include +#include #include #endif #include @@ -207,14 +207,14 @@ bool default_sink::will_consume(attribute_value_set const&) void default_sink::consume(record_view const& rec) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_mutex);) m_message_visitor(m_message_name, rec.attribute_values(), message_printer(m_severity_extractor(m_severity_name, rec).get())); std::fflush(stdout); } void default_sink::flush() { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex_type > lock(m_mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_mutex);) std::fflush(stdout); } diff --git a/src/default_sink.hpp b/src/default_sink.hpp index ed2c033886..a89b862aaa 100644 --- a/src/default_sink.hpp +++ b/src/default_sink.hpp @@ -25,7 +25,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include +#include #endif #include @@ -47,7 +47,7 @@ class default_sink : { private: #if !defined(BOOST_LOG_NO_THREADS) - typedef mutex mutex_type; + typedef std::mutex mutex_type; mutex_type m_mutex; #endif attribute_name const m_severity_name, m_message_name; diff --git a/src/event.cpp b/src/event.cpp index bbc033e7a2..16f3f451bb 100644 --- a/src/event.cpp +++ b/src/event.cpp @@ -45,7 +45,7 @@ #else -#include +#include #endif @@ -222,7 +222,7 @@ BOOST_LOG_API generic_event::~generic_event() //! Waits for the object to become signalled BOOST_LOG_API void generic_event::wait() { - boost::unique_lock< boost::mutex > lock(m_mutex); + std::unique_lock< std::mutex > lock(m_mutex); while (!m_state) { m_cond.wait(lock); @@ -233,7 +233,7 @@ BOOST_LOG_API void generic_event::wait() //! Sets the object to a signalled state BOOST_LOG_API void generic_event::set_signalled() { - boost::lock_guard< boost::mutex > lock(m_mutex); + std::lock_guard< std::mutex > lock(m_mutex); if (!m_state) { m_state = true; diff --git a/src/global_logger_storage.cpp b/src/global_logger_storage.cpp index 6662f19f34..abb5bc346f 100644 --- a/src/global_logger_storage.cpp +++ b/src/global_logger_storage.cpp @@ -23,8 +23,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include @@ -47,7 +46,7 @@ struct loggers_repository : #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization primitive - mutable mutex m_Mutex; + mutable std::mutex m_Mutex; #endif //! Map of logger holders loggers_map_t m_Loggers; @@ -61,7 +60,7 @@ BOOST_LOG_API shared_ptr< logger_holder_base > global_storage::get_or_init(typei typedef loggers_repository::loggers_map_t loggers_map_t; loggers_repository& repo = loggers_repository::get(); - BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex > lock(repo.m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(repo.m_Mutex);) loggers_map_t::iterator it = repo.m_Loggers.find(key); if (it != repo.m_Loggers.end()) { diff --git a/src/once_block.cpp b/src/once_block.cpp index c76009da0a..67326d02b0 100644 --- a/src/once_block.cpp +++ b/src/once_block.cpp @@ -108,12 +108,11 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #else // BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 #include // atexit +#include +#include #include #include #include -#include -#include -#include #include namespace boost { @@ -229,13 +228,13 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { public once_block_impl_base { private: - mutex m_Mutex; - condition_variable m_Cond; + std::mutex m_Mutex; + std::condition_variable m_Cond; public: bool enter_once_block(once_block_flag volatile& flag) { - unique_lock< mutex > lock(m_Mutex); + std::unique_lock< std::mutex > lock(m_Mutex); while (flag.status != once_block_flag::initialized) { @@ -261,7 +260,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { void commit(once_block_flag& flag) { { - lock_guard< mutex > lock(m_Mutex); + std::lock_guard< std::mutex > lock(m_Mutex); flag.status = once_block_flag::initialized; } m_Cond.notify_all(); @@ -270,7 +269,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { void rollback(once_block_flag& flag) { { - lock_guard< mutex > lock(m_Mutex); + std::lock_guard< std::mutex > lock(m_Mutex); flag.status = once_block_flag::uninitialized; } m_Cond.notify_all(); diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 978a6a2052..de639df08a 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -866,7 +866,7 @@ template< typename CharT > BOOST_LOG_SETUP_API void register_sink_factory(const char* sink_name, shared_ptr< sink_factory< CharT > > const& factory) { sinks_repository< CharT >& repo = sinks_repository< CharT >::get(); - BOOST_LOG_EXPR_IF_MT(lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);) + BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< log::aux::light_rw_mutex > lock(repo.m_Mutex);) repo.m_Factories[sink_name] = factory; } diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index e505893053..15a47e3929 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -43,8 +43,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include "unique_ptr.hpp" @@ -125,14 +124,14 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Syslog service initializer (implemented as a weak singleton) #if !defined(BOOST_LOG_NO_THREADS) class native_syslog_initializer : - private log::aux::lazy_singleton< native_syslog_initializer, mutex > + private log::aux::lazy_singleton< native_syslog_initializer, std::mutex > #else class native_syslog_initializer #endif { #if !defined(BOOST_LOG_NO_THREADS) - friend class log::aux::lazy_singleton< native_syslog_initializer, mutex >; - typedef log::aux::lazy_singleton< native_syslog_initializer, mutex > mutex_holder; + friend class log::aux::lazy_singleton< native_syslog_initializer, std::mutex >; + typedef log::aux::lazy_singleton< native_syslog_initializer, std::mutex > mutex_holder; #endif private: @@ -163,7 +162,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { static shared_ptr< native_syslog_initializer > get_instance(std::string const& ident, int facility) { #if !defined(BOOST_LOG_NO_THREADS) - lock_guard< mutex > lock(mutex_holder::get()); + std::lock_guard< std::mutex > lock(mutex_holder::get()); #endif static weak_ptr< native_syslog_initializer > instance; shared_ptr< native_syslog_initializer > p(instance.lock()); @@ -354,7 +353,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { #if !defined(BOOST_LOG_NO_THREADS) //! A synchronization primitive to protect the host name resolver - mutex m_Mutex; + std::mutex m_Mutex; //! The resolver is used to acquire connection endpoints asio::ip::udp::resolver m_HostNameResolver; #endif // !defined(BOOST_LOG_NO_THREADS) @@ -539,7 +538,7 @@ BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, un asio::ip::udp::endpoint local_address; { - lock_guard< mutex > lock(impl->m_pService->m_Mutex); + std::lock_guard< std::mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( impl->m_Protocol, @@ -585,7 +584,7 @@ BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, u asio::ip::udp::endpoint remote_address; { - lock_guard< mutex > lock(impl->m_pService->m_Mutex); + std::lock_guard< std::mutex > lock(impl->m_pService->m_Mutex); asio::ip::udp::resolver::results_type results = impl->m_pService->m_HostNameResolver.resolve ( impl->m_Protocol, diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index a147518ed0..6c2e8633b2 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -58,8 +58,7 @@ #include "unique_ptr.hpp" #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif // !defined(BOOST_LOG_NO_THREADS) #include @@ -674,7 +673,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex - mutex m_Mutex; + std::mutex m_Mutex; #endif // !defined(BOOST_LOG_NO_THREADS) //! Total file size upper limit @@ -765,7 +764,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { private: #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex - mutex m_Mutex; + std::mutex m_Mutex; #endif // !defined(BOOST_LOG_NO_THREADS) //! The list of file collectors file_collectors m_Collectors; @@ -864,7 +863,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::create_directories(m_StorageDir); } - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_list::iterator it = m_Files.begin(); const file_list::iterator end = m_Files.end(); @@ -982,7 +981,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { filesystem::file_status status = filesystem::status(dir, ec); if (status.type() == filesystem::directory_file) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_list files; filesystem::directory_iterator it(dir), end; @@ -1031,7 +1030,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! The function updates storage restrictions void file_collector::update(uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) m_MaxSize = (std::min)(m_MaxSize, max_size); m_MinFreeSpace = (std::max)(m_MinFreeSpace, min_free_space); @@ -1043,7 +1042,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { shared_ptr< file::collector > file_collector_repository::get_collector( filesystem::path const& target_dir, uintmax_t max_size, uintmax_t min_free_space, uintmax_t max_files) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) file_collectors::iterator it = std::find_if(m_Collectors.begin(), m_Collectors.end(), [&target_dir](file_collector const& collector) { return collector.is_governed(target_dir); }); @@ -1071,7 +1070,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! Removes the file collector from the list void file_collector_repository::remove_collector(file_collector* p) { - BOOST_LOG_EXPR_IF_MT(lock_guard< mutex > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< std::mutex > lock(m_Mutex);) m_Collectors.erase(m_Collectors.iterator_to(*p)); } diff --git a/src/thread_id.cpp b/src/thread_id.cpp index e3a70a4626..c80d7ab69d 100644 --- a/src/thread_id.cpp +++ b/src/thread_id.cpp @@ -29,7 +29,7 @@ #include #include #elif defined(BOOST_WINDOWS) -#include +#include // at_thread_exit #include #else #include diff --git a/src/timer.cpp b/src/timer.cpp index db55ea7bcd..928900ccd2 100644 --- a/src/timer.cpp +++ b/src/timer.cpp @@ -22,8 +22,7 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) -#include -#include +#include #endif #include #include @@ -41,7 +40,7 @@ class BOOST_SYMBOL_VISIBLE timer::impl : private: #if !defined(BOOST_LOG_NO_THREADS) //! Synchronization mutex type - typedef boost::mutex mutex_type; + typedef std::mutex mutex_type; //! Synchronization mutex mutex_type m_Mutex; #endif @@ -70,7 +69,7 @@ class BOOST_SYMBOL_VISIBLE timer::impl : { uint64_t duration; { - BOOST_LOG_EXPR_IF_MT(log::aux::exclusive_lock_guard< mutex_type > lock(m_Mutex);) + BOOST_LOG_EXPR_IF_MT(std::lock_guard< mutex_type > lock(m_Mutex);) LARGE_INTEGER li; QueryPerformanceCounter(&li); diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 34a8324fbb..a3bb840f1e 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -55,7 +55,6 @@ project /boost/filesystem//boost_filesystem /boost/test//boost_unit_test_framework single:BOOST_LOG_NO_THREADS - multi:/boost/thread//boost_thread : default-build # Testers typically don't specify threading environment and the library can be built and tested for single and multi. I'm more interested in multi though. multi diff --git a/test/common/test_barrier.hpp b/test/common/test_barrier.hpp new file mode 100644 index 0000000000..72b2a26f11 --- /dev/null +++ b/test/common/test_barrier.hpp @@ -0,0 +1,62 @@ +// Copyright (c) 2024 Andrey Semashev +// +// Distributed under the Boost Software License, Version 1.0. +// See accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) + +#ifndef BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ +#define BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ + +#include +#include + +//! A simplified version of thread barrier from Boost.Thread and C++20 std::barrier +class test_barrier +{ +private: + std::mutex m_mutex; + std::condition_variable m_cond; + unsigned int m_generation; + unsigned int m_count; + const unsigned int m_initial_count; + +public: + explicit test_barrier(unsigned int initial_count) : + m_generation(0u), m_count(initial_count), m_initial_count(initial_count) + { + } + + test_barrier(test_barrier const&) = delete; + test_barrier& operator= (test_barrier const&) = delete; + + void arrive_and_wait() + { + std::unique_lock< std::mutex > lock(m_mutex); + + --m_count; + if (m_count == 0u) + { + ++m_generation; + m_count = m_initial_count; + m_cond.notify_all(); + return; + } + + const unsigned int generation = m_generation; + do + { + m_cond.wait(lock); + } + while (m_generation == generation); + } + + void wake_all() + { + std::lock_guard< std::mutex > lock(m_mutex); + ++m_generation; + m_count = m_initial_count; + m_cond.notify_all(); + } +}; + +#endif // BOOST_LOG_TEST_BARRIER_HPP_INCLUDED_ diff --git a/test/performance/record_emission.cpp b/test/performance/record_emission.cpp index 0dd388cb05..92446cace8 100644 --- a/test/performance/record_emission.cpp +++ b/test/performance/record_emission.cpp @@ -17,16 +17,13 @@ // #define BOOST_LOG_DYN_LINK 1 #define BOOST_NO_DYN_LINK 1 +#include +#include +#include #include #include -#include -#include #include #include -#include -#include -#include -#include #include #include @@ -39,6 +36,8 @@ #include +#include "test_barrier.hpp" + enum config { RECORD_COUNT = 20000000, @@ -76,12 +75,12 @@ namespace { } // namespace -void test(unsigned int record_count, boost::barrier& bar) +void test(unsigned int record_count, test_barrier& bar) { BOOST_LOG_SCOPED_THREAD_TAG("ThreadID", boost::this_thread::get_id()); src::severity_logger< severity_level > slg; // src::logger lg; - bar.wait(); + bar.arrive_and_wait(); for (unsigned int i = 0; i < record_count; ++i) { @@ -93,7 +92,6 @@ void test(unsigned int record_count, boost::barrier& bar) int main(int argc, char* argv[]) { std::cout << "Test config: " << THREAD_COUNT << " threads, " << SINK_COUNT << " sinks, " << RECORD_COUNT << " records" << std::endl; -//__debugbreak(); // typedef sinks::unlocked_sink< fake_backend > fake_sink; // typedef sinks::synchronous_sink< fake_backend > fake_sink; typedef sinks::asynchronous_sink< fake_backend > fake_sink; @@ -110,19 +108,19 @@ int main(int argc, char* argv[]) // logging::core::get()->set_filter(severity > error); // all records don't pass the filter const unsigned int record_count = RECORD_COUNT / THREAD_COUNT; - boost::barrier bar(THREAD_COUNT); - boost::thread_group threads; + test_barrier bar(THREAD_COUNT); + std::vector< std::thread > threads(THREAD_COUNT - 1); - for (unsigned int i = 1; i < THREAD_COUNT; ++i) - threads.create_thread(boost::bind(&test, record_count, boost::ref(bar))); + for (unsigned int i = 0; i < THREAD_COUNT - 1; ++i) + threads[i] = std::thread([&bar, record_count]() { test(record_count, bar); }); - boost::posix_time::ptime start = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(), end; + const auto start = std::chrono::steady_clock::now(); test(record_count, bar); - if (THREAD_COUNT > 1) - threads.join_all(); - end = boost::date_time::microsec_clock< boost::posix_time::ptime >::universal_time(); + for (unsigned int i = 0; i < THREAD_COUNT - 1; ++i) + threads[i].join(); + const auto finish = std::chrono::steady_clock::now(); - unsigned long long duration = (end - start).total_microseconds(); + unsigned long long duration_us = std::chrono::duration_cast< std::chrono::microseconds >(finish - start).count(); std::cout << "Test duration: " << duration << " us (" << std::fixed << std::setprecision(3) << static_cast< double >(RECORD_COUNT) / (static_cast< double >(duration) / 1000000.0) diff --git a/test/run/core.cpp b/test/run/core.cpp index 69b42647a2..99ff64e743 100644 --- a/test/run/core.cpp +++ b/test/run/core.cpp @@ -28,7 +28,7 @@ #include #include #ifndef BOOST_LOG_NO_THREADS -#include +#include #endif // BOOST_LOG_NO_THREADS #include "char_definitions.hpp" #include "test_sink.hpp" @@ -221,7 +221,7 @@ BOOST_AUTO_TEST_CASE(attributes) } #ifndef BOOST_LOG_NO_THREADS { - boost::thread th(&thread_attributes_test); + std::thread th(&thread_attributes_test); th.join(); BOOST_CHECK_EQUAL(pSink->m_RecordCounter, 1UL); BOOST_CHECK_EQUAL(pSink->m_Consumed[data::attr1()], 0UL); diff --git a/test/run/util_ipc_reliable_mq.cpp b/test/run/util_ipc_reliable_mq.cpp index aae22f2a0b..62732590a3 100644 --- a/test/run/util_ipc_reliable_mq.cpp +++ b/test/run/util_ipc_reliable_mq.cpp @@ -39,11 +39,10 @@ #include #include #if !defined(BOOST_LOG_NO_THREADS) +#include +#include #include -#include #include -#include -#include #endif #include "char_definitions.hpp" @@ -351,9 +350,9 @@ BOOST_AUTO_TEST_CASE(multithreaded_message_passing) unsigned int failure_count1 = 0, failure_count2 = 0, failure_count3 = 0; boost::atomic_thread_fence(boost::memory_order_release); - boost::thread thread1(&multithreaded_message_passing_feeding_thread, "Thread 1", boost::ref(failure_count1)); - boost::thread thread2(&multithreaded_message_passing_feeding_thread, "Thread 2", boost::ref(failure_count2)); - boost::thread thread3(&multithreaded_message_passing_feeding_thread, "Thread 3", boost::ref(failure_count3)); + std::thread thread1([&failure_count1]() { multithreaded_message_passing_feeding_thread("Thread 1", failure_count1); }); + std::thread thread2([&failure_count2]() { multithreaded_message_passing_feeding_thread("Thread 2", failure_count2); }); + std::thread thread3([&failure_count3]() { multithreaded_message_passing_feeding_thread("Thread 3", failure_count3); }); BOOST_TEST_PASSPOINT(); @@ -447,14 +446,14 @@ BOOST_AUTO_TEST_CASE(stop_reset_local) BOOST_TEST_PASSPOINT(); // Case 1: Let the feeder block and then we unblock it with stop_local() - boost::thread feeder_thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 3); - boost::thread reader_thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 1); + std::thread feeder_thread([&feeder_queue, &feeder_results]() { stop_reset_feeding_thread(feeder_queue, feeder_results, 3); }); + std::thread reader_thread([&reader_queue, &reader_results]() { stop_reset_reading_thread(reader_queue, reader_results, 1); }); BOOST_TEST_PASSPOINT(); reader_thread.join(); BOOST_TEST_PASSPOINT(); - boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); BOOST_TEST_PASSPOINT(); @@ -480,14 +479,14 @@ BOOST_AUTO_TEST_CASE(stop_reset_local) BOOST_TEST_PASSPOINT(); // Case 2: Let the reader block and then we unblock it with stop_local() - boost::thread(&stop_reset_feeding_thread, boost::ref(feeder_queue), feeder_results, 1).swap(feeder_thread); - boost::thread(&stop_reset_reading_thread, boost::ref(reader_queue), reader_results, 2).swap(reader_thread); + feeder_thread = std::thread([&feeder_queue, &feeder_results]() { stop_reset_feeding_thread(feeder_queue, feeder_results, 1); }); + reader_thread = std::thread([&reader_queue, &reader_results]() { stop_reset_reading_thread(reader_queue, reader_results, 2); }); BOOST_TEST_PASSPOINT(); feeder_thread.join(); BOOST_TEST_PASSPOINT(); - boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); + std::this_thread::sleep_for(std::chrono::milliseconds(500)); BOOST_TEST_PASSPOINT(); diff --git a/test/run/util_once_block.cpp b/test/run/util_once_block.cpp index 4149c74284..ced2e94f44 100644 --- a/test/run/util_once_block.cpp +++ b/test/run/util_once_block.cpp @@ -21,12 +21,9 @@ #if !defined(BOOST_LOG_NO_THREADS) -#include -#include -#include -#include -#include -#include +#include +#include +#include "test_barrier.hpp" namespace logging = boost::log; @@ -36,8 +33,8 @@ enum config LOOP_COUNT = 100 }; -boost::mutex m; -typedef boost::lock_guard< boost::mutex > scoped_lock; +std::mutex m; +typedef std::lock_guard< std::mutex > scoped_lock; logging::once_block_flag flag = BOOST_LOG_ONCE_BLOCK_INIT; int var_to_init_once_flag = 0; @@ -50,10 +47,10 @@ void initialize_variable() } -void once_block_flag_thread(boost::barrier& barrier) +void once_block_flag_thread(test_barrier& barrier) { int my_once_value = 0; - barrier.wait(); + barrier.arrive_and_wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK_FLAG(flag) @@ -74,21 +71,25 @@ void once_block_flag_thread(boost::barrier& barrier) // The test checks if the BOOST_LOG_ONCE_BLOCK_FLAG macro works BOOST_AUTO_TEST_CASE(once_block_flag) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_flag_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_flag_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; } @@ -97,10 +98,10 @@ BOOST_AUTO_TEST_CASE(once_block_flag) int var_to_init_once = 0; -void once_block_thread(boost::barrier& barrier) +void once_block_thread(test_barrier& barrier) { int my_once_value = 0; - barrier.wait(); + barrier.arrive_and_wait(); for (unsigned int i = 0; i < LOOP_COUNT; ++i) { BOOST_LOG_ONCE_BLOCK() @@ -123,21 +124,25 @@ void once_block_thread(boost::barrier& barrier) // The test checks if the BOOST_LOG_ONCE_BLOCK macro works BOOST_AUTO_TEST_CASE(once_block) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } - catch(...) + catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; } @@ -152,9 +157,9 @@ struct my_exception unsigned int pass_counter = 0; unsigned int exception_counter = 0; -void once_block_with_exception_thread(boost::barrier& barrier) +void once_block_with_exception_thread(test_barrier& barrier) { - barrier.wait(); + barrier.arrive_and_wait(); try { BOOST_LOG_ONCE_BLOCK() @@ -177,21 +182,25 @@ void once_block_with_exception_thread(boost::barrier& barrier) // The test verifies that the once_block flag is not set if an exception is thrown from the once-block BOOST_AUTO_TEST_CASE(once_block_retried_on_exception) { - boost::thread_group group; - boost::barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); + std::thread threads[THREAD_COUNT]; + test_barrier barrier(static_cast< unsigned int >(THREAD_COUNT)); try { for (unsigned int i = 0; i < THREAD_COUNT; ++i) - { - group.create_thread(boost::bind(&once_block_with_exception_thread, boost::ref(barrier))); - } - group.join_all(); + threads[i] = std::thread([&barrier]() { once_block_with_exception_thread(barrier); }); + + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + threads[i].join(); } - catch(...) + catch (...) { - group.interrupt_all(); - group.join_all(); + barrier.wake_all(); + for (unsigned int i = 0; i < THREAD_COUNT; ++i) + { + if (threads[i].joinable()) + threads[i].join(); + } throw; } From 028247d2e6f4d55713d26c0250ce9b762148db2c Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 19 Aug 2024 02:39:07 +0300 Subject: [PATCH 254/309] Updated dependencies in CMakeLists.txt. Removed unused dependences, made Boost.WinAPI Windows-specific. --- CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ba2f46fd2f..8817719a45 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -471,10 +471,8 @@ target_include_directories(boost_log target_link_libraries(boost_log PUBLIC - Boost::array Boost::assert Boost::config - Boost::container Boost::core Boost::date_time Boost::filesystem @@ -490,13 +488,11 @@ target_link_libraries(boost_log Boost::proto Boost::range Boost::smart_ptr - Boost::static_assert Boost::system Boost::throw_exception Boost::type_index Boost::type_traits Boost::utility - Boost::winapi PRIVATE Boost::align @@ -510,6 +506,13 @@ target_link_libraries(boost_log ${boost_log_regex_backend_private_libs} ) +if (WIN32 OR CYGWIN) + target_link_libraries(boost_log + PUBLIC + Boost::winapi + ) +endif() + if (NOT BOOST_LOG_NO_THREADS) target_link_libraries(boost_log PUBLIC From c126392841ac785157abf34215cc7080d79efcf1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 29 Sep 2024 19:30:32 +0300 Subject: [PATCH 255/309] Switched from atomic_count to Boost.Atomic for reference counting. This avoids including a deprecated header from Boost.SmartPtr implementation details. Closes https://github.com/boostorg/log/pull/236. --- include/boost/log/core/record_view.hpp | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/include/boost/log/core/record_view.hpp b/include/boost/log/core/record_view.hpp index 7a3867760b..0455b3933c 100644 --- a/include/boost/log/core/record_view.hpp +++ b/include/boost/log/core/record_view.hpp @@ -23,7 +23,8 @@ #include #include #ifndef BOOST_LOG_NO_THREADS -#include +#include +#include #endif // BOOST_LOG_NO_THREADS #include @@ -63,19 +64,34 @@ class record_view //! Publicly available record data struct public_data { + private: //! Reference counter #ifndef BOOST_LOG_NO_THREADS - mutable boost::detail::atomic_count m_ref_counter; + mutable boost::atomic< unsigned int > m_ref_counter; + + friend void intrusive_ptr_add_ref(const public_data* p) BOOST_NOEXCEPT + { + p->m_ref_counter.opaque_add(1u, boost::memory_order_relaxed); + } + friend void intrusive_ptr_release(const public_data* p) BOOST_NOEXCEPT + { + if (!p->m_ref_counter.sub_and_test(1u, boost::memory_order_acq_rel)) + public_data::destroy(p); + } #else mutable unsigned int m_ref_counter; + + friend void intrusive_ptr_add_ref(const public_data* p) BOOST_NOEXCEPT { ++p->m_ref_counter; } + friend void intrusive_ptr_release(const public_data* p) BOOST_NOEXCEPT { if (--p->m_ref_counter == 0u) public_data::destroy(p); } #endif // BOOST_LOG_NO_THREADS + public: //! Attribute values view attribute_value_set m_attribute_values; //! Constructor from the attribute value set explicit public_data(BOOST_RV_REF(attribute_value_set) values) BOOST_NOEXCEPT : - m_ref_counter(1), + m_ref_counter(1u), m_attribute_values(boost::move(values)) { } @@ -88,9 +104,6 @@ class record_view BOOST_DELETED_FUNCTION(public_data(public_data const&)) BOOST_DELETED_FUNCTION(public_data& operator= (public_data const&)) - - friend void intrusive_ptr_add_ref(const public_data* p) BOOST_NOEXCEPT { ++p->m_ref_counter; } - friend void intrusive_ptr_release(const public_data* p) BOOST_NOEXCEPT { if (--p->m_ref_counter == 0) public_data::destroy(p); } }; private: From 440b160c9160decfde222fa5ad2643820e8b7c6a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 11 Oct 2024 00:07:47 +0300 Subject: [PATCH 256/309] Replaced leftover BOOST_STATIC_ASSERT_MSGs with static_assert. --- include/boost/log/detail/named_scope_fmt_pp.hpp | 4 ++-- .../log/utility/type_dispatch/dynamic_type_dispatcher.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/boost/log/detail/named_scope_fmt_pp.hpp b/include/boost/log/detail/named_scope_fmt_pp.hpp index 16e4508919..7c8966e9f7 100644 --- a/include/boost/log/detail/named_scope_fmt_pp.hpp +++ b/include/boost/log/detail/named_scope_fmt_pp.hpp @@ -41,7 +41,7 @@ BOOST_FORCEINLINE format_named_scope_actor< > format_named_scope(attribute_keyword< DescriptorT, ActorT > const& keyword, BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, const& arg)) { - BOOST_STATIC_ASSERT_MSG((is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value),\ + static_assert(is_same< typename DescriptorT::value_type, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef typename boost::log::aux::deduce_char_type< @@ -68,7 +68,7 @@ BOOST_FORCEINLINE format_named_scope_actor< > format_named_scope(attribute_actor< T, FallbackPolicyT, TagT, ActorT > const& placeholder, BOOST_PP_ENUM_BINARY_PARAMS(BOOST_PP_ITERATION(), ArgT, const& arg)) { - BOOST_STATIC_ASSERT_MSG((is_same< T, attributes::named_scope::value_type >::value),\ + static_assert(is_same< T, attributes::named_scope::value_type >::value, "Boost.Log: Named scope formatter only accepts attribute values of type attributes::named_scope::value_type."); typedef typename boost::log::aux::deduce_char_type< diff --git a/include/boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp b/include/boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp index 21428ff949..67c65ce56f 100644 --- a/include/boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp +++ b/include/boost/log/utility/type_dispatch/dynamic_type_dispatcher.hpp @@ -18,8 +18,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -63,7 +63,7 @@ class dynamic_type_dispatcher : { this->m_pVisitor = (void*)boost::addressof(m_Visitor); typedef void (*trampoline_t)(void*, T const&); - BOOST_STATIC_ASSERT_MSG(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); + static_assert(sizeof(trampoline_t) == sizeof(void*), "Boost.Log: Unsupported platform, the size of a function pointer differs from the size of a pointer"); union { void* as_pvoid; From 29e5fc6504327823a4f17c98deef4d5e89066f63 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 29 Oct 2024 18:50:49 +0300 Subject: [PATCH 257/309] Fixed grammar in the docs. --- doc/changelog.qbk | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 15fe4c29a8..54be1cb9fc 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -12,9 +12,9 @@ [heading 2.30, Boost 1.87] * Replaced __boost_thread__ synchronization primitives with equivalents from the C++ standard library. This may improve multithreaded performance, but also has user-facing consequences: - * __boost_thread__ thread interruption is no longer supported. Boost.Log no longer has special treatment for the `thread_interrupted` exception that is used by Boost.Thread to implement thread interruption. This exception will be handled like any other exception. + * __boost_thread__ thread interruption is no longer supported. Boost.Log no longer has special treatment for the `thread_interrupted` exception that is used by __boost_thread__ to implement thread interruption. This exception will be handled like any other exception. In particular, user-specified exception handlers may now be invoked with the `thread_interrupted` pending exception. - * For timed waiting operations, timeouts are now using std::chrono time units. This means that the `ordering_window` named parameter that is supported by the [class_sinks_bounded_ordering_queue] and [class_sinks_unbounded_ordering_queue] now expects an `std::chrono::duration` value instead of `boost::posix_time::time_duration` from __boost_date_time__. + * For timed waiting operations, timeouts are now using std::chrono time units. This means that the `ordering_window` named parameter that is supported by the [class_sinks_bounded_ordering_queue] and [class_sinks_unbounded_ordering_queue] classes now expects an `std::chrono::duration` value instead of `boost::posix_time::time_duration` from __boost_date_time__. * In case of errors indicated by thread synchronization primitives, `std::system_error` exception is thrown instead of __boost_thread__ exception types. * Added support for C++ standard library lock types to [class_log_strictest_lock]. From 1be88666c525a6ad8efa865c2d56818b9fc5c9ee Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 5 Nov 2024 18:16:18 +0300 Subject: [PATCH 258/309] Replaced address::from_string with make_address. address::from_string functions in Boost.ASIO were deprecated and removed. Use make_address free functions as a replacement. Fixes https://github.com/boostorg/log/issues/239. --- src/syslog_backend.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 15a47e3929..b93e574a7f 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -554,8 +554,8 @@ BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, un } #else // Boost.ASIO requires threads for the host name resolver, - // so without threads we simply assume the string already contains IP address - set_local_address(boost::asio::ip::address::from_string(addr), port); + // so without threads we simply assume the string already contains an IP address + set_local_address(asio::ip::make_address(addr), port); #endif // !defined(BOOST_LOG_NO_THREADS) } //! The method sets the local address which log records will be sent from. @@ -600,8 +600,8 @@ BOOST_LOG_API void syslog_backend::set_target_address(std::string const& addr, u } #else // Boost.ASIO requires threads for the host name resolver, - // so without threads we simply assume the string already contains IP address - set_target_address(boost::asio::ip::address::from_string(addr), port); + // so without threads we simply assume the string already contains an IP address + set_target_address(asio::ip::make_address(addr), port); #endif // !defined(BOOST_LOG_NO_THREADS) } //! The method sets the address of the remote host where log records will be sent to. From a741a34df2213d04eb363ab719bedd31ac7ece86 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 7 Dec 2024 15:25:27 +0300 Subject: [PATCH 259/309] Added new gcc and clang versions to GHA CI. --- .github/workflows/ci.yml | 69 +++++++++++++++++++++++++--------------- 1 file changed, 43 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b376a9f4fd..a2fbbe18b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,18 +82,22 @@ jobs: - g++-12 - toolset: gcc-13 cxxstd: "11,14,17,20,23" - os: ubuntu-latest - container: ubuntu:23.04 + os: ubuntu-24.04 install: - g++-13 + - toolset: gcc-14 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-24.04 + install: + - g++-14 - name: UBSAN - toolset: gcc-11 + toolset: gcc-13 cxxstd: "11,14,17,20,23" ubsan: 1 build_variant: debug - os: ubuntu-22.04 + os: ubuntu-24.04 install: - - g++-11 + - g++-13 # Linux, clang - toolset: clang @@ -224,50 +228,63 @@ jobs: - toolset: clang compiler: clang++-16 cxxstd: "11,14,17,20,2b" - os: ubuntu-22.04 + os: ubuntu-24.04 install: - clang-16 - sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-16 main" - source_keys: - - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - g++-11 + gcc_toolchain: 11 - toolset: clang compiler: clang++-17 - cxxstd: "11,14,17,20,23" - os: ubuntu-22.04 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-24.04 install: - clang-17 + - g++-11 + gcc_toolchain: 11 + - toolset: clang + compiler: clang++-18 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-24.04 + install: + - clang-18 + - g++-13 + - toolset: clang + compiler: clang++-19 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-24.04 + install: + - clang-19 sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang - compiler: clang++-17 - cxxstd: "11,14,17,20,23" - os: ubuntu-22.04 + compiler: clang++-19 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-24.04 install: - - clang-17 - - libc++-17-dev - - libc++abi-17-dev + - clang-19 + - libc++-19-dev + - libc++abi-19-dev sources: - - "deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-17 main" + - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" source_keys: - "https://apt.llvm.org/llvm-snapshot.gpg.key" cxxflags: -stdlib=libc++ linkflags: -stdlib=libc++ - name: UBSAN toolset: clang - compiler: clang++-15 - cxxstd: "11,14,17,20,2b" + compiler: clang++-18 + cxxstd: "11,14,17,20,23,26" cxxflags: -stdlib=libc++ linkflags: "-stdlib=libc++ -lubsan" ubsan: 1 build_variant: debug - os: ubuntu-22.04 + os: ubuntu-24.04 install: - - clang-15 - - libc++-15-dev - - libc++abi-15-dev + - clang-18 + - libc++-18-dev + - libc++abi-18-dev - toolset: clang cxxstd: "11,14,17,20,2b" From 403fff4062d73a3f97c6743244f4b216dda76879 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 7 Dec 2024 15:28:51 +0300 Subject: [PATCH 260/309] Removed macos-12 job from GHA CI. The image is deprecated. --- .github/workflows/ci.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2fbbe18b0..b7d5a0ae7a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -286,9 +286,6 @@ jobs: - libc++-18-dev - libc++abi-18-dev - - toolset: clang - cxxstd: "11,14,17,20,2b" - os: macos-12 - toolset: clang cxxstd: "11,14,17,20,2b" os: macos-13 From ddb9868bfb7ecad5a1f951ebfdbae7ad41fc0d8e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 7 Dec 2024 17:25:40 +0300 Subject: [PATCH 261/309] Disable std::codecvt and std::codecvt for C++20 and later. These specializations were deprecated in C++20, and libc++-19 now generates deprecation warnings when using std::codecvt and std::codecvt in C++20 and later modes. --- doc/changelog.qbk | 4 ++++ include/boost/log/detail/config.hpp | 8 +++++--- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 54be1cb9fc..dd75471a25 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.31, Boost 1.88] + +* Disabled usage of `std::codecvt` and `std::codecvt` locale facets in C++20 and later modes as they were deprecated in C++20. This means character code conversions to/from `char16_t` and `char32_t` is no longer available in C++20 and later. + [heading 2.30, Boost 1.87] * Replaced __boost_thread__ synchronization primitives with equivalents from the C++ standard library. This may improve multithreaded performance, but also has user-facing consequences: diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 7835a5b4b0..0e69949ff1 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -92,12 +92,14 @@ # define BOOST_LOG_BROKEN_CONSTANT_EXPRESSIONS #endif -#if (defined(BOOST_NO_CXX11_HDR_CODECVT) && BOOST_CXX_VERSION < 201703) || (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142) +#if (defined(BOOST_NO_CXX11_HDR_CODECVT) && BOOST_CXX_VERSION < 201703) || (BOOST_CXX_VERSION >= 202002) || \ + (defined(_MSVC_STL_VERSION) && _MSVC_STL_VERSION < 142) // The compiler does not support std::codecvt and std::codecvt specializations. // The BOOST_NO_CXX11_HDR_CODECVT means there's no usable , which is slightly different from this macro. // But in order for to be implemented the std::codecvt specializations have to be implemented as well. // We need to check the C++ version as well, since is deprecated from C++17 onwards which may cause // BOOST_NO_CXX11_HDR_CODECVT to be set, even though std::codecvt in is just fine. + // The std::codecvt and std::codecvt specializations were eventually deprecated in C++20. # define BOOST_LOG_NO_CXX11_CODECVT_FACETS #endif @@ -113,8 +115,8 @@ # include #endif -#if (!defined(__CRYSTAX__) && defined(__ANDROID__) && (__ANDROID_API__ < 21)) \ - || (defined(__VXWORKS__) && !defined(_WRS_CONFIG_USER_MANAGEMENT)) +#if (!defined(__CRYSTAX__) && defined(__ANDROID__) && (__ANDROID_API__ < 21)) || \ + (defined(__VXWORKS__) && !defined(_WRS_CONFIG_USER_MANAGEMENT)) // Until Android API version 21 Google NDK does not provide getpwuid_r # define BOOST_LOG_NO_GETPWUID_R #endif From e9e857960789e5ad03b9f2bc4c6e7148d6bea58a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 15 Dec 2024 12:09:03 +0300 Subject: [PATCH 262/309] Added CMake MinGW-w64 job to GHA. --- .github/workflows/ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b7d5a0ae7a..e4eb76717f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -557,9 +557,13 @@ jobs: cxxstd: "11-gnu,14-gnu,17-gnu,2a-gnu" os: windows-2019 - - name: CMake tests + - name: CMake MSVC tests + cmake_tests: 1 + os: windows-2022 + - name: CMake MinGW-w64 tests cmake_tests: 1 os: windows-2022 + cmake_generator: "MinGW Makefiles" timeout-minutes: 60 runs-on: ${{matrix.os}} @@ -621,6 +625,7 @@ jobs: - name: Run CMake tests if: matrix.cmake_tests run: | + if not "${{matrix.cmake_generator}}" == "" set "CMAKE_GENERATOR=${{matrix.cmake_generator}}" cd boost-root mkdir __build_static__ cd __build_static__ From aa0acf366d4d78b3ab6a92137b3e1715629b8a3a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 15 Dec 2024 18:37:25 +0300 Subject: [PATCH 263/309] Create output directory for Message Compiler tool. Presumably, windmc.exe from MinGW-w64 fails if the output directory doesn't exist. So create it prior to running the tool. Additionally, removed explicit markup of the tool outputs as generated sources. This should be done automatically by add_custom_command. Also, added the max CMake version to silence its warnings. --- CMakeLists.txt | 8 +++----- test/test_cmake/CMakeLists.txt | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8817719a45..3cf8f007eb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,9 +1,9 @@ -# Copyright 2021-2023 Andrey Semashev +# Copyright 2021-2024 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.5...3.16) project(BoostLog VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) include(CheckCXXSourceCompiles) @@ -258,8 +258,8 @@ if (WIN32) OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" "${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" + COMMAND "${CMAKE_COMMAND}" -E make_directory "${CMAKE_CURRENT_BINARY_DIR}/src/windows" COMMAND "${CMAKE_MC_COMPILER}" - ARGS -h "${CMAKE_CURRENT_BINARY_DIR}/src/windows" -r "${CMAKE_CURRENT_BINARY_DIR}/src/windows" "${CMAKE_CURRENT_SOURCE_DIR}/src/windows/simple_event_log.mc" @@ -269,8 +269,6 @@ if (WIN32) "Building src/windows/simple_event_log.mc" VERBATIM ) - set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.h" PROPERTIES GENERATED TRUE) - set_source_files_properties("${CMAKE_CURRENT_BINARY_DIR}/src/windows/simple_event_log.rc" PROPERTIES GENERATED TRUE) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") # Workaround for a windres.exe issue on MinGW-w64: by default, it uses popen to pipe preprocessed diff --git a/test/test_cmake/CMakeLists.txt b/test/test_cmake/CMakeLists.txt index bc9555f16d..7f679e234d 100644 --- a/test/test_cmake/CMakeLists.txt +++ b/test/test_cmake/CMakeLists.txt @@ -6,7 +6,7 @@ # NOTE: This does NOT run the unit tests for Boost.Log. # It only tests if the CMakeLists.txt file in its root works as expected -cmake_minimum_required(VERSION 3.5) +cmake_minimum_required(VERSION 3.5...3.16) project(BoostLogCMakeSelfTest) From 3dacd004ae8baca62a3cae918e5115fcb73184f4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sun, 15 Dec 2024 19:02:49 +0300 Subject: [PATCH 264/309] Added linking log_setup with ws2_32 on MinGW-w64. The dependency is introduced by Boost.ASIO, when it is enabled. Closes https://github.com/boostorg/log/pull/241. --- CMakeLists.txt | 4 ++++ doc/changelog.qbk | 1 + 2 files changed, 5 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3cf8f007eb..97ad278282 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -326,6 +326,9 @@ if (WIN32 OR CYGWIN) mswsock advapi32 ) + list(APPEND boost_log_setup_private_libs + ws2_32 + ) endif() if (CMAKE_SYSTEM_NAME STREQUAL "Linux") @@ -655,6 +658,7 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) target_link_libraries(boost_log_setup PRIVATE + ${boost_log_setup_private_libs} ${boost_log_common_private_linkflags} ) else() diff --git a/doc/changelog.qbk b/doc/changelog.qbk index dd75471a25..e32d04838e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -12,6 +12,7 @@ [heading 2.31, Boost 1.88] * Disabled usage of `std::codecvt` and `std::codecvt` locale facets in C++20 and later modes as they were deprecated in C++20. This means character code conversions to/from `char16_t` and `char32_t` is no longer available in C++20 and later. +* Fixed building issues when using CMake and MinGW-w64. ([pull_request 241]) [heading 2.30, Boost 1.87] From 8d4492d90ff1b652ff5607a150340bb28eb1f6cd Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 16 Dec 2024 19:01:41 +0300 Subject: [PATCH 265/309] Added a Cygwin job to GitHub Actions. Only test C++14 and up and only debug builds since building and running tests on Cygwin is extra slow. --- .github/workflows/ci.yml | 103 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e4eb76717f..4921756a26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -638,3 +638,106 @@ jobs: cmake -DBUILD_SHARED_LIBS=On ../libs/%LIBRARY%/test/test_cmake cmake --build . --target boost_%LIBRARY%_cmake_self_test -j %NUMBER_OF_PROCESSORS% cmake --build . --target boost_%LIBRARY%_setup_cmake_self_test -j %NUMBER_OF_PROCESSORS% + + cygwin: + defaults: + run: + shell: bash + + env: + SHELLOPTS: igncr + + strategy: + fail-fast: false + matrix: + include: + - toolset: gcc + cxxstd: "14-gnu,17-gnu,20-gnu,23-gnu" + build_variant: debug + os: windows-2022 + + timeout-minutes: 60 + runs-on: ${{matrix.os}} + + steps: + - name: Install Cygwin + uses: cygwin/cygwin-install-action@v4 + with: + packages: + gcc-g++ + + - name: Setup Boost + run: | + echo GITHUB_REPOSITORY: $GITHUB_REPOSITORY + LIBRARY=${GITHUB_REPOSITORY#*/} + echo LIBRARY: $LIBRARY + echo "LIBRARY=$LIBRARY" >> $GITHUB_ENV + echo GITHUB_BASE_REF: $GITHUB_BASE_REF + echo GITHUB_REF: $GITHUB_REF + REF=${GITHUB_BASE_REF:-$GITHUB_REF} + REF=${REF#refs/heads/} + echo REF: $REF + BOOST_BRANCH=develop && [ "$REF" = "master" ] && BOOST_BRANCH=master || true + echo BOOST_BRANCH: $BOOST_BRANCH + BUILD_JOBS=$((nproc) 2> /dev/null) + echo "BUILD_JOBS=$BUILD_JOBS" >> $GITHUB_ENV + echo "CMAKE_BUILD_PARALLEL_LEVEL=$BUILD_JOBS" >> $GITHUB_ENV + DEPINST_ARGS=("--git_args" "--jobs $GIT_FETCH_JOBS") + mkdir -p snapshot + cd snapshot + echo "Downloading library snapshot: https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" + curl -L --retry "$NET_RETRY_COUNT" -o "${LIBRARY}-${GITHUB_SHA}.tar.gz" "https://github.com/${GITHUB_REPOSITORY}/archive/${GITHUB_SHA}.tar.gz" + tar -xf "${LIBRARY}-${GITHUB_SHA}.tar.gz" + if [ ! -d "${LIBRARY}-${GITHUB_SHA}" ] + then + echo "Library snapshot does not contain the library directory ${LIBRARY}-${GITHUB_SHA}:" + ls -la + exit 1 + fi + rm -f "${LIBRARY}-${GITHUB_SHA}.tar.gz" + cd .. + git clone -b "$BOOST_BRANCH" --depth 1 "https://github.com/boostorg/boost.git" "boost-root" + cd boost-root + mkdir -p libs + rm -rf "libs/$LIBRARY" + mv -f "../snapshot/${LIBRARY}-${GITHUB_SHA}" "libs/$LIBRARY" + rm -rf "../snapshot" + git submodule update --init tools/boostdep + if [ -n "${{matrix.extra_tests}}" ] + then + DEPINST_ARGS+=("--include" "example") + fi + DEPINST_ARGS+=("$LIBRARY") + python tools/boostdep/depinst/depinst.py "${DEPINST_ARGS[@]}" + ./bootstrap.sh + ./b2 -d0 headers + + - name: Run tests + run: | + cd boost-root + if [ -z "${{matrix.extra_tests}}" ] + then + export BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS=1 + export BOOST_LOG_TEST_WITHOUT_EXAMPLES=1 + fi + B2_ARGS=("-j" "$BUILD_JOBS" "toolset=${{matrix.toolset}}" "cxxstd=${{matrix.cxxstd}}") + if [ -n "${{matrix.build_variant}}" ] + then + B2_ARGS+=("variant=${{matrix.build_variant}}") + else + B2_ARGS+=("variant=$DEFAULT_BUILD_VARIANT") + fi + if [ -n "${{matrix.threading}}" ] + then + B2_ARGS+=("threading=${{matrix.threading}}") + fi + if [ -n "${{matrix.cxxflags}}" ] + then + B2_ARGS+=("cxxflags=${{matrix.cxxflags}}") + fi + if [ -n "${{matrix.linkflags}}" ] + then + B2_ARGS+=("linkflags=${{matrix.linkflags}}") + fi + B2_ARGS+=("libs/$LIBRARY/test") + ./b2 "${B2_ARGS[@]}" From 6366d73335d298c8c5c7f7bd80f6931fedb0df1b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 17 Dec 2024 04:29:24 +0300 Subject: [PATCH 266/309] Updated references to Boost.Interprocess issue with Cygwin. --- CMakeLists.txt | 2 +- build/Jamfile.v2 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 97ad278282..4d4e116c11 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,7 +306,7 @@ else() endif() if (CYGWIN) - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/242 set(BOOST_LOG_WITHOUT_IPC ON) list(APPEND boost_log_common_private_defines __USE_W32_SOCKETS diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index dfb6a65a4a..6c4d2d1117 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -113,7 +113,7 @@ project boost/log windows:advapi32 cygwin:BOOST_USE_WINDOWS_H - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 + # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/242 cygwin:BOOST_LOG_WITHOUT_IPC cygwin:ws2_32 cygwin:mswsock From 724e888b5a558f8dc3db64b4397ce23f83baa53e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 18 Mar 2025 01:35:04 +0300 Subject: [PATCH 267/309] Only reuse the old counter if the file name pattern has a counter placeholder. If text_file_backend is set up to append to a previously written file, and the actively written file name pattern does not include a file counter placeholder but the target file name pattern does, we used to skip incrementing the file counter in an attempt to generate the same file name as was last used, so that we open the last used file for appending. While it did result in reusing the last written file, since the counter was not incremented, the next rotation would generate the last used target file name, which would result in overwriting the last rotated file instead of adding a new file to the storage. To mitigate this, only skip incrementing the counter if the file name pattern for the actively written file actually has a counter placeholder. This way, the counter will get incremented in the case described above, and on rotation a new target file name will be generated. Fixes https://github.com/boostorg/log/issues/245. --- doc/changelog.qbk | 3 ++- src/text_file_backend.cpp | 30 ++++++++++++++++++++++-------- 2 files changed, 24 insertions(+), 9 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index e32d04838e..affcf5cc28 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2024. + Copyright Andrey Semashev 2007 - 2025. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -13,6 +13,7 @@ * Disabled usage of `std::codecvt` and `std::codecvt` locale facets in C++20 and later modes as they were deprecated in C++20. This means character code conversions to/from `char16_t` and `char32_t` is no longer available in C++20 and later. * Fixed building issues when using CMake and MinGW-w64. ([pull_request 241]) +* Fixed incorrect file counter used by `text_file_backend` when the backend was configured to append to an existing file and the actively written file name pattern didn't have a counter placeholder but the target file name pattern did, and the log files were written directly into the target storage. ([github_issue 245]) [heading 2.30, Boost 1.87] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 6c2e8633b2..f1e8f28caf 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2025. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -507,7 +507,14 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { } //! The function parses file name pattern and splits it into path and filename and creates a function object that will generate the actual filename from the pattern - void parse_file_name_pattern(filesystem::path const& pattern, filesystem::path& storage_dir, filesystem::path& file_name_pattern, boost::log::aux::light_function< path_string_type (unsigned int) >& file_name_generator) + void parse_file_name_pattern + ( + filesystem::path const& pattern, + filesystem::path& storage_dir, + filesystem::path& file_name_pattern, + boost::log::aux::light_function< path_string_type (unsigned int) >& file_name_generator, + bool& has_file_counter + ) { // Note: avoid calling Boost.Filesystem functions that involve path::codecvt() // https://svn.boost.org/trac/boost/ticket/9119 @@ -606,6 +613,8 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { // No placeholders detected file_name_generator = empty_formatter(name_pattern); } + + has_file_counter = counter_found; } @@ -1271,6 +1280,8 @@ struct text_file_backend::implementation filesystem::path m_StorageDir; //! File name generator (according to m_FileNamePattern) boost::log::aux::light_function< path_string_type (unsigned int) > m_FileNameGenerator; + //! The flag indicates whether m_FileNamePattern has a file counter placeholder + bool m_FileNamePatternHasCounter; //! Target file name pattern filesystem::path m_TargetFileNamePattern; @@ -1316,6 +1327,7 @@ struct text_file_backend::implementation bool m_IsFirstFile; implementation(uintmax_t rotation_size, auto_newline_mode auto_newline, bool auto_flush, bool enable_final_rotation) : + m_FileNamePatternHasCounter(false), m_FileCounter(0u), m_FileOpenMode(std::ios_base::trunc | std::ios_base::out), m_CharactersWritten(0u), @@ -1449,11 +1461,11 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ unsigned int file_counter = m_pImpl->m_FileCounter; if (BOOST_LIKELY(m_pImpl->m_FileCounterIsLastUsed)) { - // If the sink backend is configured to append to a previously written file, don't - // increment the file counter and try to open the existing file. Only do this if the - // file is not moved to a different storage location by the file collector. + // If the sink backend is configured to append to a previously written file and the file pattern + // includes a file counter, don't increment the counter and try to open the existing file, with the last + // used counter value. Only do this if the file is not moved to a different storage location by the file collector. bool increment_file_counter = true; - if (BOOST_UNLIKELY(m_pImpl->m_IsFirstFile && (m_pImpl->m_FileOpenMode & std::ios_base::app) != 0)) + if (BOOST_UNLIKELY(m_pImpl->m_IsFirstFile && (m_pImpl->m_FileOpenMode & std::ios_base::app) != 0 && m_pImpl->m_FileNamePatternHasCounter)) { filesystem::path last_file_name = m_pImpl->m_StorageDir / m_pImpl->m_FileNameGenerator(file_counter); if (!!m_pImpl->m_pFileCollector) @@ -1575,7 +1587,8 @@ BOOST_LOG_API void text_file_backend::set_file_name_pattern_internal(filesystem: !pattern.empty() ? pattern : filesystem::path(traits_t::default_file_name_pattern()), m_pImpl->m_StorageDir, m_pImpl->m_FileNamePattern, - m_pImpl->m_FileNameGenerator + m_pImpl->m_FileNameGenerator, + m_pImpl->m_FileNamePatternHasCounter ); } @@ -1584,7 +1597,8 @@ BOOST_LOG_API void text_file_backend::set_target_file_name_pattern_internal(file { if (!pattern.empty()) { - parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator); + bool has_file_counter = false; + parse_file_name_pattern(pattern, m_pImpl->m_TargetStorageDir, m_pImpl->m_TargetFileNamePattern, m_pImpl->m_TargetFileNameGenerator, has_file_counter); } else { From 521d30d2cfc5306fec52eb1102b164a20845ea8d Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 19 Apr 2025 16:42:38 +0300 Subject: [PATCH 268/309] Cast character types when calling character classification functions. --- src/format_parser.cpp | 3 ++- src/setup/filter_parser.cpp | 5 +++-- src/setup/formatter_parser.cpp | 7 ++++--- src/setup/init_from_settings.cpp | 16 +++++++++------- src/setup/parser_utils.cpp | 10 +++++----- src/setup/parser_utils.hpp | 2 +- src/setup/settings_parser.cpp | 7 ++++--- src/text_file_backend.cpp | 2 +- 8 files changed, 29 insertions(+), 23 deletions(-) diff --git a/src/format_parser.cpp b/src/format_parser.cpp index 1215d6b2c6..5b50763c26 100644 --- a/src/format_parser.cpp +++ b/src/format_parser.cpp @@ -42,6 +42,7 @@ BOOST_LOG_API format_description< CharT > parse_format(const CharT* begin, const typedef CharT char_type; typedef format_description< char_type > description; typedef typename encoding< char_type >::type traits; + typedef typename traits::classify_type char_classify_type; const char_type* original_begin = begin; description descr; @@ -74,7 +75,7 @@ BOOST_LOG_API format_description< CharT > parse_format(const CharT* begin, const } // Check if this is a positional argument - if (traits::isdigit(c)) + if (traits::isdigit(static_cast< char_classify_type >(c))) { if (c != static_cast< char_type >('0')) { diff --git a/src/setup/filter_parser.cpp b/src/setup/filter_parser.cpp index cf41bca023..4379e1df1c 100644 --- a/src/setup/filter_parser.cpp +++ b/src/setup/filter_parser.cpp @@ -123,6 +123,7 @@ class filter_parser typedef CharT char_type; typedef const char_type* iterator_type; typedef typename log::aux::encoding< char_type >::type encoding; + typedef typename encoding::classify_type char_classify_type; typedef log::aux::encoding_specific< encoding > encoding_specific; typedef std::basic_string< char_type > string_type; typedef log::aux::char_constants< char_type > constants; @@ -314,7 +315,7 @@ class filter_parser else { // Check for custom relation - while (next != end && (encoding::isalnum(*next) || *next == constants::char_underline)) + while (next != end && (encoding::isalnum(static_cast< char_classify_type >(*next)) || *next == constants::char_underline)) ++next; if (p == next) goto DoneL; @@ -347,7 +348,7 @@ class filter_parser char_type c1 = *p, c2 = *keyword; if (c2 == 0) { - if (encoding::isspace(c1)) + if (encoding::isspace(static_cast< char_classify_type >(c1))) { next = p; return true; diff --git a/src/setup/formatter_parser.cpp b/src/setup/formatter_parser.cpp index 597b6ca7b2..1cd1d703c0 100644 --- a/src/setup/formatter_parser.cpp +++ b/src/setup/formatter_parser.cpp @@ -183,6 +183,7 @@ class formatter_parser typedef basic_formatter< char_type > formatter_type; typedef boost::log::aux::char_constants< char_type > constants; typedef typename log::aux::encoding< char_type >::type encoding; + typedef typename encoding::classify_type char_classify_type; typedef log::aux::encoding_specific< encoding > encoding_specific; typedef formatter_factory< char_type > formatter_factory_type; typedef typename formatter_factory_type::args_map args_map; @@ -299,14 +300,14 @@ class formatter_parser // Read argument name iterator_type start = p; - if (!encoding::isalpha(*p)) + if (!encoding::isalpha(static_cast< char_classify_type >(*p))) BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid"); for (++p; p != end; ++p) { c = *p; - if (encoding::isspace(c) || c == constants::char_equal) + if (encoding::isspace(static_cast< char_classify_type >(c)) || c == constants::char_equal) break; - if (!encoding::isalnum(c) && c != constants::char_underline) + if (!encoding::isalnum(static_cast< char_classify_type >(c)) && c != constants::char_underline) BOOST_LOG_THROW_DESCR(parse_error, "Placeholder argument name is invalid"); } diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index de639df08a..86f4c4151e 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -116,7 +116,8 @@ struct is_case_insensitive_equal result_type operator() (CharT left, CharT right) const BOOST_NOEXCEPT { typedef typename boost::log::aux::encoding< CharT >::type encoding; - return encoding::tolower(left) == encoding::tolower(right); + typedef typename encoding::classify_type char_classify_type; + return encoding::tolower(static_cast< char_classify_type >(left)) == encoding::tolower(static_cast< char_classify_type >(right)); } }; @@ -193,6 +194,7 @@ sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char typedef CharT char_type; typedef boost::log::aux::char_constants< char_type > constants; typedef typename boost::log::aux::encoding< char_type >::type encoding; + typedef typename encoding::classify_type char_classify_type; typedef qi::extract_uint< unsigned short, 10, 1, 2 > day_extract; typedef qi::extract_uint< unsigned char, 10, 2, 2 > time_component_extract; @@ -202,14 +204,14 @@ sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char unsigned char hour = 0, minute = 0, second = 0; const char_type* begin = value.c_str(), *end = begin + value.size(); - if (!encoding::isalnum(*begin)) // begin is null-terminated, so we also check that the string is not empty here + if (!encoding::isalnum(static_cast< char_classify_type >(*begin))) // begin is null-terminated, so we also check that the string is not empty here throw_invalid_value(param_name); const char_type* p = begin + 1; - if (encoding::isalpha(*begin)) + if (encoding::isalpha(static_cast< char_classify_type >(*begin))) { // This must be a weekday - while (encoding::isalpha(*p)) + while (encoding::isalpha(static_cast< char_classify_type >(*p))) ++p; std::size_t len = p - begin; @@ -233,10 +235,10 @@ sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char else { // This may be either a month day or an hour - while (encoding::isdigit(*p)) + while (encoding::isdigit(static_cast< char_classify_type >(*p))) ++p; - if (encoding::isspace(*p)) + if (encoding::isspace(static_cast< char_classify_type >(*p))) { // This is a month day unsigned short mday = 0; @@ -256,7 +258,7 @@ sinks::file::rotation_at_time_point param_cast_to_rotation_time_point(const char } // Skip spaces - while (encoding::isspace(*p)) + while (encoding::isspace(static_cast< char_classify_type >(*p))) ++p; // Parse hour diff --git a/src/setup/parser_utils.cpp b/src/setup/parser_utils.cpp index 08a5de8b06..a8c3299b0f 100644 --- a/src/setup/parser_utils.cpp +++ b/src/setup/parser_utils.cpp @@ -60,7 +60,7 @@ const char_constants< char >::char_type char_constants< char >::char_paren_brack const char* char_constants< char >::trim_spaces_left(const char_type* begin, const char_type* end) { using namespace std; - while (begin != end && isspace(*begin)) + while (begin != end && isspace(static_cast< unsigned char >(*begin))) ++begin; return begin; } @@ -69,7 +69,7 @@ const char* char_constants< char >::trim_spaces_left(const char_type* begin, con const char* char_constants< char >::trim_spaces_right(const char_type* begin, const char_type* end) { using namespace std; - while (begin != end && isspace(*(end - 1))) + while (begin != end && isspace(static_cast< unsigned char >(*(end - 1)))) --end; return end; } @@ -81,7 +81,7 @@ const char* char_constants< char >::scan_attr_placeholder(const char_type* begin while (begin != end) { char_type c = *begin; - if (!isalnum(c) && c != char_underline) + if (!isalnum(static_cast< unsigned char >(c)) && c != char_underline) break; ++begin; } @@ -132,7 +132,7 @@ const char* char_constants< char >::parse_operand(const char_type* begin, const for (++p; p != end; ++p) { c = *p; - if (!isalnum(c) && c != '_' && c != '-' && c != '+' && c != '.') + if (!isalnum(static_cast< unsigned char >(c)) && c != '_' && c != '-' && c != '+' && c != '.') break; } @@ -174,7 +174,7 @@ void char_constants< char >::translate_escape_sequences(string_type& str) if (std::distance(++b, str.end()) >= 2) { char_type c1 = *b++, c2 = *b++; - if (isxdigit(c1) && isxdigit(c2)) + if (isxdigit(static_cast< unsigned char >(c1)) && isxdigit(static_cast< unsigned char >(c2))) { *it++ = char_type((to_number(c1) << 4) | to_number(c2)); it = str.erase(it, b); diff --git a/src/setup/parser_utils.hpp b/src/setup/parser_utils.hpp index bf0be4b873..f6e6180d29 100644 --- a/src/setup/parser_utils.hpp +++ b/src/setup/parser_utils.hpp @@ -150,7 +150,7 @@ struct char_constants< char > { using namespace std; // to make sure we can use C functions unqualified int n = 0; - if (isdigit(c)) + if (isdigit(static_cast< unsigned char >(c))) n = c - '0'; else if (c >= 'a' && c <= 'f') n = c - 'a' + 10; diff --git a/src/setup/settings_parser.cpp b/src/setup/settings_parser.cpp index 9a0634564d..e3e99a6806 100644 --- a/src/setup/settings_parser.cpp +++ b/src/setup/settings_parser.cpp @@ -50,6 +50,7 @@ class settings_parser typedef CharT char_type; typedef const char_type* iterator_type; typedef typename log::aux::encoding< char_type >::type encoding; + typedef typename encoding::classify_type char_classify_type; typedef settings_parser< char_type > this_type; typedef std::basic_string< char_type > string_type; @@ -157,7 +158,7 @@ class settings_parser for (iterator_type p = begin; p != end; ++p) { char_type c = *p; - if (c != constants::char_dot && !encoding::isalnum(c)) + if (c != constants::char_dot && !encoding::isalnum(static_cast< char_classify_type >(c))) BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Section name is invalid", (m_LineCounter)); } @@ -183,12 +184,12 @@ class settings_parser BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is empty", (m_LineCounter)); iterator_type p = begin; - if (!encoding::isalpha(*p)) + if (!encoding::isalpha(static_cast< char_classify_type >(*p))) BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter)); for (++p; p != end; ++p) { char_type c = *p; - if (!encoding::isgraph(c)) + if (!encoding::isgraph(static_cast< char_classify_type >(c))) BOOST_LOG_THROW_DESCR_PARAMS(parse_error, "Parameter name is invalid", (m_LineCounter)); } diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index f1e8f28caf..dcf1faa6ed 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -133,7 +133,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { static bool is_digit(char c) { using namespace std; - return (isdigit(c) != 0); + return (isdigit(static_cast< unsigned char >(c)) != 0); } static std::string default_file_name_pattern() { return "%5N.log"; } }; From 75f2e8eb6d5450b739bec3c662f49801d58cf041 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 19 Apr 2025 18:07:22 +0300 Subject: [PATCH 269/309] Use locale-independent formatting of the file counter in text_file_backend. This fixes failures in the subsequent parsing of the file names in file_collector::scan_for_files. Closes https://github.com/boostorg/log/pull/246. --- doc/changelog.qbk | 4 ++++ src/text_file_backend.cpp | 37 +++++++++++++++++++++++++++---------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index affcf5cc28..da31e36eff 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.32, Boost 1.89] + +* Use locale-independent formatting of the file counter in `text_file_backend` when composing log file names. This fixes failures in the subsequent parsing of the file names in `file_collector::scan_for_files`. ([pull_request 246]) + [heading 2.31, Boost 1.88] * Disabled usage of `std::codecvt` and `std::codecvt` locale facets in C++20 and later modes as they were deprecated in C++20. This means character code conversions to/from `char16_t` and `char32_t` is no longer available in C++20 and later. diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index dcf1faa6ed..1fb3a4944a 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -262,9 +263,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! The position in the pattern where the file counter placeholder is path_string_type::size_type m_FileCounterPosition; //! File counter width - std::streamsize m_Width; - //! The file counter formatting stream - mutable std::basic_ostringstream< path_char_type > m_Stream; + unsigned int m_Width; public: //! Initializing constructor @@ -272,26 +271,44 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { m_FileCounterPosition(pos), m_Width(width) { - typedef file_char_traits< path_char_type > traits_t; - m_Stream.fill(traits_t::zero); } //! Copy constructor file_counter_formatter(file_counter_formatter const& that) : m_FileCounterPosition(that.m_FileCounterPosition), m_Width(that.m_Width) { - m_Stream.fill(that.m_Stream.fill()); } //! The function formats the file counter into the file name path_string_type operator()(path_string_type const& pattern, unsigned int counter) const { + typedef file_char_traits< path_char_type > traits_t; + + // Perform formatting that does not depend on the locale. This is important to be able to parse the counter match_pattern. + path_char_type buf[(std::numeric_limits< unsigned int >::digits10 + 1u) < 64u ? 64u : (std::numeric_limits< unsigned int >::digits10 + 1u)]; + path_char_type* e = buf + sizeof(buf) / sizeof(*buf); + path_char_type* p = e; + do + { + --p; + *p = traits_t::zero + (counter % 10u); + counter /= 10u; + } + while (counter > 0u); + + while (static_cast< std::size_t >(e - p) < m_Width && p > buf) + { + --p; + *p = traits_t::zero; + } + path_string_type file_name = pattern; - m_Stream.str(path_string_type()); - m_Stream.width(m_Width); - m_Stream << counter; - file_name.insert(m_FileCounterPosition, m_Stream.str()); + typename path_string_type::size_type const size = static_cast< typename path_string_type::size_type >(e - p); + file_name.insert(m_FileCounterPosition, p, size); + + if (size < m_Width) + file_name.insert(m_FileCounterPosition, static_cast< typename path_string_type::size_type >(m_Width - size), traits_t::zero); return file_name; } From fea445eaa9cbdeaafa7b94f54f83d106744c591a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 19 Apr 2025 18:15:02 +0300 Subject: [PATCH 270/309] Unconditionally use std::unique_ptr. --- CMakeLists.txt | 1 - src/core.cpp | 6 ++-- src/named_scope.cpp | 6 ++-- src/record_ostream.cpp | 8 ++--- src/severity_level.cpp | 4 +-- src/syslog_backend.cpp | 4 +-- src/text_file_backend.cpp | 1 - src/unique_ptr.hpp | 59 ------------------------------- src/windows/event_log_backend.cpp | 6 ++-- src/windows/ipc_sync_wrappers.cpp | 4 +-- 10 files changed, 19 insertions(+), 80 deletions(-) delete mode 100644 src/unique_ptr.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4d4e116c11..3122845028 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,6 @@ set(boost_log_sources src/bit_tools.hpp src/code_conversion.cpp src/stateless_allocator.hpp - src/unique_ptr.hpp src/core.cpp src/record_ostream.cpp src/severity_level.cpp diff --git a/src/core.cpp b/src/core.cpp index 1da9d30728..40014bf61b 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -44,7 +45,6 @@ #include #include #endif -#include "unique_ptr.hpp" #include "default_sink.hpp" #include "stateless_allocator.hpp" #include "alignment_gap_between.hpp" @@ -282,7 +282,7 @@ struct core::implementation : #else //! Thread-specific data - log::aux::unique_ptr< thread_data > m_thread_data; + std::unique_ptr< thread_data > m_thread_data; #endif //! The global state of logging @@ -427,7 +427,7 @@ struct core::implementation : BOOST_LOG_EXPR_IF_MT(scoped_write_lock lock(m_mutex);) if (!m_thread_data.get()) { - log::aux::unique_ptr< thread_data > p(new thread_data()); + std::unique_ptr< thread_data > p(new thread_data()); m_thread_data.reset(p.get()); #if defined(BOOST_LOG_USE_COMPILER_TLS) m_thread_data_cache = p.release(); diff --git a/src/named_scope.cpp b/src/named_scope.cpp index 8121cbfa7c..22c60f6099 100644 --- a/src/named_scope.cpp +++ b/src/named_scope.cpp @@ -14,6 +14,7 @@ */ #include +#include #include #include #include @@ -27,7 +28,6 @@ #if !defined(BOOST_LOG_NO_THREADS) #include #endif -#include "unique_ptr.hpp" #include namespace boost { @@ -153,7 +153,7 @@ struct BOOST_SYMBOL_VISIBLE named_scope::impl : #else //! Pointer to the scope stack - log::aux::unique_ptr< scope_list > pScopes; + std::unique_ptr< scope_list > pScopes; #endif //! The method returns current thread scope stack @@ -166,7 +166,7 @@ struct BOOST_SYMBOL_VISIBLE named_scope::impl : #endif if (!p) { - log::aux::unique_ptr< scope_list > pNew(new scope_list()); + std::unique_ptr< scope_list > pNew(new scope_list()); pScopes.reset(pNew.get()); #if defined(BOOST_LOG_USE_COMPILER_TLS) pScopesCache = p = pNew.release(); diff --git a/src/record_ostream.cpp b/src/record_ostream.cpp index 27ed3d09b2..28f3e520dc 100644 --- a/src/record_ostream.cpp +++ b/src/record_ostream.cpp @@ -15,6 +15,7 @@ #include #include +#include #include #include #include @@ -23,7 +24,6 @@ #if !defined(BOOST_LOG_NO_THREADS) #include #endif -#include "unique_ptr.hpp" #include namespace boost { @@ -75,7 +75,7 @@ class stream_compound_pool : #if !defined(BOOST_LOG_NO_THREADS) thread_specific_ptr< stream_compound_pool< CharT > > #else - log::aux::unique_ptr< stream_compound_pool< CharT > > + std::unique_ptr< stream_compound_pool< CharT > > #endif > { @@ -86,7 +86,7 @@ class stream_compound_pool : typedef thread_specific_ptr< this_type > tls_ptr_type; #else //! Thread-specific pointer type - typedef log::aux::unique_ptr< this_type > tls_ptr_type; + typedef std::unique_ptr< this_type > tls_ptr_type; #endif //! Singleton base type typedef log::aux::lazy_singleton< @@ -117,7 +117,7 @@ class stream_compound_pool : this_type* p = ptr.get(); if (!p) { - log::aux::unique_ptr< this_type > pNew(new this_type()); + std::unique_ptr< this_type > pNew(new this_type()); ptr.reset(pNew.get()); p = pNew.release(); } diff --git a/src/severity_level.cpp b/src/severity_level.cpp index 9ba01cc287..21fdf586cb 100644 --- a/src/severity_level.cpp +++ b/src/severity_level.cpp @@ -14,6 +14,7 @@ */ #include +#include #include #include @@ -22,7 +23,6 @@ #include #include #endif -#include "unique_ptr.hpp" #include namespace boost { @@ -61,7 +61,7 @@ BOOST_LOG_API uintmax_t& get_severity_level() uintmax_t* p = tss.get(); if (BOOST_UNLIKELY(!p)) { - log::aux::unique_ptr< uintmax_t > ptr(new uintmax_t(0)); + std::unique_ptr< uintmax_t > ptr(new uintmax_t(0)); tss.set(ptr.get()); p = ptr.release(); boost::this_thread::at_thread_exit([p]() { delete p; }); diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index b93e574a7f..8f383e1cb0 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -18,6 +18,7 @@ #ifndef BOOST_LOG_WITHOUT_SYSLOG #include +#include #include #include #include @@ -45,7 +46,6 @@ #if !defined(BOOST_LOG_NO_THREADS) #include #endif -#include "unique_ptr.hpp" #ifdef BOOST_LOG_USE_NATIVE_SYSLOG #include @@ -422,7 +422,7 @@ struct syslog_backend::implementation::udp_socket_based : //! Pointer to the list of sockets shared_ptr< syslog_udp_service > m_pService; //! Pointer to the socket being used - log::aux::unique_ptr< syslog_udp_socket > m_pSocket; + std::unique_ptr< syslog_udp_socket > m_pSocket; //! The target host to send packets to asio::ip::udp::endpoint m_TargetHost; diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 1fb3a4944a..924f3cd6f2 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -56,7 +56,6 @@ #include #include #include -#include "unique_ptr.hpp" #if !defined(BOOST_LOG_NO_THREADS) #include diff --git a/src/unique_ptr.hpp b/src/unique_ptr.hpp deleted file mode 100644 index 091bb9cf8d..0000000000 --- a/src/unique_ptr.hpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Andrey Semashev 2007 - 2015. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - */ -/*! - * \file unique_ptr.hpp - * \author Andrey Semashev - * \date 18.07.2015 - * - * \brief This header is the Boost.Log library implementation, see the library documentation - * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. - */ - -#ifndef BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_ -#define BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_ - -#include - -#if !defined(BOOST_NO_CXX11_SMART_PTR) - -#include - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace aux { - -using std::unique_ptr; - -} // namespace aux - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#else // !defined(BOOST_NO_CXX11_SMART_PTR) - -#include - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace aux { - -using boost::movelib::unique_ptr; - -} // namespace aux - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#endif // !defined(BOOST_NO_CXX11_SMART_PTR) - -#endif // BOOST_LOG_UNIQUE_PTR_HPP_INCLUDED_ diff --git a/src/windows/event_log_backend.cpp b/src/windows/event_log_backend.cpp index 7515f8bc56..6f9d81c911 100644 --- a/src/windows/event_log_backend.cpp +++ b/src/windows/event_log_backend.cpp @@ -17,6 +17,7 @@ #ifndef BOOST_LOG_WITHOUT_EVENT_LOG +#include #include #include #include @@ -33,7 +34,6 @@ #include #include #include -#include "unique_ptr.hpp" #include "windows/event_log_registry.hpp" #include "windows/simple_event_log.h" #include @@ -262,7 +262,7 @@ BOOST_LOG_API void basic_simple_event_log_backend< CharT >::construct( aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params); } - log::aux::unique_ptr< implementation > p(new implementation()); + std::unique_ptr< implementation > p(new implementation()); const char_type* target_unc = NULL; if (!target.empty()) @@ -518,7 +518,7 @@ BOOST_LOG_API void basic_event_log_backend< CharT >::construct( aux::init_event_log_registry(log_name, source_name, reg_mode == event_log::forced, reg_params); } - log::aux::unique_ptr< implementation > p(new implementation()); + std::unique_ptr< implementation > p(new implementation()); const char_type* target_unc = NULL; if (!target.empty()) diff --git a/src/windows/ipc_sync_wrappers.cpp b/src/windows/ipc_sync_wrappers.cpp index 77ec34b8fa..6848809235 100644 --- a/src/windows/ipc_sync_wrappers.cpp +++ b/src/windows/ipc_sync_wrappers.cpp @@ -26,6 +26,7 @@ #include // for error codes #include #include +#include #include #include #include @@ -34,7 +35,6 @@ #include #include #include -#include "unique_ptr.hpp" #include "windows/ipc_sync_wrappers.hpp" #include @@ -413,7 +413,7 @@ interprocess_condition_variable::semaphore_info* interprocess_condition_variable { // We need to open the semaphore. It is possible that the semaphore does not exist because all processes that had it opened terminated. // Because of this we also attempt to create it. - boost::log::aux::unique_ptr< semaphore_info > p(new semaphore_info(id)); + std::unique_ptr< semaphore_info > p(new semaphore_info(id)); generate_semaphore_name(id); p->m_semaphore.create_or_open(m_semaphore_name.c_str(), m_perms); From 7fc4a55d332ee6fa64a2a492661e477088517fab Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 19 Apr 2025 18:20:49 +0300 Subject: [PATCH 271/309] Removed usage of obsolete ubuntu-20.04 GHA image. --- .github/workflows/ci.yml | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4921756a26..c9c02ae389 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -62,12 +62,14 @@ jobs: - g++-8 - toolset: gcc-9 cxxstd: "11,14,17,2a" - os: ubuntu-20.04 + os: ubuntu-latest + container: ubuntu:20.04 install: - g++-9 - toolset: gcc-10 cxxstd: "11,14,17,20" - os: ubuntu-20.04 + os: ubuntu-latest + container: ubuntu:20.04 install: - g++-10 - toolset: gcc-11 @@ -176,13 +178,15 @@ jobs: - toolset: clang compiler: clang++-9 cxxstd: "11,14,17,2a" - os: ubuntu-20.04 + os: ubuntu-latest + container: ubuntu:20.04 install: - clang-9 - toolset: clang compiler: clang++-10 cxxstd: "11,14,17,20" - os: ubuntu-20.04 + os: ubuntu-latest + container: ubuntu:20.04 install: - clang-10 - toolset: clang @@ -295,7 +299,7 @@ jobs: - name: CMake tests cmake_tests: 1 - os: ubuntu-20.04 + os: ubuntu-24.04 timeout-minutes: 60 runs-on: ${{matrix.os}} From ad61f2c13ec249bfcaf5ebefbe4b06049cb14884 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 14 May 2025 17:36:20 +0300 Subject: [PATCH 272/309] Disabled MSVC warnings about implicitly defined ctor/assignment being deleted. Closes https://github.com/boostorg/log/issues/247. Closes https://github.com/boostorg/log/pull/248. --- include/boost/log/detail/header.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/boost/log/detail/header.hpp b/include/boost/log/detail/header.hpp index 37495c00c2..cb7b315323 100644 --- a/include/boost/log/detail/header.hpp +++ b/include/boost/log/detail/header.hpp @@ -42,6 +42,10 @@ #pragma warning(disable: 4456) // declaration of 'A' hides global declaration #pragma warning(disable: 4459) +// copy constructor was implicitly defined as deleted because a base class copy constructor is inaccessible or deleted +#pragma warning(disable: 4625) +// assignment operator was implicitly defined as deleted because a base class assignment operator is inaccessible or deleted +#pragma warning(disable: 4626) // 'X': This function or variable may be unsafe. Consider using Y instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details. #pragma warning(disable: 4996) From 2530a4e03a51be0c38c171323dd04eea69419f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Ferdinand=20Rivera=20Morell?= Date: Sun, 25 May 2025 16:48:16 -0500 Subject: [PATCH 273/309] Add support for modular build structure. (#233) * Make the library modular usable. * Switch to library requirements instead of source. As source puts extra source in install targets. * Clean up build dependencies. * Remove external build references and avoid custom project loading. * Use relative paths to declare config sub-projects. * Add missing NO_LIB usage requirements. * Add missing library ref. * Add missing import-search for cconfig/predef checks. * Add requires-b2 check to top-level build file. * Update dependencies. * Bump B2 require to 5.2 * Update copyright dates. * Move inter-lib dependencies to a project variable and into the build targets. * Remove custom symbolic project names for config subprojects. And use project root relative targets. * Move private deps to the build project. * Put back default boost locale link as locale build is now fixed. * Set default address-model and architecture to avoid extra/custom detection logic. Put back missing check and config rules. * Adjust doc build to avoid boost-root references. * Fix ref to predef.jam location. * Have B2 build use same deps as CML for per-target private/public. * Add log dep to log_setup, as it's needed on some platforms. * Add boost_log_with_support target to mirror CML. * Fix platform specific winapi dependency spec. --- build.jam | 19 +++ build/Jamfile.v2 | 147 ++++++++++++++++++------ build/log-arch-config.jam | 59 +--------- build/log-build-config.jam | 20 +--- build/log-platform-config.jam | 8 +- config/atomic-int32/Jamfile.jam | 4 +- config/build.jam | 14 +++ config/message-compiler/Jamfile.jam | 2 +- config/native-syslog/Jamfile.jam | 2 +- config/pthread-mutex-robust/Jamfile.jam | 2 +- config/regex-header-only/Jamfile.jam | 2 +- config/x86-ext/Jamfile.jam | 4 +- config/xopen-source-600/Jamfile.jam | 2 +- doc/Jamfile.v2 | 32 +++--- example/doc/Jamfile.v2 | 5 +- example/event_log/Jamfile.v2 | 2 +- test/Jamfile.v2 | 4 +- 17 files changed, 189 insertions(+), 139 deletions(-) create mode 100644 build.jam create mode 100644 config/build.jam diff --git a/build.jam b/build.jam new file mode 100644 index 0000000000..aac1c89ecb --- /dev/null +++ b/build.jam @@ -0,0 +1,19 @@ +# Copyright René Ferdinand Rivera Morell 2023-2024 +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +require-b2 5.2 ; + +project /boost/log ; + +explicit + [ alias boost_log : build//boost_log ] + [ alias boost_log_setup : build//boost_log_setup ] + [ alias boost_log_with_support : build//boost_log_with_support ] + [ alias all : boost_log boost_log_setup boost_log_with_support example test ] + ; + +call-if : boost-library log + : install boost_log boost_log_setup + ; diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 6c4d2d1117..79d40a06a9 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -12,53 +12,120 @@ import path ; import project ; import feature ; import configure ; +import-search /boost/config/checks ; import config : requires ; import log-arch-config ; import log-platform-config ; import log-build-config ; +import-search /boost/predef/tools/check ; +import predef ; using mc ; -local here = [ modules.binding $(__name__) ] ; - -project.push-current [ project.current ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/x86-ext ] ; -project.pop-current ; - # Windows libs -lib psapi ; -lib advapi32 ; -lib secur32 ; -lib ws2_32 ; -lib mswsock ; +searched-lib psapi ; +searched-lib advapi32 ; +searched-lib secur32 ; +searched-lib ws2_32 ; +searched-lib mswsock ; explicit psapi advapi32 secur32 ws2_32 mswsock ; # UNIX libs -lib rt ; -lib socket ; -lib nsl ; -lib ipv6 ; +searched-lib rt ; +searched-lib socket ; +searched-lib nsl ; +searched-lib ipv6 ; explicit rt socket nsl ipv6 ; -local log_cxx_public_requirements = [ requires +constant boost_log_public_deps : + /boost/assert//boost_assert + /boost/config//boost_config + /boost/core//boost_core + /boost/date_time//boost_date_time + /boost/filesystem//boost_filesystem + /boost/function_types//boost_function_types + /boost/fusion//boost_fusion + /boost/intrusive//boost_intrusive + /boost/move//boost_move + /boost/mpl//boost_mpl + /boost/parameter//boost_parameter + /boost/phoenix//boost_phoenix + /boost/predef//boost_predef + /boost/preprocessor//boost_preprocessor + /boost/proto//boost_proto + /boost/range//boost_range + /boost/smart_ptr//boost_smart_ptr + /boost/system//boost_system + /boost/throw_exception//boost_throw_exception + /boost/type_index//boost_type_index + /boost/type_traits//boost_type_traits + /boost/utility//boost_utility + windows:/boost/winapi//boost_winapi + [ requires cxx11_static_assert - ] ; + ] + ; -local log_cxx_private_requirements = [ requires +constant boost_log_private_deps : + /boost/align//boost_align + /boost/asio//boost_asio + /boost/bind//boost_bind + /boost/exception//boost_exception + /boost/interprocess//boost_interprocess + /boost/optional//boost_optional + /boost/random//boost_random + /boost/spirit//boost_spirit + [ requires cxx11_lambdas - ] ; + ] + ; -local log_setup_cxx_public_requirements = [ requires +constant boost_log_setup_public_deps : + /boost/assert//boost_assert + /boost/config//boost_config + /boost/core//boost_core + /boost/iterator//boost_iterator + /boost/move//boost_move + /boost/optional//boost_optional + /boost/parameter//boost_parameter + /boost/phoenix//boost_phoenix + /boost/preprocessor//boost_preprocessor + /boost/property_tree//boost_property_tree + /boost/smart_ptr//boost_smart_ptr + /boost/type_traits//boost_type_traits + [ requires cxx11_static_assert cxx11_unified_initialization_syntax - ] ; + ] + ; -local log_setup_cxx_public_requirements = [ requires +constant boost_log_setup_private_deps : + /boost/asio//boost_asio + /boost/bind//boost_bind + /boost/date_time//boost_date_time + /boost/exception//boost_exception + /boost/filesystem//boost_filesystem + /boost/io//boost_io + /boost/log//boost_log + /boost/spirit//boost_spirit + /boost/throw_exception//boost_throw_exception + /boost/utility//boost_utility + [ requires cxx11_lambdas - ] ; + ] + ; -project boost/log +constant boost_log_support_public_deps : + /boost/log//boost_log + /boost/exception//boost_exception + /boost/spirit//boost_spirit + /boost/xpressive//boost_xpressive + ; + +project : source-location ../src + : common-requirements + ../include : requirements @log-arch-config.check-instruction-set @log-build-config.check-atomic-int32 @@ -129,6 +196,10 @@ project boost/log freebsd:rt qnxnto:socket pgi:rt + + # Set these to computed values according to the build. + [ predef.address-model ] + [ predef.architecture ] : usage-requirements clang:-Wno-bind-to-temporary-copy clang:-Wno-unused-function @@ -218,16 +289,16 @@ rule select-arch-specific-sources ( properties * ) { local result ; - if x86 in [ log-arch-config.deduce-architecture $(properties) ] + if x86 in $(properties) { - local has_ssse3 = [ configure.builds /boost/log/x86-extensions//ssse3 : $(properties) : "compiler supports SSSE3" ] ; + local has_ssse3 = [ configure.builds /boost/log/config/x86-ext//ssse3 : $(properties) : "compiler supports SSSE3" ] ; if $(has_ssse3) { result += BOOST_LOG_USE_SSSE3 ; result += $(BOOST_LOG_COMMON_SSSE3_SRC) ; } - local has_avx2 = [ configure.builds /boost/log/x86-extensions//avx2 : $(properties) : "compiler supports AVX2" ] ; + local has_avx2 = [ configure.builds /boost/log/config/x86-ext//avx2 : $(properties) : "compiler supports AVX2" ] ; if $(has_avx2) { result += BOOST_LOG_USE_AVX2 ; @@ -302,13 +373,14 @@ lib boost_log @select-platform-specific-sources shared:BOOST_LOG_DLL BOOST_LOG_BUILDING_THE_LIB=1 - $(log_cxx_public_requirements) - $(log_cxx_private_requirements) + $(boost_log_private_deps) + $(boost_log_public_deps) : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_DYN_LINK=1 single:BOOST_LOG_NO_THREADS - $(log_cxx_public_requirements) + BOOST_LOG_NO_LIB=1 + $(boost_log_public_deps) ; @@ -344,14 +416,19 @@ lib boost_log_setup shared:BOOST_LOG_DYN_LINK=1 shared:BOOST_LOG_SETUP_DLL BOOST_LOG_SETUP_BUILDING_THE_LIB=1 - $(log_setup_cxx_public_requirements) - $(log_setup_cxx_private_requirements) - boost_log + $(boost_log_setup_private_deps) + $(boost_log_setup_public_deps) : ## default-build ## : ## usage-requirements ## shared:BOOST_LOG_SETUP_DYN_LINK=1 single:BOOST_LOG_NO_THREADS - $(log_setup_cxx_public_requirements) + BOOST_LOG_SETUP_NO_LIB=1 + $(boost_log_setup_public_deps) ; -boost-install boost_log boost_log_setup ; +alias boost_log_with_support + : requirements + $(boost_log_support_public_deps) + : usage-requirements + $(boost_log_support_public_deps) + ; diff --git a/build/log-arch-config.jam b/build/log-arch-config.jam index ee410ce1e0..b5438ff009 100644 --- a/build/log-arch-config.jam +++ b/build/log-arch-config.jam @@ -13,68 +13,22 @@ import path ; import property ; import feature ; -local here = [ modules.binding $(__name__) ] ; - -project.push-current [ project.current ] ; -project.load [ path.join [ path.make $(here:D) ] ../../config/checks/architecture ] ; -project.pop-current ; - rule deduce-address-model ( properties * ) { - local address_model = [ feature.get-values "address-model" : $(properties) ] ; - if $(address_model) - { - return $(address_model) ; - } - else - { - if [ configure.builds /boost/architecture//32 : $(properties) : 32-bit ] - { - return 32 ; - } - else if [ configure.builds /boost/architecture//64 : $(properties) : 64-bit ] - { - return 64 ; - } - } + # The address-model is always set to a deduced value using the predef.address-model checks. + return [ feature.get-values : $(properties) ] ; } rule deduce-architecture ( properties * ) { - local architecture = [ feature.get-values "architecture" : $(properties) ] ; - if $(architecture) - { - return $(architecture) ; - } - else - { - if [ configure.builds /boost/architecture//x86 : $(properties) : x86 ] - { - return x86 ; - } - else if [ configure.builds /boost/architecture//arm : $(properties) : arm ] - { - return arm ; - } - else if [ configure.builds /boost/architecture//mips : $(properties) : mips ] - { - return mips ; - } - else if [ configure.builds /boost/architecture//power : $(properties) : power ] - { - return power ; - } - else if [ configure.builds /boost/architecture//sparc : $(properties) : sparc ] - { - return sparc ; - } - } + # The architecture is always set to a deduced value using the predef.architecture checks. + return [ feature.get-values : $(properties) ] ; } rule deduce-instruction-set ( properties * ) { local result ; - local instruction_set = [ feature.get-values "instruction-set" : $(properties) ] ; + local instruction_set = [ feature.get-values : $(properties) ] ; if $(instruction_set) { @@ -95,7 +49,6 @@ rule deduce-instruction-set ( properties * ) rule ssse3-flags ( properties * ) { local result ; - if intel in $(properties) { if win in $(properties) @@ -111,7 +64,7 @@ rule ssse3-flags ( properties * ) { # MSVC doesn't really care about these switches, all SSE intrinsics are always available, but still... # Also 64 bit MSVC doesn't have the /arch:SSE2 switch as it is the default. - if 32 in [ deduce-address-model $(properties) ] + if 32 in $(properties) { result = "/arch:SSE2" ; } diff --git a/build/log-build-config.jam b/build/log-build-config.jam index 51cc312798..e32e720d6c 100644 --- a/build/log-build-config.jam +++ b/build/log-build-config.jam @@ -12,16 +12,6 @@ import path ; import property ; import feature ; -local here = [ modules.binding $(__name__) ] ; - -project.push-current [ project.current ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/message-compiler ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/pthread-mutex-robust ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/native-syslog ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/atomic-int32 ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/regex-header-only ] ; -project.pop-current ; - rule has-config-flag ( flag : properties * ) { if ( "$(flag)" in $(properties) || "$(flag)=1" in $(properties) ) @@ -38,7 +28,7 @@ rule check-regex-header-only ( properties * ) { local result ; - local has_regex_header_only = [ configure.builds /boost/log/regex-header-only//regex_header_only : $(properties) : "Boost.Regex is header-only" ] ; + local has_regex_header_only = [ configure.builds /boost/log/config/regex-header-only//regex_header_only : $(properties) : "Boost.Regex is header-only" ] ; if ! $(has_regex_header_only) { result = /boost/regex//boost_regex ; @@ -51,7 +41,7 @@ rule check-atomic-int32 ( properties * ) { local result ; - local has_atomic_int32 = [ configure.builds /boost/log/atomic-int32//atomic_int32 : $(properties) : "native atomic int32 supported" ] ; + local has_atomic_int32 = [ configure.builds /boost/log/config/atomic-int32//atomic_int32 : $(properties) : "native atomic int32 supported" ] ; if ! $(has_atomic_int32) { result = BOOST_LOG_WITHOUT_IPC ; @@ -64,7 +54,7 @@ rule check-pthread-mutex-robust ( properties * ) { local result ; - local has_pthread_mutex_robust = [ configure.builds /boost/log/pthread-mutex-robust//pthread_mutex_robust : $(properties) : "pthread supports robust mutexes" ] ; + local has_pthread_mutex_robust = [ configure.builds /boost/log/config/pthread-mutex-robust//pthread_mutex_robust : $(properties) : "pthread supports robust mutexes" ] ; if $(has_pthread_mutex_robust) { result = BOOST_LOG_HAS_PTHREAD_MUTEX_ROBUST ; @@ -79,7 +69,7 @@ rule check-native-syslog ( properties * ) if ! [ has-config-flag BOOST_LOG_WITHOUT_SYSLOG : $(properties) ] { - local has_native_syslog = [ configure.builds /boost/log/native-syslog//native_syslog : $(properties) : "native syslog supported" ] ; + local has_native_syslog = [ configure.builds /boost/log/config/native-syslog//native_syslog : $(properties) : "native syslog supported" ] ; if $(has_native_syslog) { result = BOOST_LOG_USE_NATIVE_SYSLOG ; @@ -97,7 +87,7 @@ rule check-message-compiler ( properties * ) { if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] { - local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : "has message compiler" ] ; + local has_mc = [ configure.builds /boost/log/config/message-compiler//test-availability : $(properties) : "has message compiler" ] ; if ! $(has_mc) { result = BOOST_LOG_WITHOUT_EVENT_LOG ; diff --git a/build/log-platform-config.jam b/build/log-platform-config.jam index 93b31431b4..d83d41f128 100644 --- a/build/log-platform-config.jam +++ b/build/log-platform-config.jam @@ -12,12 +12,6 @@ import path ; import property ; import feature ; -local here = [ modules.binding $(__name__) ] ; - -project.push-current [ project.current ] ; -project.load [ path.join [ path.make $(here:D) ] ../config/xopen-source-600 ] ; -project.pop-current ; - rule set-platform-defines ( properties * ) { local result ; @@ -49,7 +43,7 @@ rule set-platform-defines ( properties * ) { # Solaris headers are broken and cannot be included in C++03 when _XOPEN_SOURCE=600. At the same time, they cannot be included with _XOPEN_SOURCE=500 in C++11 and later. # This is because the system headers check the C language version and error out if the version does not match. We have to test if we can request _XOPEN_SOURCE=600. - if [ configure.builds /boost/log/xopen-source-600//xopen_source_600 : $(properties) : xopen-source-600-supported ] + if [ configure.builds /boost/log/config/xopen-source-600//xopen_source_600 : $(properties) : xopen-source-600-supported ] { result += _XOPEN_SOURCE=600 ; } diff --git a/config/atomic-int32/Jamfile.jam b/config/atomic-int32/Jamfile.jam index 2f8d4baf29..308ce94170 100644 --- a/config/atomic-int32/Jamfile.jam +++ b/config/atomic-int32/Jamfile.jam @@ -6,9 +6,9 @@ # import project ; -import log-platform-config ; +import ../../build/log-platform-config ; -project /boost/log/atomic-int32 +project : source-location . : requirements @log-platform-config.set-platform-defines diff --git a/config/build.jam b/config/build.jam new file mode 100644 index 0000000000..551de845f6 --- /dev/null +++ b/config/build.jam @@ -0,0 +1,14 @@ +# Copyright René Ferdinand Rivera Morell +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE_1_0.txt or copy at +# http://www.boost.org/LICENSE_1_0.txt) + +import-search /boost/predef/tools/check ; +import predef ; + +project + : requirements + # Set these to computed values according to the build. + [ predef.address-model ] + [ predef.architecture ] + ; diff --git a/config/message-compiler/Jamfile.jam b/config/message-compiler/Jamfile.jam index 6716021bbb..a42b801ecf 100644 --- a/config/message-compiler/Jamfile.jam +++ b/config/message-compiler/Jamfile.jam @@ -9,7 +9,7 @@ import project ; import log-platform-config ; using mc ; -project /boost/log/message-compiler +project : source-location ../../src : requirements @log-platform-config.set-platform-defines diff --git a/config/native-syslog/Jamfile.jam b/config/native-syslog/Jamfile.jam index dd9143f50a..3c89154045 100644 --- a/config/native-syslog/Jamfile.jam +++ b/config/native-syslog/Jamfile.jam @@ -8,7 +8,7 @@ import project ; import log-platform-config ; -project /boost/log/native-syslog +project : source-location . : requirements @log-platform-config.set-platform-defines diff --git a/config/pthread-mutex-robust/Jamfile.jam b/config/pthread-mutex-robust/Jamfile.jam index ac3de06bd6..49cd199353 100644 --- a/config/pthread-mutex-robust/Jamfile.jam +++ b/config/pthread-mutex-robust/Jamfile.jam @@ -8,7 +8,7 @@ import project ; import log-platform-config ; -project /boost/log/pthread-mutex-robust +project : source-location . : requirements @log-platform-config.set-platform-defines diff --git a/config/regex-header-only/Jamfile.jam b/config/regex-header-only/Jamfile.jam index 90d28e94fc..4f5873eee7 100644 --- a/config/regex-header-only/Jamfile.jam +++ b/config/regex-header-only/Jamfile.jam @@ -8,7 +8,7 @@ import project ; import log-platform-config ; -project /boost/log/regex-header-only +project : source-location . : requirements @log-platform-config.set-platform-defines diff --git a/config/x86-ext/Jamfile.jam b/config/x86-ext/Jamfile.jam index 5379dbd164..a010067e76 100644 --- a/config/x86-ext/Jamfile.jam +++ b/config/x86-ext/Jamfile.jam @@ -6,9 +6,9 @@ # import project ; -import log-arch-config ; +import ../../build/log-arch-config ; -project /boost/log/x86-extensions +project : source-location . : requirements off diff --git a/config/xopen-source-600/Jamfile.jam b/config/xopen-source-600/Jamfile.jam index d2a28ad567..b35fa46523 100644 --- a/config/xopen-source-600/Jamfile.jam +++ b/config/xopen-source-600/Jamfile.jam @@ -7,7 +7,7 @@ import project ; -project /boost/log/xopen-source-600 +project : source-location . : requirements off diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index adc588260e..46bd2bdb8d 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -86,57 +86,57 @@ local doxygen_params = local top_level_includes = [ glob - ../../../boost/log/*.hpp + ../include/boost/log/*.hpp ] ; local core_includes = [ glob - ../../../boost/log/core/*.hpp + ../include/boost/log/core/*.hpp ] ; local attributes_includes = [ glob - ../../../boost/log/attributes/*.hpp + ../include/boost/log/attributes/*.hpp ] ; local expressions_includes = [ glob - ../../../boost/log/expressions/*.hpp - ../../../boost/log/expressions/predicates/*.hpp - ../../../boost/log/expressions/formatters/*.hpp + ../include/boost/log/expressions/*.hpp + ../include/boost/log/expressions/predicates/*.hpp + ../include/boost/log/expressions/formatters/*.hpp ] ; local sources_includes = [ glob - ../../../boost/log/sources/*.hpp + ../include/boost/log/sources/*.hpp ] ; local sinks_includes = [ set.difference # Document all these files... [ glob - ../../../boost/log/sinks/*.hpp + ../include/boost/log/sinks/*.hpp ] : # ...except these [ glob - ../../../boost/log/sinks/nt6_event_log*.hpp + ../include/boost/log/sinks/nt6_event_log*.hpp ] ] ; local utility_includes = [ glob - ../../../boost/log/utility/*.hpp - ../../../boost/log/utility/ipc/*.hpp - ../../../boost/log/utility/setup/*.hpp - ../../../boost/log/utility/type_dispatch/*.hpp - ../../../boost/log/utility/functional/*.hpp - ../../../boost/log/utility/manipulators/*.hpp + ../include/boost/log/utility/*.hpp + ../include/boost/log/utility/ipc/*.hpp + ../include/boost/log/utility/setup/*.hpp + ../include/boost/log/utility/type_dispatch/*.hpp + ../include/boost/log/utility/functional/*.hpp + ../include/boost/log/utility/manipulators/*.hpp ] ; local support_includes = [ glob - ../../../boost/log/support/*.hpp + ../include/boost/log/support/*.hpp ] ; diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index 1a1fe40595..c84959ef1d 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -29,7 +29,7 @@ rule check-message-compiler ( properties * ) { if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] { - local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ; + local has_mc = [ configure.builds /boost/log/config/message-compiler//test-availability : $(properties) : message-compiler ] ; if ! $(has_mc) { result = BOOST_LOG_WITHOUT_EVENT_LOG ; @@ -89,6 +89,9 @@ project /boost/date_time//boost_date_time /boost/filesystem//boost_filesystem /boost/thread//boost_thread + /boost/lambda//boost_lambda + /boost/scope_exit//boost_scope_exit + /boost/format//boost_format multi ; diff --git a/example/event_log/Jamfile.v2 b/example/event_log/Jamfile.v2 index ab80036d4f..89e652d055 100644 --- a/example/event_log/Jamfile.v2 +++ b/example/event_log/Jamfile.v2 @@ -29,7 +29,7 @@ rule check-message-compiler ( properties * ) { if ! [ has-config-flag BOOST_LOG_WITHOUT_EVENT_LOG : $(properties) ] { - local has_mc = [ configure.builds /boost/log/message-compiler//test-availability : $(properties) : message-compiler ] ; + local has_mc = [ configure.builds /boost/log/config/message-compiler//test-availability : $(properties) : message-compiler ] ; if ! $(has_mc) { result += no ; diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a3bb840f1e..fe60de1edd 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -71,8 +71,8 @@ rule test_all if ! [ os.environ BOOST_LOG_TEST_WITHOUT_SELF_CONTAINED_HEADER_TESTS ] { - local headers_path = [ path.make $(BOOST_ROOT)/libs/log/include/boost/log ] ; - for file in [ path.glob-tree $(headers_path) : *.hpp : detail ] + local headers_path = ../include/boost/log ; + for file in [ glob-tree-ex $(headers_path) : *.hpp : detail ] { local rel_file = [ path.relative-to $(headers_path) $(file) ] ; # Note: The test name starts with '~' in order to group these tests in the test report table, preferably at the end. From 15bfb08b0a69352004871cae8aa071a95d7af1c4 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 30 May 2025 15:10:23 +0300 Subject: [PATCH 274/309] Relax property check in has-config-flag. We are only interested in whether a config flag is defined, the value of the define is irrelevant. So instead of checking for a value of 1, detect the flag with any value, if present. --- build/log-build-config.jam | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/build/log-build-config.jam b/build/log-build-config.jam index e32e720d6c..212ef1095b 100644 --- a/build/log-build-config.jam +++ b/build/log-build-config.jam @@ -1,6 +1,6 @@ # log-build-config.jam # -# Copyright 2023 Andrey Semashev +# Copyright 2023-2025 Andrey Semashev # # Distributed under the Boost Software License Version 1.0. (See # accompanying file LICENSE_1_0.txt or copy at @@ -14,14 +14,18 @@ import feature ; rule has-config-flag ( flag : properties * ) { - if ( "$(flag)" in $(properties) || "$(flag)=1" in $(properties) ) - { - return 1 ; - } - else + local result ; + + for local property in $(properties) { - return ; + if [ MATCH "^($(flag))(=.*)?$" : $(property) ] + { + result = 1 ; + break ; + } } + + return $(result) ; } rule check-regex-header-only ( properties * ) From 4bd90c7d6c8d7d7dd2fb2c0dd74a5104ef3898d1 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 30 May 2025 15:44:23 +0300 Subject: [PATCH 275/309] Allow multiple defines to be specified in has-config-flag. --- build/log-build-config.jam | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/build/log-build-config.jam b/build/log-build-config.jam index 212ef1095b..555ded141f 100644 --- a/build/log-build-config.jam +++ b/build/log-build-config.jam @@ -12,20 +12,21 @@ import path ; import property ; import feature ; -rule has-config-flag ( flag : properties * ) +# The rule checks if there is one of the defines listed in `flags` in `properties`. The value of the define is not considered. +rule has-config-flag ( flags + : properties * ) { - local result ; - for local property in $(properties) { - if [ MATCH "^($(flag))(=.*)?$" : $(property) ] + for local flag in $(flags) { - result = 1 ; - break ; + if [ MATCH "^($(flag))(=.*)?$" : $(property) ] + { + return 1 ; + } } } - return $(result) ; + return ; } rule check-regex-header-only ( properties * ) @@ -116,11 +117,7 @@ rule select-regex-backend ( properties * ) local result ; # Use Boost.Regex backend by default. It produces smaller executables and also has the best performance for small string matching. - if ! ( - [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS : $(properties) ] || - [ log-build-config.has-config-flag BOOST_LOG_WITHOUT_DEFAULT_FACTORIES : $(properties) ] || - [ log-build-config.has-config-flag BOOST_LOG_USE_STD_REGEX : $(properties) ] || - [ log-build-config.has-config-flag BOOST_LOG_USE_BOOST_XPRESSIVE : $(properties) ] ) + if ! [ has-config-flag BOOST_LOG_WITHOUT_SETTINGS_PARSERS BOOST_LOG_WITHOUT_DEFAULT_FACTORIES BOOST_LOG_USE_STD_REGEX BOOST_LOG_USE_BOOST_XPRESSIVE : $(properties) ] { result = @log-build-config.check-regex-header-only ; } From 1c956799d5054cc61571ab0d0d39e282b355ce46 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 31 May 2025 16:05:06 +0300 Subject: [PATCH 276/309] Made configure check for native atomic int32 more lightweight. Only include capabilities.hpp to test whether native atomic int32 is supported. Also added a dependency on Boost.Atomic, which may be needed in modular builds. --- config/atomic-int32/Jamfile.jam | 1 + config/atomic-int32/atomic_int32.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config/atomic-int32/Jamfile.jam b/config/atomic-int32/Jamfile.jam index 308ce94170..bc20c0d02b 100644 --- a/config/atomic-int32/Jamfile.jam +++ b/config/atomic-int32/Jamfile.jam @@ -12,6 +12,7 @@ project : source-location . : requirements @log-platform-config.set-platform-defines + /boost/atomic//boost_atomic off ; diff --git a/config/atomic-int32/atomic_int32.cpp b/config/atomic-int32/atomic_int32.cpp index f39bcc8f5b..6f3285f6d0 100644 --- a/config/atomic-int32/atomic_int32.cpp +++ b/config/atomic-int32/atomic_int32.cpp @@ -5,9 +5,9 @@ * http://www.boost.org/LICENSE_1_0.txt) */ -#include +#include -#if !defined(BOOST_ATOMIC_INT32_LOCK_FREE) || (BOOST_ATOMIC_INT32_LOCK_FREE+0) != 2 +#if !defined(BOOST_ATOMIC_INT32_LOCK_FREE) || (BOOST_ATOMIC_INT32_LOCK_FREE != 2) #error Boost.Log: Native 32-bit atomic operations are required but not supported by Boost.Atomic on the target platform #endif From 9ee2e2953c51df14653a555dcd0499f73d704e34 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 31 May 2025 16:18:13 +0300 Subject: [PATCH 277/309] Check for native atomic int32 in tests. If native atomic int32 is not supported, Boost.Log disables IPC utilities, so make a similar check in tests Jamfile to disable the corresponding tests. --- test/Jamfile.v2 | 1 + 1 file changed, 1 insertion(+) diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index fe60de1edd..a685dff195 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -16,6 +16,7 @@ import ../build/log-build-config ; project : requirements @log-platform-config.set-platform-defines + @log-build-config.check-atomic-int32 # sets BOOST_LOG_WITHOUT_IPC if native atomic int32 is not supported @log-build-config.check-regex-header-only common From 1cb564b688942fa8e8c1a2e229b2a913d8766d3b Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 31 May 2025 16:23:39 +0300 Subject: [PATCH 278/309] Added dependency on Boost.Regex in regex-header-only test. This may be needed in modular builds. --- config/regex-header-only/Jamfile.jam | 1 + 1 file changed, 1 insertion(+) diff --git a/config/regex-header-only/Jamfile.jam b/config/regex-header-only/Jamfile.jam index 4f5873eee7..4b718bcf9d 100644 --- a/config/regex-header-only/Jamfile.jam +++ b/config/regex-header-only/Jamfile.jam @@ -12,6 +12,7 @@ project : source-location . : requirements @log-platform-config.set-platform-defines + /boost/regex//boost_regex off ; From b2e49a91132a485ceaacc81c14f0cb5891c01423 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 31 May 2025 16:28:00 +0300 Subject: [PATCH 279/309] Replaced MinGW-w64 gcc 6 jobs with gcc 8. gcc 6 is no longer supported since it doesn't provide synchronization library that is needed by Boost.Atomic. --- appveyor.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 417b06c001..3ecf70dbff 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,4 +1,4 @@ -# Copyright 2019 - 2023 Andrey Semashev +# Copyright 2019 - 2025 Andrey Semashev # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -39,14 +39,14 @@ environment: APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 11,14 - ADDPATH: C:\mingw-w64\x86_64-6.3.0-posix-seh-rt_v5-rev1\mingw64\bin + CXXSTD: 11,14,17 + ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 - CXXSTD: 11,14,17 - ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin + CXXSTD: 11,14,17,2a + ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: clang-win ADDRESS_MODEL: 64 @@ -73,8 +73,8 @@ environment: - TOOLSET: gcc ADDRESS_MODEL: 32 CXXSTD: 11,14 - ADDPATH: C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 + ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin + APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: clang-win ADDRESS_MODEL: 32 CXXSTD: 14,17 From 48a33d9eb0fd1e5bd0efd50649c44a82dc2aeb84 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 11 Jun 2025 23:18:05 +0300 Subject: [PATCH 280/309] Use thread_pause from Boost.Atomic in ipc_reliable_message_queue. --- src/posix/ipc_reliable_message_queue.cpp | 4 ++-- src/windows/ipc_reliable_message_queue.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index c3b1cb6582..696e6d3e6c 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -40,11 +40,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include #include @@ -604,7 +604,7 @@ struct reliable_message_queue::implementation } if (i < region_init_wait_loops_pause) - boost::log::aux::pause(); + boost::atomics::thread_pause(); else if (i < region_init_wait_loops_short_yield) short_yield(); else diff --git a/src/windows/ipc_reliable_message_queue.cpp b/src/windows/ipc_reliable_message_queue.cpp index 146ae34739..ed90feb15a 100644 --- a/src/windows/ipc_reliable_message_queue.cpp +++ b/src/windows/ipc_reliable_message_queue.cpp @@ -30,10 +30,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -472,7 +472,7 @@ struct reliable_message_queue::implementation { for (unsigned int j = 0; j < spins; ++j) { - boost::log::aux::pause(); + boost::atomics::thread_pause(); } } else From fdcd3a233c466e4bb51496460ae32c74b66825c8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 12 Jun 2025 00:22:37 +0300 Subject: [PATCH 281/309] Reimplemented adaptive_mutex using Boost.Atomic. adaptive_mutex now uses Boost.Atomic on all platforms that support lock-free atomics native waiting/notifying operations for unsigned int and pthreads on the other platforms. Windows always uses Boost.Atomic. The new implementation blocks the thread after a number of attempts to acquire the lock with spinning backoff. This should reduce CPU load if for some reason the thread that owns the lock is holding it for a long time (which typically should not happen, since adaptive_mutex is currently only used in threadsafe_queue, which doesn't hold the lock for too long, unless the holder gets preempted). The change may be significant on POSIX systems, which previously always used pthreads, and performance characteristics of pthread_mutex_t could have been different from our Boost.Atomic-based implementation. --- include/boost/log/detail/adaptive_mutex.hpp | 165 ++++++++++---------- 1 file changed, 86 insertions(+), 79 deletions(-) diff --git a/include/boost/log/detail/adaptive_mutex.hpp b/include/boost/log/detail/adaptive_mutex.hpp index fa06a0bdbf..e642a2ac97 100644 --- a/include/boost/log/detail/adaptive_mutex.hpp +++ b/include/boost/log/detail/adaptive_mutex.hpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2025. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -24,36 +24,19 @@ #ifndef BOOST_LOG_NO_THREADS -#if defined(BOOST_THREAD_POSIX) // This one can be defined by users, so it should go first -#define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD -#elif defined(BOOST_WINDOWS) -#define BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI -#elif defined(BOOST_HAS_PTHREADS) -#define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD -#endif +#include -#if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_WINAPI) - -#include -#include -#include - -#if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# if defined(__INTEL_COMPILER) -# define BOOST_LOG_COMPILER_BARRIER __memory_barrier() -# elif defined(__clang__) // clang-win also defines _MSC_VER -# define BOOST_LOG_COMPILER_BARRIER __atomic_signal_fence(__ATOMIC_SEQ_CST) -# else -extern "C" void _ReadWriteBarrier(void); -# if defined(BOOST_MSVC) -# pragma intrinsic(_ReadWriteBarrier) -# endif -# define BOOST_LOG_COMPILER_BARRIER _ReadWriteBarrier() -# endif -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# define BOOST_LOG_COMPILER_BARRIER __asm__ __volatile__("" : : : "memory") +#if defined(BOOST_WINDOWS) || (BOOST_ATOMIC_INT_LOCK_FREE == 2) && (BOOST_ATOMIC_HAS_NATIVE_INT_WAIT_NOTIFY == 2) +#define BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_ATOMIC +#else +#define BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_PTHREAD #endif +#if defined(BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_ATOMIC) + +#include +#include +#include #include namespace boost { @@ -62,73 +45,97 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -//! A mutex that performs spinning or thread yielding in case of contention +//! A mutex that performs spinning or thread blocking in case of contention class adaptive_mutex { private: - enum state + enum state : unsigned int { - initial_pause = 2, - max_pause = 16 + locked_bit = 1u, + waiters_one = 1u << 1u }; - long m_State; + enum pause_constants : unsigned int + { + initial_pause = 1u, + max_pause = 16u + }; + + //! Mutex state. Lowest bit indicates whether the mutex is locked or not, all higher bits store the number of blocked waiters. See \c state enum. + boost::atomics::atomic< unsigned int > m_state; public: - adaptive_mutex() : m_State(0) {} + adaptive_mutex() noexcept : m_state(0u) {} - bool try_lock() + // Non-copyable + adaptive_mutex(adaptive_mutex const&) = delete; + adaptive_mutex& operator= (adaptive_mutex const&) = delete; + + bool try_lock() noexcept { - return (BOOST_INTERLOCKED_COMPARE_EXCHANGE(&m_State, 1L, 0L) == 0L); + unsigned int old_state = m_state.load(boost::memory_order::relaxed); + return (old_state & locked_bit) == 0u && + m_state.compare_exchange_strong(old_state, old_state | locked_bit, boost::memory_order::acquire, boost::memory_order::relaxed); } - void lock() + void lock() noexcept { -#if defined(BOOST_LOG_AUX_PAUSE) unsigned int pause_count = initial_pause; -#endif - while (!try_lock()) + unsigned int waiter_added = 0u; + unsigned int old_state = m_state.load(boost::memory_order::relaxed); + while (true) { -#if defined(BOOST_LOG_AUX_PAUSE) + if ((old_state & locked_bit) == 0u) + { + unsigned int new_state = (old_state - waiter_added) | locked_bit; + if (m_state.compare_exchange_weak(old_state, new_state, boost::memory_order::acquire, boost::memory_order::relaxed)) + break; + + continue; + } + if (pause_count < max_pause) { - for (unsigned int i = 0; i < pause_count; ++i) + if (waiter_added != 0u) { - BOOST_LOG_AUX_PAUSE; + old_state = m_state.sub(waiters_one, boost::memory_order::relaxed); + waiter_added = 0u; } - pause_count += pause_count; + else + { + for (unsigned int i = 0u; i < pause_count; ++i) + { + boost::atomics::thread_pause(); + } + pause_count += pause_count; + + old_state = m_state.load(boost::memory_order::relaxed); + } + } + else if (waiter_added == 0u) + { + old_state = m_state.add(waiters_one, boost::memory_order::relaxed); + waiter_added = waiters_one; } else { // Restart spinning after waking up this thread pause_count = initial_pause; - boost::winapi::SwitchToThread(); + old_state = m_state.wait(old_state, boost::memory_order::relaxed); } -#else - boost::winapi::SwitchToThread(); -#endif } } - void unlock() + void unlock() noexcept { -#if (defined(_M_IX86) || defined(_M_AMD64)) && defined(BOOST_LOG_COMPILER_BARRIER) - BOOST_LOG_COMPILER_BARRIER; - m_State = 0L; - BOOST_LOG_COMPILER_BARRIER; -#else - BOOST_INTERLOCKED_EXCHANGE(&m_State, 0L); -#endif + if (m_state.and_and_test(~static_cast< unsigned int >(locked_bit), boost::memory_order::release)) + { + // If the resulting state is non-zero then there are blocked waiters + m_state.notify_one(); + } } - - // Non-copyable - BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&)) - BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&)) }; -#undef BOOST_LOG_AUX_PAUSE -#undef BOOST_LOG_COMPILER_BARRIER - } // namespace aux BOOST_LOG_CLOSE_NAMESPACE // namespace log @@ -137,7 +144,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include -#elif defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD) +#elif defined(BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_PTHREAD) #include #include @@ -147,7 +154,7 @@ BOOST_LOG_CLOSE_NAMESPACE // namespace log #include #if defined(PTHREAD_ADAPTIVE_MUTEX_INITIALIZER_NP) -#define BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP +#define BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP #endif namespace boost { @@ -156,37 +163,41 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -//! A mutex that performs spinning or thread yielding in case of contention +//! A mutex that performs spinning or thread blocking in case of contention class adaptive_mutex { private: - pthread_mutex_t m_State; + pthread_mutex_t m_state; public: adaptive_mutex() { -#if defined(BOOST_LOG_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP) +#if defined(BOOST_LOG_AUX_ADAPTIVE_MUTEX_USE_PTHREAD_MUTEX_ADAPTIVE_NP) pthread_mutexattr_t attrs; pthread_mutexattr_init(&attrs); pthread_mutexattr_settype(&attrs, PTHREAD_MUTEX_ADAPTIVE_NP); - const int err = pthread_mutex_init(&m_State, &attrs); + const int err = pthread_mutex_init(&m_state, &attrs); pthread_mutexattr_destroy(&attrs); #else - const int err = pthread_mutex_init(&m_State, NULL); + const int err = pthread_mutex_init(&m_state, nullptr); #endif if (BOOST_UNLIKELY(err != 0)) throw_system_error(err, "Failed to initialize an adaptive mutex", "adaptive_mutex::adaptive_mutex()", __FILE__, __LINE__); } + // Non-copyable + adaptive_mutex(adaptive_mutex const&) = delete; + adaptive_mutex& operator= (adaptive_mutex const&) = delete; + ~adaptive_mutex() { - BOOST_VERIFY(pthread_mutex_destroy(&m_State) == 0); + BOOST_VERIFY(pthread_mutex_destroy(&m_state) == 0); } bool try_lock() { - const int err = pthread_mutex_trylock(&m_State); + const int err = pthread_mutex_trylock(&m_state); if (err == 0) return true; if (BOOST_UNLIKELY(err != EBUSY)) @@ -196,20 +207,16 @@ class adaptive_mutex void lock() { - const int err = pthread_mutex_lock(&m_State); + const int err = pthread_mutex_lock(&m_state); if (BOOST_UNLIKELY(err != 0)) throw_system_error(err, "Failed to lock an adaptive mutex", "adaptive_mutex::lock()", __FILE__, __LINE__); } - void unlock() + void unlock() noexcept { - BOOST_VERIFY(pthread_mutex_unlock(&m_State) == 0); + BOOST_VERIFY(pthread_mutex_unlock(&m_state) == 0); } - // Non-copyable - BOOST_DELETED_FUNCTION(adaptive_mutex(adaptive_mutex const&)) - BOOST_DELETED_FUNCTION(adaptive_mutex& operator= (adaptive_mutex const&)) - private: static BOOST_NOINLINE BOOST_LOG_NORETURN void throw_system_error(int err, const char* descr, const char* func, const char* file, int line) { From d6aa912c7dd719852b650eb3c27614f9b7ca574e Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 12 Jun 2025 00:35:09 +0300 Subject: [PATCH 282/309] Removed detail/pause.hpp. This header was no longer used as all uses have been ported to the better thread_pause equivalent in Boost.Atomic. --- include/boost/log/detail/pause.hpp | 61 ------------------------------ 1 file changed, 61 deletions(-) delete mode 100644 include/boost/log/detail/pause.hpp diff --git a/include/boost/log/detail/pause.hpp b/include/boost/log/detail/pause.hpp deleted file mode 100644 index c1b43498f0..0000000000 --- a/include/boost/log/detail/pause.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright Andrey Semashev 2016. - * Distributed under the Boost Software License, Version 1.0. - * (See accompanying file LICENSE_1_0.txt or copy at - * http://www.boost.org/LICENSE_1_0.txt) - */ -/*! - * \file pause.hpp - * \author Andrey Semashev - * \date 06.01.2016 - * - * \brief This header is the Boost.Log library implementation, see the library documentation - * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. - */ - -#ifndef BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ -#define BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ - -#include -#include - -#ifdef BOOST_HAS_PRAGMA_ONCE -#pragma once -#endif - -#if defined(__INTEL_COMPILER) || defined(_MSC_VER) -# if defined(_M_IX86) -# define BOOST_LOG_AUX_PAUSE __asm { pause } -# elif defined(_M_AMD64) -extern "C" void _mm_pause(void); -# if defined(BOOST_MSVC) -# pragma intrinsic(_mm_pause) -# endif -# define BOOST_LOG_AUX_PAUSE _mm_pause() -# endif -#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) -# define BOOST_LOG_AUX_PAUSE __asm__ __volatile__("pause;") -#endif - -namespace boost { - -BOOST_LOG_OPEN_NAMESPACE - -namespace aux { - -BOOST_FORCEINLINE void pause() BOOST_NOEXCEPT -{ -#if defined(BOOST_LOG_AUX_PAUSE) - BOOST_LOG_AUX_PAUSE; -#endif -} - -} // namespace aux - -BOOST_LOG_CLOSE_NAMESPACE // namespace log - -} // namespace boost - -#include - -#endif // BOOST_LOG_DETAIL_PAUSE_HPP_INCLUDED_ From d6528b6e0cfe1f097a070e6a3665ef06bdc98d83 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 12 Jun 2025 00:40:02 +0300 Subject: [PATCH 283/309] Removed windows-2019 GitHub Actions jobs. The windows-2019 image is deprecated and will soon be removed. This means MSVC versions prior to 14.3 are no longer tested in GitHub Actions, only on AppVeyor CI. In order to avoid CI job timeouts, split MSVC 14.3 into two jobs, one for C++14 and extra header tests and another one for other C++ versions. --- .github/workflows/ci.yml | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c9c02ae389..e3b5ff1efe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -# Copyright 2021-2024 Andrey Semashev +# Copyright 2021-2025 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) @@ -544,22 +544,19 @@ jobs: fail-fast: false matrix: include: - - toolset: msvc-14.0 + - toolset: msvc-14.3 cxxstd: "14" - os: windows-2019 + os: windows-2022 extra_tests: 1 - - toolset: msvc-14.2 - cxxstd: "14,17,20,latest" - os: windows-2019 - toolset: msvc-14.3 - cxxstd: "14,17,20,latest" + cxxstd: "17,20,latest" os: windows-2022 - toolset: clang-win cxxstd: "14,17,latest" os: windows-2022 - toolset: gcc - cxxstd: "11-gnu,14-gnu,17-gnu,2a-gnu" - os: windows-2019 + cxxstd: "11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + os: windows-2022 - name: CMake MSVC tests cmake_tests: 1 From 40eaf1923f6449c76db6c1bab1da35648fea7de2 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 02:17:28 +0300 Subject: [PATCH 284/309] Use Azure mirrors of Ubuntu .deb repositories in containers. This reduces the likelihood of spurious CI failures caused by DDoS filters being triggered by massive numbers of concurrent CI jobs. --- .github/workflows/ci.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3b5ff1efe..a666e9aa78 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -318,6 +318,22 @@ jobs: echo "GHA_CONTAINER=${{matrix.container}}" >> $GITHUB_ENV if [ -f "/etc/debian_version" ] then + # Use Azure APT mirrors in containers to avoid HTTP errors due to DDoS filters triggered by lots of CI jobs launching concurrently. + # Note that not all Ubuntu versions support "mirror+file:..." URIs in APT sources, so just use Azure mirrors exclusively. + # Note also that on recent Ubuntu versions DEB822 format is used for source files. + APT_SOURCES=() + if [ -d "/etc/apt/sources.list.d" ] + then + readarray -t APT_SOURCES < <(find "/etc/apt/sources.list.d" -type f -name '*.sources' -print) + fi + if [ -f "/etc/apt/sources.list" ] + then + APT_SOURCES+=("/etc/apt/sources.list") + fi + if [ "${#APT_SOURCES[@]}" -gt 0 ] + then + sed -i -E -e 's!([^ ]+) (http|https)://(archive|security)\.ubuntu\.com/ubuntu[^ ]*(.*)!\1 http://azure.archive.ubuntu.com/ubuntu/\4!' "${APT_SOURCES[@]}" + fi apt-get -o Acquire::Retries=$NET_RETRY_COUNT update if [ "$(apt-cache search "^python-is-python3$" | wc -l)" -ne 0 ] then From c6a268af54c02e22dc212ef20359c63164cdca63 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 13:41:06 +0300 Subject: [PATCH 285/309] Enabled extra tests on MinGW-w64 in GitHub Actions. Also moved the extra tests to a separate job to avoid timeouts. --- .github/workflows/ci.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a666e9aa78..d8031a873d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -571,7 +571,11 @@ jobs: cxxstd: "14,17,latest" os: windows-2022 - toolset: gcc - cxxstd: "11-gnu,14-gnu,17-gnu,20-gnu,23-gnu" + cxxstd: "11-gnu" + os: windows-2022 + extra_tests: 1 + - toolset: gcc + cxxstd: "14-gnu,17-gnu,20-gnu,23-gnu" os: windows-2022 - name: CMake MSVC tests From 6b2d476f0237830bd01fb9cb7683e2fbd8727b69 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 13:45:43 +0300 Subject: [PATCH 286/309] Removed extra tests from all AppVeyor jobs but one. This reduces the CI run time on AppVeyor, which is already too slow. Extra tests on other configurations are run on GitHub Actions. --- appveyor.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 3ecf70dbff..7336195277 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,13 +35,11 @@ environment: ADDRESS_MODEL: 64 CXXSTD: 11 ADDPATH: C:\cygwin64\bin - EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 CXXSTD: 11,14,17 ADDPATH: C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin - EXTRA_TESTS: 1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - TOOLSET: gcc ADDRESS_MODEL: 64 From a30d9313485c7748957e9683eaaf538ed7e3549a Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 15:29:38 +0300 Subject: [PATCH 287/309] Added new gcc and clang jobs to GitHub Actions. --- .github/workflows/ci.yml | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d8031a873d..bdc7350a41 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,6 +92,12 @@ jobs: os: ubuntu-24.04 install: - g++-14 + - toolset: gcc-15 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-latest + container: ubuntu:25.04 + install: + - g++-15 - name: UBSAN toolset: gcc-13 cxxstd: "11,14,17,20,23" @@ -258,22 +264,22 @@ jobs: os: ubuntu-24.04 install: - clang-19 - sources: - - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" - source_keys: - - "https://apt.llvm.org/llvm-snapshot.gpg.key" - toolset: clang - compiler: clang++-19 + compiler: clang++-20 cxxstd: "11,14,17,20,23,26" - os: ubuntu-24.04 + os: ubuntu-latest + container: ubuntu:25.04 install: - - clang-19 - - libc++-19-dev - - libc++abi-19-dev - sources: - - "deb http://apt.llvm.org/noble/ llvm-toolchain-noble-19 main" - source_keys: - - "https://apt.llvm.org/llvm-snapshot.gpg.key" + - clang-20 + - toolset: clang + compiler: clang++-20 + cxxstd: "11,14,17,20,23,26" + os: ubuntu-latest + container: ubuntu:25.04 + install: + - clang-20 + - libc++-20-dev + - libc++abi-20-dev cxxflags: -stdlib=libc++ linkflags: -stdlib=libc++ - name: UBSAN From ecc4466bc00b9b0398443207cbffba432090d5e6 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 14:57:36 +0300 Subject: [PATCH 288/309] Added BOOST_LOG_WITHOUT_ASIO config option. This lets users to disable Boost.ASIO-related functionality and remove the dependency on Boost.ASIO. This may be useful on platforms where Boost.ASIO or its dependencies don't work or disabled. Refs https://github.com/chriskohlhoff/asio/issues/1637. --- CMakeLists.txt | 23 +++++++++++++++++++--- build/Jamfile.v2 | 6 +++--- build/log-build-config.jam | 12 +++++++++++ doc/changelog.qbk | 1 + doc/install.qbk | 7 ++++--- example/doc/sinks_syslog.cpp | 4 ++-- example/syslog/main.cpp | 2 +- include/boost/log/detail/config.hpp | 6 +++--- include/boost/log/sinks/syslog_backend.hpp | 10 +++++----- src/setup/init_from_settings.cpp | 10 +++++----- src/syslog_backend.cpp | 14 ++++++------- 11 files changed, 63 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3122845028..6544d4f508 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright 2021-2024 Andrey Semashev +# Copyright 2021-2025 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt @@ -19,6 +19,7 @@ if (WIN32) set(BOOST_LOG_WITHOUT_EVENT_LOG OFF CACHE BOOL "Disable support for event log on Windows in Boost.Log") endif() set(BOOST_LOG_WITHOUT_IPC OFF CACHE BOOL "Disable support for inter-process communication in Boost.Log") +set(BOOST_LOG_WITHOUT_ASIO OFF CACHE BOOL "Disable support for Boost.ASIO in Boost.Log") set(BOOST_LOG_WITHOUT_SYSLOG OFF CACHE BOOL "Disable support for syslog API in Boost.Log") set(BOOST_LOG_USE_NATIVE_SYSLOG OFF CACHE BOOL "Force-enable using native syslog API in Boost.Log") set(BOOST_LOG_USE_COMPILER_TLS OFF CACHE BOOL "Enable using compiler-specific intrinsics for thread-local storage in Boost.Log") @@ -123,6 +124,10 @@ else() list(APPEND boost_log_common_public_defines BOOST_LOG_STATIC_LINK) endif() +if (BOOST_LOG_WITHOUT_ASIO) + list(APPEND boost_log_common_public_defines BOOST_LOG_WITHOUT_ASIO) +endif() + set(boost_log_sources src/alignment_gap_between.hpp src/attribute_name.cpp @@ -496,7 +501,6 @@ target_link_libraries(boost_log PRIVATE Boost::align - Boost::asio Boost::bind Boost::exception Boost::interprocess @@ -521,6 +525,13 @@ if (NOT BOOST_LOG_NO_THREADS) ) endif() +if (NOT BOOST_LOG_WITHOUT_ASIO) + target_link_libraries(boost_log + PRIVATE + Boost::asio + ) +endif() + target_compile_definitions(boost_log PUBLIC ${boost_log_common_public_defines} @@ -622,7 +633,6 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) ${boost_log_setup_public_deps} PRIVATE - Boost::asio Boost::bind Boost::date_time Boost::exception @@ -642,6 +652,13 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) ) endif() + if (NOT BOOST_LOG_WITHOUT_ASIO) + target_link_libraries(boost_log_setup + PRIVATE + Boost::asio + ) + endif() + target_compile_definitions(boost_log_setup PUBLIC ${boost_log_common_public_defines} diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 79d40a06a9..a8cf4ea8f5 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -1,5 +1,5 @@ # -# Copyright Andrey Semashev 2007 - 2023. +# Copyright Andrey Semashev 2007 - 2025. # Distributed under the Boost Software License, Version 1.0. # (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) @@ -68,13 +68,13 @@ constant boost_log_public_deps : constant boost_log_private_deps : /boost/align//boost_align - /boost/asio//boost_asio /boost/bind//boost_bind /boost/exception//boost_exception /boost/interprocess//boost_interprocess /boost/optional//boost_optional /boost/random//boost_random /boost/spirit//boost_spirit + @log-build-config.check-asio [ requires cxx11_lambdas ] @@ -100,7 +100,6 @@ constant boost_log_setup_public_deps : ; constant boost_log_setup_private_deps : - /boost/asio//boost_asio /boost/bind//boost_bind /boost/date_time//boost_date_time /boost/exception//boost_exception @@ -110,6 +109,7 @@ constant boost_log_setup_private_deps : /boost/spirit//boost_spirit /boost/throw_exception//boost_throw_exception /boost/utility//boost_utility + @log-build-config.check-asio [ requires cxx11_lambdas ] diff --git a/build/log-build-config.jam b/build/log-build-config.jam index 555ded141f..dd0a17b56e 100644 --- a/build/log-build-config.jam +++ b/build/log-build-config.jam @@ -124,3 +124,15 @@ rule select-regex-backend ( properties * ) return $(result) ; } + +rule check-asio ( properties * ) +{ + local result ; + + if ! [ has-config-flag BOOST_LOG_WITHOUT_ASIO : $(properties) ] + { + result = /boost/asio//boost_asio ; + } + + return $(result) ; +} diff --git a/doc/changelog.qbk b/doc/changelog.qbk index da31e36eff..06136a8829 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -11,6 +11,7 @@ [heading 2.32, Boost 1.89] +* Added support for `BOOST_LOG_WITHOUT_ASIO` configuration macro, which can be used to remove the dependency on __boost_asio__ and disable the related functionality. * Use locale-independent formatting of the file counter in `text_file_backend` when composing log file names. This fixes failures in the subsequent parsing of the file names in `file_collector::scan_for_files`. ([pull_request 246]) [heading 2.31, Boost 1.88] diff --git a/doc/install.qbk b/doc/install.qbk index 0909f9a403..522c3dd660 100644 --- a/doc/install.qbk +++ b/doc/install.qbk @@ -50,7 +50,7 @@ MinGW users on Windows XP may be affected by the [@http://sourceforge.net/p/ming [heading Additional notes for Cygwin users] -Cygwin support is very preliminary. The default GCC version available in Cygwin (4.5.3 as of this writing) is unable to compile the library because of compiler errors. You will have to build a newer GCC from sources. Even then some Boost.Log functionality is not available. In particular, the socket-based syslog backend is not supported, as it is based on __boost_asio__, which doesn't compile on this platform. However, the native syslog support is still in place. +Cygwin support is very preliminary. The default GCC version available in Cygwin (4.5.3 as of this writing) is unable to compile the library because of compiler errors. You will have to build a newer GCC from sources. Even then some Boost.Log functionality is not available. In particular, the socket-based [link log.detailed.sink_backends.syslog syslog backend] is not supported, as it is based on __boost_asio__, which doesn't compile on this platform. However, the native syslog support is still in place. [endsect] @@ -74,8 +74,9 @@ The library supports a number of configuration macros: [[`BOOST_LOG_WITHOUT_SETTINGS_PARSERS`] [Affects only compilation of the library. If defined, none of the facilities related to the parsers for settings will be built. This can substantially reduce the binary size.] [Disables compilation of the `boost_log_setup` library.]] [[`BOOST_LOG_WITHOUT_DEBUG_OUTPUT`] [Affects only compilation of the library. If defined, the support for debugger output on Windows will not be built.] []] [[`BOOST_LOG_WITHOUT_EVENT_LOG`] [Affects only compilation of the library. If defined, the support for Windows event log will not be built. Defining the macro also makes Message Compiler toolset unnecessary.] []] - [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for syslog backend will not be built.] []] - [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for interprocess queues will not be built.] []] + [[`BOOST_LOG_WITHOUT_SYSLOG`] [Affects only compilation of the library. If defined, the support for [link log.detailed.sink_backends.syslog syslog backend] will not be built.] []] + [[`BOOST_LOG_WITHOUT_IPC`] [Affects only compilation of the library. If defined, the support for [link log.detailed.utilities.ipc interprocess queues] and the related [link log.detailed.sink_backends.text_ipc_message_queue backend] will not be built.] []] + [[`BOOST_LOG_WITHOUT_ASIO`] [Affects compilation of both the library and users' code. If defined, the support for Boost.ASIO-dependent functionality will not be built. In particular, this disables socket-based [link log.detailed.sink_backends.syslog syslog backend] implementation.] []] [[`BOOST_LOG_NO_SHORTHAND_NAMES`] [Affects only compilation of users' code. If defined, some deprecated shorthand macro names will not be available.] [Not a CMake configuration option.]] [[`BOOST_LOG_USE_COMPILER_TLS`] [Affects only compilation of the library. This macro enables support for compiler intrinsics for thread-local storage. Defining it may improve performance of Boost.Log if certain usage limitations are acceptable. See below for more comments.] []] [[`BOOST_LOG_USE_STD_REGEX`, `BOOST_LOG_USE_BOOST_REGEX` or `BOOST_LOG_USE_BOOST_XPRESSIVE`] [Affects only compilation of the library. By defining one of these macros the user can instruct Boost.Log to use `std::regex`, __boost_regex__ or __boost_xpressive__ internally for string matching filters parsed from strings and settings. If none of these macros is defined then Boost.Log uses __boost_regex__ by default. Using `std::regex` or __boost_regex__ typically produces smaller executables, __boost_regex__ usually also being the fastest in run time. Using __boost_xpressive__ allows to eliminate the dependency on __boost_regex__ compiled binary. Note that these macros do not affect [link log.detailed.expressions.predicates.advanced_string_matching filtering expressions] created by users.] [Instead of definitng one of these macros, use `BOOST_LOG_USE_REGEX_BACKEND` string option with one of the following values: "std::regex", "Boost.Regex" or "Boost.Xpressive". The macros will be defined accordingly by CMake.]] diff --git a/example/doc/sinks_syslog.cpp b/example/doc/sinks_syslog.cpp index 6262304b01..25b0ffea97 100644 --- a/example/doc/sinks_syslog.cpp +++ b/example/doc/sinks_syslog.cpp @@ -54,7 +54,7 @@ void init_native_syslog() //-> //<- -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) //-> void init_builtin_syslog() { @@ -89,7 +89,7 @@ int main(int, char*[]) { #if defined(BOOST_LOG_USE_NATIVE_SYSLOG) init_native_syslog(); -#elif !defined(BOOST_LOG_NO_ASIO) +#elif !defined(BOOST_LOG_WITHOUT_ASIO) init_builtin_syslog(); #endif diff --git a/example/syslog/main.cpp b/example/syslog/main.cpp index 18db091955..aef1098ce5 100644 --- a/example/syslog/main.cpp +++ b/example/syslog/main.cpp @@ -73,7 +73,7 @@ int main(int argc, char* argv[]) sink->locked_backend()->set_severity_mapper(mapping); -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) // Set the remote address to sent syslog messages to sink->locked_backend()->set_target_address("localhost"); #endif diff --git a/include/boost/log/detail/config.hpp b/include/boost/log/detail/config.hpp index 0e69949ff1..4f188ef13e 100644 --- a/include/boost/log/detail/config.hpp +++ b/include/boost/log/detail/config.hpp @@ -103,9 +103,9 @@ # define BOOST_LOG_NO_CXX11_CODECVT_FACETS #endif -#if defined(__CYGWIN__) +#if defined(__CYGWIN__) && !defined(BOOST_LOG_WITHOUT_ASIO) // Boost.ASIO is broken on Cygwin -# define BOOST_LOG_NO_ASIO +# define BOOST_LOG_WITHOUT_ASIO #endif #if defined(__VXWORKS__) @@ -121,7 +121,7 @@ # define BOOST_LOG_NO_GETPWUID_R #endif -#if !defined(BOOST_LOG_USE_NATIVE_SYSLOG) && defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_USE_NATIVE_SYSLOG) && defined(BOOST_LOG_WITHOUT_ASIO) # ifndef BOOST_LOG_WITHOUT_SYSLOG # define BOOST_LOG_WITHOUT_SYSLOG # endif diff --git a/include/boost/log/sinks/syslog_backend.hpp b/include/boost/log/sinks/syslog_backend.hpp index 7424931189..4a4604dae5 100644 --- a/include/boost/log/sinks/syslog_backend.hpp +++ b/include/boost/log/sinks/syslog_backend.hpp @@ -57,11 +57,11 @@ namespace syslog { { #ifdef BOOST_LOG_USE_NATIVE_SYSLOG native = 0 //!< Use native syslog API -#ifndef BOOST_LOG_NO_ASIO +#ifndef BOOST_LOG_WITHOUT_ASIO , #endif #endif -#ifndef BOOST_LOG_NO_ASIO +#ifndef BOOST_LOG_WITHOUT_ASIO udp_socket_based = 1 //!< Use UDP sockets, according to RFC3164 #endif }; @@ -205,7 +205,7 @@ class syslog_backend : */ BOOST_LOG_API void set_severity_mapper(severity_mapper_type const& mapper); -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) /*! * The method sets the local host name which log records will be sent from. The host name @@ -247,7 +247,7 @@ class syslog_backend : */ BOOST_LOG_API void set_target_address(boost::asio::ip::address const& addr, unsigned short port = 514); -#endif // !defined(BOOST_LOG_NO_ASIO) +#endif // !defined(BOOST_LOG_WITHOUT_ASIO) /*! * The method passes the formatted message to the syslog API or sends to a syslog server @@ -262,7 +262,7 @@ class syslog_backend : { construct( args[keywords::facility | syslog::user], -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) args[keywords::use_impl | syslog::udp_socket_based], #else args[keywords::use_impl | syslog::native], diff --git a/src/setup/init_from_settings.cpp b/src/setup/init_from_settings.cpp index 86f4c4151e..378b1ea5dc 100644 --- a/src/setup/init_from_settings.cpp +++ b/src/setup/init_from_settings.cpp @@ -62,7 +62,7 @@ #include #include #include -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) #include #endif #if !defined(BOOST_LOG_NO_THREADS) @@ -171,14 +171,14 @@ inline sinks::auto_newline_mode param_cast_to_auto_newline_mode(const char* para } } -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) //! Extracts a network address from parameter value template< typename CharT > inline std::string param_cast_to_address(const char* param_name, std::basic_string< CharT > const& value) { return log::aux::to_narrow(value); } -#endif // !defined(BOOST_LOG_NO_ASIO) +#endif // !defined(BOOST_LOG_WITHOUT_ASIO) template< typename CharT > inline bool is_weekday(const CharT* str, std::size_t len, boost::log::basic_string_literal< CharT > const& weekday, boost::log::basic_string_literal< CharT > const& short_weekday) @@ -589,14 +589,14 @@ class default_syslog_sink_factory : // For now we use only the default level mapping. Will add support for configuration later. backend->set_severity_mapper(sinks::syslog::direct_severity_mapping< >(log::aux::default_attribute_names::severity())); -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) // Setup local and remote addresses if (optional< string_type > local_address_param = params["LocalAddress"]) backend->set_local_address(param_cast_to_address("LocalAddress", local_address_param.get())); if (optional< string_type > target_address_param = params["TargetAddress"]) backend->set_target_address(param_cast_to_address("TargetAddress", target_address_param.get())); -#endif // !defined(BOOST_LOG_NO_ASIO) +#endif // !defined(BOOST_LOG_WITHOUT_ASIO) return base_type::init_sink(backend, params); } diff --git a/src/syslog_backend.cpp b/src/syslog_backend.cpp index 8f383e1cb0..43eee4ff24 100644 --- a/src/syslog_backend.cpp +++ b/src/syslog_backend.cpp @@ -28,7 +28,7 @@ #include #include #include -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) #include #include #include @@ -90,7 +90,7 @@ struct syslog_backend::implementation #ifdef BOOST_LOG_USE_NATIVE_SYSLOG struct native; #endif // BOOST_LOG_USE_NATIVE_SYSLOG -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) struct udp_socket_based; #endif @@ -303,7 +303,7 @@ struct syslog_backend::implementation::native : // Socket-based implementation //////////////////////////////////////////////////////////////////////////////// -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) BOOST_LOG_ANONYMOUS_NAMESPACE { @@ -463,7 +463,7 @@ struct syslog_backend::implementation::udp_socket_based : } }; -#endif // !defined(BOOST_LOG_NO_ASIO) +#endif // !defined(BOOST_LOG_WITHOUT_ASIO) //////////////////////////////////////////////////////////////////////////////// // Sink backend implementation @@ -506,7 +506,7 @@ BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_ } #endif // BOOST_LOG_USE_NATIVE_SYSLOG -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) typedef implementation::udp_socket_based udp_socket_based_impl; asio::ip::udp protocol = asio::ip::udp::v4(); switch (ip_version) @@ -524,7 +524,7 @@ BOOST_LOG_API void syslog_backend::construct(syslog::facility fac, syslog::impl_ #endif } -#if !defined(BOOST_LOG_NO_ASIO) +#if !defined(BOOST_LOG_WITHOUT_ASIO) //! The method sets the local address which log records will be sent from. BOOST_LOG_API void syslog_backend::set_local_address(std::string const& addr, unsigned short port) @@ -617,7 +617,7 @@ BOOST_LOG_API void syslog_backend::set_target_address(boost::asio::ip::address c } } -#endif // !defined(BOOST_LOG_NO_ASIO) +#endif // !defined(BOOST_LOG_WITHOUT_ASIO) } // namespace sinks From 71635b6fba1ebddef0f79dd74eab0aa2661ad8a7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 13 Jun 2025 15:03:45 +0300 Subject: [PATCH 289/309] Disable Boost.ASIO in 32-bit MinGW-w64 job in AppVeyor. Boost.ASIO depends on Boost.Context, which requires cxx11_thread_local that is not supported on this target. This prevents Boost.Log from being built and tested. Refs https://github.com/chriskohlhoff/asio/issues/1637. --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 7336195277..0fb7c17d44 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -72,6 +72,9 @@ environment: ADDRESS_MODEL: 32 CXXSTD: 11,14 ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin + # Boost.Context, on which Boost.ASIO depends, does not build on this target, which prevents Boost.Log from building. + # https://github.com/chriskohlhoff/asio/issues/1637 + B2_ARGS: define=BOOST_LOG_WITHOUT_ASIO=1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: clang-win ADDRESS_MODEL: 32 From f01996cfd389793f0ff7b0227890cb6f7ff35de3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 14 Jun 2025 20:19:55 +0300 Subject: [PATCH 290/309] Removed dependency on Boost.Random. Boost.Random imposes excessive compiler requirements that prevents Boost.Log from being built and tested with 32-bit gcc 8 on MinGW-w64. We only need a fast RNG to quickly shuffle sinks in case of thread contention in the core. Use a local implementation of xorshift64 for such an RNG, which should be even faster than taus88 and have sufficiently good quality. Also, use std::random_device to initialize the PRNG. Keep the clock/thread_id based initialization as a backup, in case if std::random_device fails. Refs https://github.com/boostorg/random/issues/131. --- CMakeLists.txt | 1 - build/Jamfile.v2 | 1 - src/core.cpp | 30 ++++++++++++++++------ src/xorshift.hpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 10 deletions(-) create mode 100644 src/xorshift.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 6544d4f508..89336c078c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -505,7 +505,6 @@ target_link_libraries(boost_log Boost::exception Boost::interprocess Boost::optional - Boost::random Boost::spirit ${boost_log_regex_backend_private_libs} ) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index a8cf4ea8f5..9d6be4ffbe 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -72,7 +72,6 @@ constant boost_log_private_deps : /boost/exception//boost_exception /boost/interprocess//boost_interprocess /boost/optional//boost_optional - /boost/random//boost_random /boost/spirit//boost_spirit @log-build-config.check-asio [ requires diff --git a/src/core.cpp b/src/core.cpp index 40014bf61b..60025997ce 100644 --- a/src/core.cpp +++ b/src/core.cpp @@ -1,5 +1,5 @@ /* - * Copyright Andrey Semashev 2007 - 2015. + * Copyright Andrey Semashev 2007 - 2025. * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -28,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -45,6 +45,7 @@ #include #include #endif +#include "xorshift.hpp" #include "default_sink.hpp" #include "stateless_allocator.hpp" #include "alignment_gap_between.hpp" @@ -239,7 +240,7 @@ struct core::implementation : //! Thread-specific attribute set attribute_set m_thread_attributes; //! Random number generator for shuffling - random::taus88 m_rng; + log::aux::xorshift64 m_rng; thread_data() : m_rng(get_random_seed()) { @@ -247,14 +248,27 @@ struct core::implementation : private: //! Creates a seed for RNG - static uint32_t get_random_seed() + static uint64_t get_random_seed() { - uint64_t now = static_cast< uint64_t >(std::chrono::system_clock::now().time_since_epoch().count()); - uint32_t seed = static_cast< uint32_t >(now) ^ static_cast< uint32_t >(now >> 32u); + try + { + std::random_device rng; + std::uniform_int_distribution< uint64_t > distrib(1u); + return distrib(rng); + } + catch (...) + { + uint64_t seed; + do + { + seed = static_cast< uint64_t >(std::chrono::system_clock::now().time_since_epoch().count()); #if !defined(BOOST_LOG_NO_THREADS) - seed += static_cast< uint32_t >(log::aux::this_thread::get_id().native_id()); + seed += static_cast< uint64_t >(log::aux::this_thread::get_id().native_id()) * UINT64_C(0x2545F4914F6CDD1D); #endif - return seed; + } + while (seed == 0u); + return seed; + } } }; diff --git a/src/xorshift.hpp b/src/xorshift.hpp new file mode 100644 index 0000000000..851d4dc52f --- /dev/null +++ b/src/xorshift.hpp @@ -0,0 +1,65 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file xorshift.hpp + * \author Andrey Semashev + * \date 14.06.2025 + * + * \brief This header is the Boost.Log library implementation, see the library documentation + * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. + * + * This file implements xorshift64 random number generator. See https://en.wikipedia.org/wiki/Xorshift. + */ + +#ifndef BOOST_LOG_XORSHIFT_HPP_INCLUDED_ +#define BOOST_LOG_XORSHIFT_HPP_INCLUDED_ + +#include +#include +#include + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace aux { + +//! Xorshift64 random number generator (https://en.wikipedia.org/wiki/Xorshift) +class xorshift64 +{ +public: + using result_type = uint64_t; + +private: + uint64_t m_state; + +public: + explicit constexpr xorshift64(uint64_t seed) noexcept : + m_state(seed) + { + } + + result_type operator()() noexcept + { + uint64_t state = m_state; + state ^= state << 13u; + state ^= state >> 7u; + state ^= state << 17u; + m_state = state; + return state; + } +}; + +} // namespace aux + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_XORSHIFT_HPP_INCLUDED_ From 6db171e3484aed88a89fab168d227e39365117f5 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 19 Jun 2025 02:29:02 +0300 Subject: [PATCH 291/309] Specify relative path to log-platform-config in config checks. This allows to use the config checks from locations other than the library project. --- config/message-compiler/Jamfile.jam | 2 +- config/native-syslog/Jamfile.jam | 2 +- config/pthread-mutex-robust/Jamfile.jam | 2 +- config/regex-header-only/Jamfile.jam | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/config/message-compiler/Jamfile.jam b/config/message-compiler/Jamfile.jam index a42b801ecf..5eea0a8bab 100644 --- a/config/message-compiler/Jamfile.jam +++ b/config/message-compiler/Jamfile.jam @@ -6,7 +6,7 @@ # import project ; -import log-platform-config ; +import ../../build/log-platform-config ; using mc ; project diff --git a/config/native-syslog/Jamfile.jam b/config/native-syslog/Jamfile.jam index 3c89154045..fd4e29714d 100644 --- a/config/native-syslog/Jamfile.jam +++ b/config/native-syslog/Jamfile.jam @@ -6,7 +6,7 @@ # import project ; -import log-platform-config ; +import ../../build/log-platform-config ; project : source-location . diff --git a/config/pthread-mutex-robust/Jamfile.jam b/config/pthread-mutex-robust/Jamfile.jam index 49cd199353..18c7f2de52 100644 --- a/config/pthread-mutex-robust/Jamfile.jam +++ b/config/pthread-mutex-robust/Jamfile.jam @@ -6,7 +6,7 @@ # import project ; -import log-platform-config ; +import ../../build/log-platform-config ; project : source-location . diff --git a/config/regex-header-only/Jamfile.jam b/config/regex-header-only/Jamfile.jam index 4b718bcf9d..78e78a2020 100644 --- a/config/regex-header-only/Jamfile.jam +++ b/config/regex-header-only/Jamfile.jam @@ -6,7 +6,7 @@ # import project ; -import log-platform-config ; +import ../../build/log-platform-config ; project : source-location . From 805f0cf971bd6bf1af005b06e5e4c47eb3e1e1a5 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 19 Jun 2025 02:42:42 +0300 Subject: [PATCH 292/309] Change searched-lib to lib in the Jamfile. Apparently, searched-lib was not supposed to be used in libraries, and the simple lib target is the preferred way to declare external libraries. https://github.com/bfgroup/b2/issues/431#issuecomment-2985057673 --- build/Jamfile.v2 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index 9d6be4ffbe..dbaa83a018 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -23,18 +23,18 @@ import predef ; using mc ; # Windows libs -searched-lib psapi ; -searched-lib advapi32 ; -searched-lib secur32 ; -searched-lib ws2_32 ; -searched-lib mswsock ; +lib psapi ; +lib advapi32 ; +lib secur32 ; +lib ws2_32 ; +lib mswsock ; explicit psapi advapi32 secur32 ws2_32 mswsock ; # UNIX libs -searched-lib rt ; -searched-lib socket ; -searched-lib nsl ; -searched-lib ipv6 ; +lib rt ; +lib socket ; +lib nsl ; +lib ipv6 ; explicit rt socket nsl ipv6 ; constant boost_log_public_deps : From ef6aec2abb4d5a6596e4d49a8caa4a3f5735068f Mon Sep 17 00:00:00 2001 From: Christopher Kohlhoff Date: Tue, 8 Jul 2025 22:25:19 +1000 Subject: [PATCH 293/309] Use new minimal boost_asio_core dependency. Re-enable Boost.Asio in 32-bit MinGW-w64 job in AppVeyor. --- CMakeLists.txt | 4 ++-- appveyor.yml | 3 --- build/log-build-config.jam | 2 +- doc/log.qbk | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 89336c078c..a6518f10f5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -527,7 +527,7 @@ endif() if (NOT BOOST_LOG_WITHOUT_ASIO) target_link_libraries(boost_log PRIVATE - Boost::asio + Boost::asio_core ) endif() @@ -654,7 +654,7 @@ if (NOT BOOST_LOG_WITHOUT_SETTINGS_PARSERS) if (NOT BOOST_LOG_WITHOUT_ASIO) target_link_libraries(boost_log_setup PRIVATE - Boost::asio + Boost::asio_core ) endif() diff --git a/appveyor.yml b/appveyor.yml index 0fb7c17d44..7336195277 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -72,9 +72,6 @@ environment: ADDRESS_MODEL: 32 CXXSTD: 11,14 ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin - # Boost.Context, on which Boost.ASIO depends, does not build on this target, which prevents Boost.Log from building. - # https://github.com/chriskohlhoff/asio/issues/1637 - B2_ARGS: define=BOOST_LOG_WITHOUT_ASIO=1 APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019 - TOOLSET: clang-win ADDRESS_MODEL: 32 diff --git a/build/log-build-config.jam b/build/log-build-config.jam index dd0a17b56e..a87c11b112 100644 --- a/build/log-build-config.jam +++ b/build/log-build-config.jam @@ -131,7 +131,7 @@ rule check-asio ( properties * ) if ! [ has-config-flag BOOST_LOG_WITHOUT_ASIO : $(properties) ] { - result = /boost/asio//boost_asio ; + result = /boost/asio//boost_asio_core ; } return $(result) ; diff --git a/doc/log.qbk b/doc/log.qbk index 325dd0ab66..0907060a49 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -45,7 +45,7 @@ [def __boost_scope_exit__ [@https://www.boost.org/doc/libs/release/libs/scope_exit/doc/html/index.html Boost.ScopeExit]] [def __boost_any__ [@https://www.boost.org/doc/libs/release/doc/html/any.html Boost.Any]] [def __boost_property_tree__ [@https://www.boost.org/doc/libs/release/doc/html/property_tree.html Boost.PropertyTree]] -[def __boost_asio__ [@https://www.boost.org/doc/libs/release/doc/html/boost_asio.html Boost.ASIO]] +[def __boost_asio__ [@https://www.boost.org/doc/libs/release/doc/html/boost_asio.html Boost.Asio]] [def __boost_move__ [@https://www.boost.org/doc/libs/release/doc/html/move.html Boost.Move]] [def __boost_locale__ [@https://www.boost.org/doc/libs/release/libs/locale/doc/html/index.html Boost.Locale]] [def __boost_type_index__ [@https://www.boost.org/doc/libs/release/doc/html/boost_typeindex.html Boost.TypeIndex]] From 86c8cdccedb18ad3b0216047991b75c75353f2c9 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 9 Jul 2025 02:59:16 +0300 Subject: [PATCH 294/309] Added a wrap_filter utility. The wrap_filter helper can be used to inject user-defined filter functions into Boost.Log filtering expressions. Added implementation, tests, docs and examples. Refs https://github.com/boostorg/log/issues/195. --- doc/changelog.qbk | 1 + doc/expressions.qbk | 38 ++++++- doc/log.qbk | 2 + .../doc/expressions_filter_adapt_function.cpp | 103 ++++++++++++++++++ example/doc/expressions_wrap_filter.cpp | 98 +++++++++++++++++ include/boost/log/expressions/predicates.hpp | 2 + .../expressions/predicates/wrap_filter.hpp | 62 +++++++++++ test/run/filt_wrap_filter.cpp | 91 ++++++++++++++++ 8 files changed, 396 insertions(+), 1 deletion(-) create mode 100644 example/doc/expressions_filter_adapt_function.cpp create mode 100644 example/doc/expressions_wrap_filter.cpp create mode 100644 include/boost/log/expressions/predicates/wrap_filter.hpp create mode 100644 test/run/filt_wrap_filter.cpp diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 06136a8829..965ec3ae4e 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -13,6 +13,7 @@ * Added support for `BOOST_LOG_WITHOUT_ASIO` configuration macro, which can be used to remove the dependency on __boost_asio__ and disable the related functionality. * Use locale-independent formatting of the file counter in `text_file_backend` when composing log file names. This fixes failures in the subsequent parsing of the file names in `file_collector::scan_for_files`. ([pull_request 246]) +* Added a new [link log.detailed.expressions.predicates.wrap_filter `wrap_filter`] utility that simplifies injecting user-defined function objects in filtering expressions. ([github_issue 195]) [heading 2.31, Boost 1.88] diff --git a/doc/expressions.qbk b/doc/expressions.qbk index bbc0c3bdb6..eed37a2c48 100644 --- a/doc/expressions.qbk +++ b/doc/expressions.qbk @@ -1,5 +1,5 @@ [/ - Copyright Andrey Semashev 2007 - 2022. + Copyright Andrey Semashev 2007 - 2025. Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -262,6 +262,42 @@ This filter is implemented for Windows only. The `is_debugger_present` filter re [endsect] +[section:wrap_filter Injecting user-defined functions in filtering expressions] + + #include <``[boost_log_expressions_predicates_wrap_filter_hpp]``> + +Users may want to combine their custom filtering function objects with the filters provided by Boost.Log. In order to be able to integrate the user-defined function into a filtering expression, the function must be adapted as a __boost_phoenix__ function object. One way to do this is to use one of the [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html macros] provided by __boost_phoenix__ to create a lazy function for the user's filtering function. For example: + +[example_expressions_filter_adapt_function] + +[@boost:/libs/log/example/doc/expressions_filter_adapt_function.cpp See the complete code]. + +Here, using the `BOOST_PHOENIX_ADAPT_FUNCTION` macro we created a `lazy::my_filter` factory function that, when called, creates a function object that is compatible with __boost_phoenix__ template expressions. This created function object becomes part of the filtering expression and, when invoked during log record filtering, will forward the call to the wrapped `my_filter` function defined by the user. The `_1` placeholder in the filtering expression designates the set of attribute values that will be forwarded to the `my_filter` function. The function must return `true` to indicate that the log record passed the filter and `false` otherwise. + +[tip It is also possible to use [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/bind.html `boost::phoenix::bind`] instead of the `BOOST_PHOENIX_ADAPT_*` macros. `boost::phoenix::bind` also creates a function object that can integrate with __boost_phoenix__ expressions: + +``` +logging::add_console_log +( + std::clog, + keywords::filter = + severity >= critical || boost::phoenix::bind(&my_filter, boost::phoenix::placeholders::_1), + keywords::format = + expr::stream << "<" << severity << "> [" << channel << "] " << expr::smessage +); +``` +] + +However, Boost.Log provides a dedicated [funcref boost::log::expressions::wrap_filter `wrap_filter`] utility that removes the need to create a factory function or specify argument placeholders. The function wraps user-defined function object and enables it to participate in filtering expressions. The above example can be simplified as follows: + +[example_expressions_wrap_filter] + +[@boost:/libs/log/example/doc/expressions_wrap_filter.cpp See the complete code]. + +Note that `wrap_filter` allows for wrapping arbitrary function objects, including C++11 lambda functions, as long as the wrapped function object is callable with a single argument of type `attribute_value_set` and returns a value convertible to `bool`. + +[endsect] + [endsect] [section:formatters Formatting expressions] diff --git a/doc/log.qbk b/doc/log.qbk index 0907060a49..3ee7ec1815 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -87,6 +87,8 @@ [import ../example/doc/expressions_keyword_fmt_tag.cpp] [import ../example/doc/expressions_has_attr_stat_accum.cpp] [import ../example/doc/expressions_channel_severity_filter.cpp] +[import ../example/doc/expressions_filter_adapt_function.cpp] +[import ../example/doc/expressions_wrap_filter.cpp] [import ../example/doc/sources_net_connection.cpp] [import ../example/doc/sources_net_connection_chan.cpp] [import ../example/doc/sources_net_connection_dynamic_chan.cpp] diff --git a/example/doc/expressions_filter_adapt_function.cpp b/example/doc/expressions_filter_adapt_function.cpp new file mode 100644 index 0000000000..1e325660d8 --- /dev/null +++ b/example/doc/expressions_filter_adapt_function.cpp @@ -0,0 +1,103 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace logging = boost::log; +namespace src = boost::log::sources; +namespace expr = boost::log::expressions; +namespace keywords = boost::log::keywords; + +enum severity_level +{ + normal, + notification, + warning, + error, + critical +}; + +std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + static const char* strings[] = + { + "normal", + "notification", + "warning", + "error", + "critical" + }; + + if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) + strm << strings[level]; + else + strm << static_cast< int >(level); + + return strm; +} + +//[ example_expressions_filter_adapt_function +// Define the attribute keywords +BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) +BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) + +// User-defined filter function +bool my_filter(logging::attribute_value_set const& values) +{ + // Filter implementation. Returns true if the log record passed the filter and false otherwise. + return values[channel] == "network"; +} + +namespace lazy { +BOOST_PHOENIX_ADAPT_FUNCTION(bool, my_filter, ::my_filter, 1) +} + +void init() +{ + logging::add_console_log + ( + std::clog, + keywords::filter = + severity >= critical || lazy::my_filter(boost::phoenix::placeholders::_1), + keywords::format = + expr::stream << "<" << severity << "> [" << channel << "] " << expr::smessage + ); +} +//] + +// Define our logger type +typedef src::severity_channel_logger< severity_level, std::string > logger_type; + +void test_logging(logger_type& lg, std::string const& channel_name) +{ + BOOST_LOG_CHANNEL_SEV(lg, channel_name, normal) << "A normal severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, notification) << "A notification severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, warning) << "A warning severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, error) << "An error severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, critical) << "A critical severity level message"; +} + +int main(int, char*[]) +{ + init(); + logging::add_common_attributes(); + + logger_type lg; + test_logging(lg, "general"); + test_logging(lg, "network"); + test_logging(lg, "gui"); + test_logging(lg, "filesystem"); + + return 0; +} diff --git a/example/doc/expressions_wrap_filter.cpp b/example/doc/expressions_wrap_filter.cpp new file mode 100644 index 0000000000..323a10b887 --- /dev/null +++ b/example/doc/expressions_wrap_filter.cpp @@ -0,0 +1,98 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +#include +#include + +namespace logging = boost::log; +namespace src = boost::log::sources; +namespace expr = boost::log::expressions; +namespace keywords = boost::log::keywords; + +enum severity_level +{ + normal, + notification, + warning, + error, + critical +}; + +std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + static const char* strings[] = + { + "normal", + "notification", + "warning", + "error", + "critical" + }; + + if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) + strm << strings[level]; + else + strm << static_cast< int >(level); + + return strm; +} + +//[ example_expressions_wrap_filter +// Define the attribute keywords +BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) +BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) + +// User-defined filter function +bool my_filter(logging::attribute_value_set const& values) +{ + // Filter implementation. Returns true if the log record passed the filter and false otherwise. + return values[channel] == "network"; +} + +void init() +{ + logging::add_console_log + ( + std::clog, + keywords::filter = + severity >= critical || expr::wrap_filter(&my_filter), + keywords::format = + expr::stream << "<" << severity << "> [" << channel << "] " << expr::smessage + ); +} +//] + +// Define our logger type +typedef src::severity_channel_logger< severity_level, std::string > logger_type; + +void test_logging(logger_type& lg, std::string const& channel_name) +{ + BOOST_LOG_CHANNEL_SEV(lg, channel_name, normal) << "A normal severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, notification) << "A notification severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, warning) << "A warning severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, error) << "An error severity level message"; + BOOST_LOG_CHANNEL_SEV(lg, channel_name, critical) << "A critical severity level message"; +} + +int main(int, char*[]) +{ + init(); + logging::add_common_attributes(); + + logger_type lg; + test_logging(lg, "general"); + test_logging(lg, "network"); + test_logging(lg, "gui"); + test_logging(lg, "filesystem"); + + return 0; +} diff --git a/include/boost/log/expressions/predicates.hpp b/include/boost/log/expressions/predicates.hpp index f218a27629..8901d34fd4 100644 --- a/include/boost/log/expressions/predicates.hpp +++ b/include/boost/log/expressions/predicates.hpp @@ -24,6 +24,8 @@ #include #include +#include + #include #include diff --git a/include/boost/log/expressions/predicates/wrap_filter.hpp b/include/boost/log/expressions/predicates/wrap_filter.hpp new file mode 100644 index 0000000000..14afb64791 --- /dev/null +++ b/include/boost/log/expressions/predicates/wrap_filter.hpp @@ -0,0 +1,62 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file predicates/wrap_filter.hpp + * \author Andrey Semashev + * \date 09.07.2025 + * + * The header contains a filter function wrapper that enables third-party functions to participate in filtering expressions. + */ + +#ifndef BOOST_LOG_EXPRESSIONS_PREDICATES_WRAP_FILTER_HPP_INCLUDED_ +#define BOOST_LOG_EXPRESSIONS_PREDICATES_WRAP_FILTER_HPP_INCLUDED_ + +#include +#include +#include +#include +#include + +#ifdef BOOST_HAS_PRAGMA_ONCE +#pragma once +#endif + +namespace boost { + +BOOST_LOG_OPEN_NAMESPACE + +namespace expressions { + +/*! + * The function wraps a function object in order it to be able to participate in filtering expressions. The wrapped function must be + * compatible with the following signature: + * + *
+ * bool (attribute_value_set const& values) const
+ * 
+ * + * The wrapped function must return \c true if the log record is to be passed by the filter and \c false otherwise. + */ +template< typename FunT > +BOOST_FORCEINLINE phoenix::actor< + aux::unary_function_terminal< typename std::remove_cv< typename std::remove_reference< FunT >::type >::type > +> wrap_filter(FunT&& fun) +{ + typedef aux::unary_function_terminal< typename std::remove_cv< typename std::remove_reference< FunT >::type >::type > terminal_type; + phoenix::actor< terminal_type > act = {{ terminal_type(static_cast< FunT&& >(fun)) }}; + return act; +} + +} // namespace expressions + +BOOST_LOG_CLOSE_NAMESPACE // namespace log + +} // namespace boost + +#include + +#endif // BOOST_LOG_EXPRESSIONS_PREDICATES_WRAP_FILTER_HPP_INCLUDED_ diff --git a/test/run/filt_wrap_filter.cpp b/test/run/filt_wrap_filter.cpp new file mode 100644 index 0000000000..bd5d5cbd9f --- /dev/null +++ b/test/run/filt_wrap_filter.cpp @@ -0,0 +1,91 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file filt_wrap_filter.cpp + * \author Andrey Semashev + * \date 09.07.2025 + * + * \brief This header contains tests for the \c wrap_filter adapter. + */ + +#define BOOST_TEST_MODULE filt_wrap_filter + +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" + +namespace logging = boost::log; +namespace attrs = logging::attributes; +namespace expr = logging::expressions; + +// The test checks that the wrap_filter adapter works +BOOST_AUTO_TEST_CASE(wrap_filter_check) +{ + typedef logging::attribute_set attr_set; + typedef logging::attribute_value_set attr_values; + typedef logging::filter filter; + typedef test_data< char > data; + + attrs::constant< int > attr1(10); + attrs::constant< double > attr2(5.5); + attrs::constant< std::string > attr3("Hello, world!"); + + attr_set set1, set2, set3; + attr_values values1(set1, set2, set3); + values1.freeze(); + set1[data::attr2()] = attr2; + attr_values values2(set1, set2, set3); + values2.freeze(); + set1[data::attr3()] = attr3; + set1[data::attr1()] = attr1; + attr_values values3(set1, set2, set3); + values3.freeze(); + + int call_count1 = 0, call_count2 = 0; + filter f = expr::wrap_filter([&](attr_values const& values) { ++call_count1; return values.find(data::attr1()) != values.end(); }) || + expr::wrap_filter([&](attr_values const& values) { ++call_count2; return values.find(data::attr2()) != values.end(); }); + BOOST_CHECK(!f(values1)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 1); + + call_count1 = 0; + call_count2 = 0; + BOOST_CHECK(f(values2)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 1); + + call_count1 = 0; + call_count2 = 0; + BOOST_CHECK(f(values3)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 0); + + f = expr::wrap_filter([&](attr_values const& values) { ++call_count1; return values.find(data::attr1()) != values.end(); }) && + expr::wrap_filter([&](attr_values const& values) { ++call_count2; return values.find(data::attr2()) != values.end(); }); + + call_count1 = 0; + call_count2 = 0; + BOOST_CHECK(!f(values1)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 0); + + call_count1 = 0; + call_count2 = 0; + BOOST_CHECK(!f(values2)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 0); + + call_count1 = 0; + call_count2 = 0; + BOOST_CHECK(f(values3)); + BOOST_CHECK(call_count1 == 1); + BOOST_CHECK(call_count2 == 1); +} From ad2eb6c4e54ebefb667fac25672bdd723fe55f37 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 11 Jul 2025 03:13:49 +0300 Subject: [PATCH 295/309] Added docs, examples and test for wrap_formatter. --- doc/expressions.qbk | 48 +++++++- doc/log.qbk | 6 + .../expressions_formatter_adapt_function.cpp | 104 ++++++++++++++++ example/doc/expressions_wrap_formatter.cpp | 116 ++++++++++++++++++ .../expressions/formatters/wrap_formatter.hpp | 4 +- test/run/form_wrap_formatter.cpp | 93 ++++++++++++++ 6 files changed, 367 insertions(+), 4 deletions(-) create mode 100644 example/doc/expressions_formatter_adapt_function.cpp create mode 100644 example/doc/expressions_wrap_formatter.cpp create mode 100644 test/run/form_wrap_formatter.cpp diff --git a/doc/expressions.qbk b/doc/expressions.qbk index eed37a2c48..73db59582b 100644 --- a/doc/expressions.qbk +++ b/doc/expressions.qbk @@ -266,7 +266,7 @@ This filter is implemented for Windows only. The `is_debugger_present` filter re #include <``[boost_log_expressions_predicates_wrap_filter_hpp]``> -Users may want to combine their custom filtering function objects with the filters provided by Boost.Log. In order to be able to integrate the user-defined function into a filtering expression, the function must be adapted as a __boost_phoenix__ function object. One way to do this is to use one of the [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html macros] provided by __boost_phoenix__ to create a lazy function for the user's filtering function. For example: +Users may want to combine their custom filtering function objects with the filters provided by Boost.Log. In order to be able to integrate the user-defined function into a filtering expression, the function must be adapted as a __boost_phoenix__ function object. One way to do this is to use one of the __boost_phoenix_adapt__ macros provided by __boost_phoenix__ to create a lazy function for the user's filtering function. For example: [example_expressions_filter_adapt_function] @@ -274,7 +274,7 @@ Users may want to combine their custom filtering function objects with the filte Here, using the `BOOST_PHOENIX_ADAPT_FUNCTION` macro we created a `lazy::my_filter` factory function that, when called, creates a function object that is compatible with __boost_phoenix__ template expressions. This created function object becomes part of the filtering expression and, when invoked during log record filtering, will forward the call to the wrapped `my_filter` function defined by the user. The `_1` placeholder in the filtering expression designates the set of attribute values that will be forwarded to the `my_filter` function. The function must return `true` to indicate that the log record passed the filter and `false` otherwise. -[tip It is also possible to use [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/bind.html `boost::phoenix::bind`] instead of the `BOOST_PHOENIX_ADAPT_*` macros. `boost::phoenix::bind` also creates a function object that can integrate with __boost_phoenix__ expressions: +[tip It is also possible to use __boost_phoenix_bind__ instead of the `BOOST_PHOENIX_ADAPT_*` macros. `boost::phoenix::bind` also creates a function object that can integrate with __boost_phoenix__ expressions: ``` logging::add_console_log @@ -707,6 +707,50 @@ The above formatter can produce output like this: [endsect] +[section:wrap_formatter Injecting user-defined functions in formatting expressions] + + #include <``[boost_log_expressions_formatters_wrap_formatter_hpp]``> + +Given that formatting expressions are __boost_phoenix__ expressions, it is possible to inject user-defined functions into the formatter by using __boost_phoenix__ facilities, such as __boost_phoenix_adapt__ macros or __boost_phoenix_bind__. + +[example_expressions_formatter_adapt_function] + +[@boost:/libs/log/example/doc/expressions_formatter_adapt_function.cpp See the complete code]. + +Here, using the `BOOST_PHOENIX_ADAPT_FUNCTION` macro we created a `lazy::extract_channel` factory function that, when called, creates a function object that is compatible with __boost_phoenix__ template expressions. This function object, when called as part of the formatter, forwards the call to our `extract_channel` function to do the actual work. + +Remember that formatters have the following signature: + + void (logging::``[class_log_record_view]`` const& rec, logging::``[class_log_basic_formatting_ostream]``< CharT >& stream) const + +Here, `rec` is a log [link log.detailed.core.record record view] that contains all captured attribute values and `stream` is the output stream that receives the formatted output. In order to pass the log record to the `extract_channel` function we use the `_1` placeholder to identify the first argument of the formatter. + +The `extract_channel` function accepts a log record view and returns the object that will be output into the stream as part of the formatting expression. In our case, the returned string is simply the value of the "Channel" attribute from the log record, if one is present, or a replacement string if it is missing. If needed, the output stream will perform character encoding conversion as it receives the string returned by `extract_channel`. + +[tip In order to use `boost::phoenix::bind` instead of the `BOOST_PHOENIX_ADAPT_*` macros one could write the formatting expression as follows: + +``` +logging::add_console_log +( + std::clog, + keywords::format = + expr::stream << "<" << severity << "> [" + << boost::phoenix::bind(&extract_channel, boost::phoenix::placeholders::_1) + << "] " << expr::smessage +); +``` +] + +The protocol of returning an object to output in the formatting stream, while simple and expressive, may be too limiting or inefficient when a more elaborate formatting logic is required. To address these advanced use cases, Boost.Log provides a [funcref boost::log::expressions::wrap_formatter `wrap_formatter`] utility that wraps a user-defined formatter function and invokes it as part of the formatting process. The user-defined formatter can be any callable that supports the signature defined above, and as such doesn't need to return anything and can use the provided stream directly for output. + +[example_expressions_wrap_formatter] + +[@boost:/libs/log/example/doc/expressions_wrap_formatter.cpp See the complete code]. + +In this example, the application uses a "Host" attribute with values of a custom `host_address` type to identify network hosts to which the application connects. The application may emit log records that are related or unrelated to a given host, as indicated by the presence of the "Host" attribute. We define our `format_host` function to implement the entire formatting logic for host addresses and then use the `wrap_formatter` utility to inject it into the formatting expression. Note that despite that the syntax of the formatting expression suggests that the value returned by `wrap_formatter` is output into the formatting stream, this is not actually the case. + +[endsect] + [endsect] [endsect] diff --git a/doc/log.qbk b/doc/log.qbk index 3ee7ec1815..86788dbbec 100644 --- a/doc/log.qbk +++ b/doc/log.qbk @@ -52,6 +52,10 @@ [def __boost_utility__ [@https://www.boost.org/doc/libs/release/libs/utility/doc/html/index.html Boost.Utility]] [def __boost_quickbook__ [@https://www.boost.org/doc/libs/release/doc/html/quickbook.html Boost.Quickbook]] +[def __boost_phoenix_adapt__ [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/function/adapting_functions.html `BOOST_PHOENIX_ADAPT_*`]] +[def __boost_phoenix_bind__ [@https://www.boost.org/doc/libs/release/libs/phoenix/doc/html/phoenix/modules/bind.html `boost::phoenix::bind`]] + + [template ticket[key]'''#'''[key]''''''] [template github_issue[key]'''GH#'''[key]''''''] [template pull_request[key]'''PR#'''[key]''''''] @@ -89,6 +93,8 @@ [import ../example/doc/expressions_channel_severity_filter.cpp] [import ../example/doc/expressions_filter_adapt_function.cpp] [import ../example/doc/expressions_wrap_filter.cpp] +[import ../example/doc/expressions_formatter_adapt_function.cpp] +[import ../example/doc/expressions_wrap_formatter.cpp] [import ../example/doc/sources_net_connection.cpp] [import ../example/doc/sources_net_connection_chan.cpp] [import ../example/doc/sources_net_connection_dynamic_chan.cpp] diff --git a/example/doc/expressions_formatter_adapt_function.cpp b/example/doc/expressions_formatter_adapt_function.cpp new file mode 100644 index 0000000000..4eb928a556 --- /dev/null +++ b/example/doc/expressions_formatter_adapt_function.cpp @@ -0,0 +1,104 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace logging = boost::log; +namespace src = boost::log::sources; +namespace expr = boost::log::expressions; +namespace keywords = boost::log::keywords; + +enum severity_level +{ + normal, + notification, + warning, + error, + critical +}; + +std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + static const char* strings[] = + { + "normal", + "notification", + "warning", + "error", + "critical" + }; + + if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) + strm << strings[level]; + else + strm << static_cast< int >(level); + + return strm; +} + +//[ example_expressions_formatter_adapt_function +// Define the attribute keywords +BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) +BOOST_LOG_ATTRIBUTE_KEYWORD(channel, "Channel", std::string) + +// User-defined formatting function +std::string extract_channel(logging::record_view const& rec) +{ + logging::value_ref< std::string, tag::channel > chan = rec[channel]; + if (chan) + return chan.get(); + else + return "-"; +} + +namespace lazy { +BOOST_PHOENIX_ADAPT_FUNCTION(std::string, extract_channel, ::extract_channel, 1) +} + +void init() +{ + logging::add_console_log + ( + std::clog, + keywords::format = + expr::stream << "<" << severity << "> [" + << lazy::extract_channel(boost::phoenix::placeholders::_1) + << "] " << expr::smessage + ); +} +//] + +int main(int, char*[]) +{ + init(); + logging::add_common_attributes(); + + src::severity_channel_logger< severity_level, std::string > lg1; + BOOST_LOG_CHANNEL_SEV(lg1, "general", normal) << "A normal severity level message"; + BOOST_LOG_CHANNEL_SEV(lg1, "general", notification) << "A notification severity level message"; + BOOST_LOG_CHANNEL_SEV(lg1, "general", warning) << "A warning severity level message"; + BOOST_LOG_CHANNEL_SEV(lg1, "general", error) << "An error severity level message"; + BOOST_LOG_CHANNEL_SEV(lg1, "general", critical) << "A critical severity level message"; + + src::severity_logger< severity_level > lg2; + BOOST_LOG_SEV(lg2, normal) << "A normal severity level message"; + BOOST_LOG_SEV(lg2, notification) << "A notification severity level message"; + BOOST_LOG_SEV(lg2, warning) << "A warning severity level message"; + BOOST_LOG_SEV(lg2, error) << "An error severity level message"; + BOOST_LOG_SEV(lg2, critical) << "A critical severity level message"; + + return 0; +} diff --git a/example/doc/expressions_wrap_formatter.cpp b/example/doc/expressions_wrap_formatter.cpp new file mode 100644 index 0000000000..138b7ad708 --- /dev/null +++ b/example/doc/expressions_wrap_formatter.cpp @@ -0,0 +1,116 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace logging = boost::log; +namespace attrs = boost::log::attributes; +namespace src = boost::log::sources; +namespace expr = boost::log::expressions; +namespace keywords = boost::log::keywords; + +enum severity_level +{ + normal, + notification, + warning, + error, + critical +}; + +std::ostream& operator<< (std::ostream& strm, severity_level level) +{ + static const char* strings[] = + { + "normal", + "notification", + "warning", + "error", + "critical" + }; + + if (static_cast< std::size_t >(level) < sizeof(strings) / sizeof(*strings)) + strm << strings[level]; + else + strm << static_cast< int >(level); + + return strm; +} + +//[ example_expressions_wrap_formatter +// Define a custom attribute value type +struct host_address +{ + std::string hostname; + std::uint_least16_t port = 0; +}; + +// Define the attribute keywords +BOOST_LOG_ATTRIBUTE_KEYWORD(severity, "Severity", severity_level) +BOOST_LOG_ATTRIBUTE_KEYWORD(host, "Host", host_address) + +// User-defined formatter for the Host attribute values +void format_host(logging::record_view const& rec, logging::formatting_ostream& stream) +{ + // Formatter implementation outputs directly into the formatting stream + logging::value_ref< host_address, tag::host > host_ref = rec[host]; + if (host_ref) + { + stream << host_ref->hostname; + + if (host_ref->port != 0) + stream << ":" << host_ref->port; + } + else + { + stream << "-"; + } +} + +void init() +{ + logging::add_console_log + ( + std::clog, + keywords::format = + expr::stream << "<" << severity << "> [" + << expr::wrap_formatter< char >(&format_host) + << "] " << expr::smessage + ); +} +//] + +int main(int, char*[]) +{ + init(); + logging::add_common_attributes(); + + src::severity_logger< severity_level > lg1; + + host_address h; + h.hostname = "hostname"; + h.port = 1234; + lg1.add_attribute(host.get_name(), attrs::make_constant(h)); + + BOOST_LOG_SEV(lg1, normal) << "Connection established"; + BOOST_LOG_SEV(lg1, normal) << "Connection closed"; + + src::severity_logger< severity_level > lg2; + BOOST_LOG_SEV(lg2, normal) << "Message not associated with a host"; + + return 0; +} diff --git a/include/boost/log/expressions/formatters/wrap_formatter.hpp b/include/boost/log/expressions/formatters/wrap_formatter.hpp index 29c19c2f80..69be0bae08 100644 --- a/include/boost/log/expressions/formatters/wrap_formatter.hpp +++ b/include/boost/log/expressions/formatters/wrap_formatter.hpp @@ -274,7 +274,7 @@ class wrapped_formatter_actor : * function object must be compatible with the following signature: * *
- * void (record_view const&, basic_formatting_ostream< CharT >&)
+ * void (record_view const&, basic_formatting_ostream< CharT >&) const
  * 
* * where \c CharT is the character type of the formatting expression. @@ -293,7 +293,7 @@ BOOST_FORCEINLINE wrapped_formatter_actor< FunT, typename aux::default_char_type * function object must be compatible with the following signature: * *
- * void (record_view const&, basic_formatting_ostream< CharT >&)
+ * void (record_view const&, basic_formatting_ostream< CharT >&) const
  * 
* * where \c CharT is the character type of the formatting expression. diff --git a/test/run/form_wrap_formatter.cpp b/test/run/form_wrap_formatter.cpp new file mode 100644 index 0000000000..627d7f6d06 --- /dev/null +++ b/test/run/form_wrap_formatter.cpp @@ -0,0 +1,93 @@ +/* + * Copyright Andrey Semashev 2025. + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + */ +/*! + * \file form_wrap_formatter.cpp + * \author Andrey Semashev + * \date 11.07.2025 + * + * \brief This header contains tests for the \c wrap_formatter utility. + */ + +#define BOOST_TEST_MODULE form_wrap_formatter + +#include +#include +#include +#include +#include +#include +#include +#include +#include "char_definitions.hpp" +#include "make_record.hpp" + +namespace logging = boost::log; +namespace attrs = logging::attributes; +namespace expr = logging::expressions; + +namespace { + + class my_class + { + int m_Data; + + public: + explicit my_class(int data) : m_Data(data) {} + + int get_data() const { return m_Data; } + }; + + template< typename StreamT > + inline void format_my_class(StreamT& strm, my_class const& obj) + { + strm << "[data: " << obj.get_data() << "]"; + } + +} // namespace + +// The test checks that wrap_formatter works +BOOST_AUTO_TEST_CASE_TEMPLATE(wrap_formatter_check, CharT, char_types) +{ + typedef logging::record_view record_view; + typedef logging::attribute_set attr_set; + typedef std::basic_string< CharT > string; + typedef logging::basic_formatting_ostream< CharT > osstream; + typedef logging::basic_formatter< CharT > formatter; + typedef test_data< CharT > data; + + attrs::constant< int > attr1(10); + attrs::constant< double > attr2(5.5); + attrs::constant< my_class > attr3(my_class(77)); + + attr_set set1; + set1[data::attr1()] = attr1; + set1[data::attr2()] = attr2; + set1[data::attr3()] = attr3; + + record_view rec = make_record_view(set1); + + // Check for various modes of attribute value type specification + { + string str1, str2; + osstream strm1(str1), strm2(str2); + int call_count = 0; + formatter f = + expr::stream << expr::attr< int >(data::attr1()) + << expr::attr< double >(data::attr2()) + << expr::wrap_formatter< CharT >([&](record_view const& rec, osstream& strm) + { + ++call_count; + logging::value_ref< my_class > val = rec[data::attr3()].template extract< my_class >(); + if (val) + format_my_class(strm, val.get()); + }); + f(rec, strm1); + strm2 << 10 << 5.5; + format_my_class(strm2, my_class(77)); + BOOST_CHECK(equal_strings(strm1.str(), strm2.str())); + } +} From f16f8026e8feeefc220cfb36f8d005b7b564762b Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Mon, 25 Aug 2025 17:26:30 +0200 Subject: [PATCH 296/309] Update Link to regression test matrix in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6fc4659ee9..122207e10a 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,8 @@ Boost.Log, part of collection of the [Boost C++ Libraries](https://github.com/bo Branch | GitHub Actions | AppVeyor | Test Matrix | Dependencies | :-------------: | -------------- | -------- | ----------- | ------------ | -[`master`](https://github.com/boostorg/log/tree/master) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/log/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](http://www.boost.org/development/tests/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) -[`develop`](https://github.com/boostorg/log/tree/develop) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/log/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](http://www.boost.org/development/tests/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) +[`master`](https://github.com/boostorg/log/tree/master) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=master)](https://github.com/boostorg/log/actions?query=branch%3Amaster) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/master?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/master) | [![Tests](https://img.shields.io/badge/matrix-master-brightgreen.svg)](https://regression.boost.io/master/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-master-brightgreen.svg)](https://pdimov.github.io/boostdep-report/master/log.html) +[`develop`](https://github.com/boostorg/log/tree/develop) | [![GitHub Actions](https://github.com/boostorg/log/actions/workflows/ci.yml/badge.svg?branch=develop)](https://github.com/boostorg/log/actions?query=branch%3Adevelop) | [![AppVeyor](https://ci.appveyor.com/api/projects/status/w7x67cnm82xihei5/branch/develop?svg=true)](https://ci.appveyor.com/project/Lastique/log/branch/develop) | [![Tests](https://img.shields.io/badge/matrix-develop-brightgreen.svg)](https://regression.boost.io/develop/developer/log.html) | [![Dependencies](https://img.shields.io/badge/deps-develop-brightgreen.svg)](https://pdimov.github.io/boostdep-report/develop/log.html) ### License From 4f081ca212ba2381f5ca94b567fbf1ef9d29b9a1 Mon Sep 17 00:00:00 2001 From: Alexander Grund Date: Wed, 1 Oct 2025 10:18:16 +0200 Subject: [PATCH 297/309] Fix required CMake version --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a6518f10f5..0720213705 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ # Distributed under the Boost Software License, Version 1.0. # See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt -cmake_minimum_required(VERSION 3.5...3.16) +cmake_minimum_required(VERSION 3.8...3.16) project(BoostLog VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX) include(CheckCXXSourceCompiles) From b1fd6a2423f49e8c315a19c75eba4361e2b46391 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 Oct 2025 01:17:20 +0300 Subject: [PATCH 298/309] Fix incorrect constant used for PP iteration limit in value_ref visitation. This fixes generation of apply_visitor_dispatch template specializations that are supposed to terminate the lookup recursion and optimize for a small number of (last) lookup steps. The bug was reported on the ML: https://lists.boost.org/archives/list/boost@lists.boost.org/message/PN6TVYAFH2ICX5ENT76ARTQ7V372G5F2/ --- doc/changelog.qbk | 4 ++++ include/boost/log/detail/value_ref_visitation.hpp | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 965ec3ae4e..51704d761d 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.33, Boost 1.90] + +* Fixed a missed optimization in `value_ref` visitation. + [heading 2.32, Boost 1.89] * Added support for `BOOST_LOG_WITHOUT_ASIO` configuration macro, which can be used to remove the dependency on __boost_asio__ and disable the related functionality. diff --git a/include/boost/log/detail/value_ref_visitation.hpp b/include/boost/log/detail/value_ref_visitation.hpp index 8ac598913a..ed86ea1870 100644 --- a/include/boost/log/detail/value_ref_visitation.hpp +++ b/include/boost/log/detail/value_ref_visitation.hpp @@ -67,7 +67,7 @@ struct apply_visitor_dispatch case i: return visitor(*static_cast< typename mpl::at_c< SequenceT, i >::type const* >(p)); #define BOOST_PP_FILENAME_1 -#define BOOST_PP_ITERATION_LIMITS (1, BOOST_PP_INC(BOOST_LOG_VALUE_REF_VISITATION_VTABLE_SIZE)) +#define BOOST_PP_ITERATION_LIMITS (1, BOOST_PP_INC(BOOST_LOG_VALUE_REF_VISITATION_UNROLL_COUNT)) #include BOOST_PP_ITERATE() #undef BOOST_LOG_AUX_CASE_ENTRY From dfe99bee621f668836e6c28037fb915a4867cba3 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 25 Oct 2025 01:48:10 +0300 Subject: [PATCH 299/309] Added a sanity check for value_ref over an empty type list. --- include/boost/log/utility/value_ref.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/boost/log/utility/value_ref.hpp b/include/boost/log/utility/value_ref.hpp index 855ca7364e..c4255acc0d 100644 --- a/include/boost/log/utility/value_ref.hpp +++ b/include/boost/log/utility/value_ref.hpp @@ -255,6 +255,7 @@ class variant_ref public: //! Referenced value type typedef T value_type; + static_assert(mpl::size< value_type >::value > 0, "Boost.Log: List of types referenced by value_ref must not be empty"); //! Tag type typedef TagT tag_type; From 826df254f019b77b87550a251fc44b590925e1b0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 6 Nov 2025 00:59:55 +0300 Subject: [PATCH 300/309] Fixed a long loop on file rotation if filename pattern did not include counter. If the log file is configured for appending and rotation_size limit is set, text_file_backend::consume would repeatedly attempt to reopen the log file with a new counter value in attempt to find a file with a size below the rotation_size limit. This logic breaks if the file name pattern does not include a file counter placeholder, as it means the backend would repeatedly attempt to open the same file, whose size would exceed the limit. The loop would terminate after 2^32 iterations, but that may take a while. Avoid this fallback if we know the file counter placeholder is missing in the file name pattern. Also, make fil size checks more robust against integer overflows. Fixes https://github.com/boostorg/log/issues/252. --- doc/changelog.qbk | 2 ++ src/text_file_backend.cpp | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/doc/changelog.qbk b/doc/changelog.qbk index 51704d761d..f8f379dc45 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -12,6 +12,8 @@ [heading 2.33, Boost 1.90] * Fixed a missed optimization in `value_ref` visitation. +* Fixed a possible long and useless loop on log file rotation in [link log.detailed.sink_backends.text_file `text_file_backend`], if the log file name pattern did not include a file counter and the log file size exceeded the `rotation_size` limit. The sink backend would repeatedly try to open a new log file with a different counter value and end up opening the same file every time. ([github_issue 252]) +* Made file size checks more robust against integer overflows in [link log.detailed.sink_backends.text_file `text_file_backend`]. [heading 2.32, Boost 1.89] diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index 924f3cd6f2..bb234e8719 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -1460,7 +1460,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ ( m_pImpl->m_File.is_open() && ( - m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize || + (m_pImpl->m_CharactersWritten > m_pImpl->m_FileRotationSize || (m_pImpl->m_FileRotationSize - m_pImpl->m_CharactersWritten) < formatted_message.size()) || (!m_pImpl->m_TimeBasedRotation.empty() && m_pImpl->m_TimeBasedRotation()) ) ) @@ -1468,8 +1468,7 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ rotate_file(); } - const unsigned int last_file_counter = m_pImpl->m_FileCounter - 1u; - while (!m_pImpl->m_File.is_open()) + for (const unsigned int last_file_counter = m_pImpl->m_FileCounter - 1u; !m_pImpl->m_File.is_open();) { filesystem::path new_file_name; if (!use_prev_file_name) @@ -1528,10 +1527,11 @@ BOOST_LOG_API void text_file_backend::consume(record_view const& rec, string_typ m_pImpl->m_IsFirstFile = false; // Check the file size before invoking the open handler, as it may write more data to the file. - // Only do this check if we haven't exhausted the file counter to avoid looping indefinitely. + // Only do this check if the file counter is present in the file name and we haven't exhausted it to avoid looping indefinitely. m_pImpl->m_CharactersWritten = static_cast< std::streamoff >(m_pImpl->m_File.tellp()); - if (m_pImpl->m_CharactersWritten > 0 && m_pImpl->m_CharactersWritten + formatted_message.size() >= m_pImpl->m_FileRotationSize && - m_pImpl->m_FileCounter != last_file_counter) + if (m_pImpl->m_CharactersWritten > 0 && + (m_pImpl->m_CharactersWritten > m_pImpl->m_FileRotationSize || (m_pImpl->m_FileRotationSize - m_pImpl->m_CharactersWritten) < formatted_message.size()) && + m_pImpl->m_FileNamePatternHasCounter && m_pImpl->m_FileCounter != last_file_counter) { // Avoid running the close handler, as we haven't run the open handler yet struct close_handler_backup_guard From ce82e7f8f2f438888e0d3d71ebb2299d80bdc142 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 6 Nov 2025 04:45:55 +0300 Subject: [PATCH 301/309] Removed clang 3.5 and 3.6 from GitHub Actions CI. Boost.SmartPtr now requires a fully functional , and these compilers fail to compile it. --- .github/workflows/ci.yml | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bdc7350a41..7b60e1c9bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -108,20 +108,6 @@ jobs: - g++-13 # Linux, clang - - toolset: clang - compiler: clang++-3.5 - cxxstd: "11" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - clang-3.5 - - toolset: clang - compiler: clang++-3.6 - cxxstd: "11,14" - os: ubuntu-latest - container: ubuntu:16.04 - install: - - clang-3.6 - toolset: clang compiler: clang++-3.7 cxxstd: "11,14" From 014f344715461cdf056eb184eb3362d8692c6bdd Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Thu, 6 Nov 2025 05:03:50 +0300 Subject: [PATCH 302/309] Removed C++17 mode job for clang-5.0 from GitHub Actions. Boost.Mp11 no longer supports C++17 mode with clang-5.0 and causes compile errors in Boost.MultiIndex and Boost.PropertyTree. Refs https://github.com/boostorg/mp11/issues/111. --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7b60e1c9bd..9303f17270 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -138,7 +138,7 @@ jobs: - clang-4.0 - toolset: clang compiler: clang++-5.0 - cxxstd: "11,14,1z" + cxxstd: "11,14" os: ubuntu-latest container: ubuntu:18.04 install: From fa2af18239410bead9f7bb352b68dc4ec04051fb Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Sat, 13 Dec 2025 20:43:36 +0300 Subject: [PATCH 303/309] Replaced macos-13 with macos-15 in GitHub Actions. The macos-13 image is retired, macos-15 is now available. --- .github/workflows/ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9303f17270..dc8b8cc5ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -282,12 +282,12 @@ jobs: - libc++-18-dev - libc++abi-18-dev - - toolset: clang - cxxstd: "11,14,17,20,2b" - os: macos-13 - toolset: clang cxxstd: "11,14,17,20,2b" os: macos-14 + - toolset: clang + cxxstd: "11,14,17,20,23" + os: macos-15 - name: CMake tests cmake_tests: 1 From 3ea24c81f230cf7dd6e7ea97fad7b143e8fb4296 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Mon, 24 Nov 2025 18:54:16 +0300 Subject: [PATCH 304/309] Enable building IPC components on Cygwin. Reportedly, Boost.Interprocess has been fixed on Cygwin, so we can enable building IPC components by default on this target. Refs https://github.com/boostorg/interprocess/issues/242. --- CMakeLists.txt | 2 -- build/Jamfile.v2 | 2 -- doc/changelog.qbk | 4 ++++ 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0720213705..66735fe06d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -310,8 +310,6 @@ else() endif() if (CYGWIN) - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/242 - set(BOOST_LOG_WITHOUT_IPC ON) list(APPEND boost_log_common_private_defines __USE_W32_SOCKETS _XOPEN_SOURCE=600 diff --git a/build/Jamfile.v2 b/build/Jamfile.v2 index dbaa83a018..2d0e5c2237 100644 --- a/build/Jamfile.v2 +++ b/build/Jamfile.v2 @@ -179,8 +179,6 @@ project windows:advapi32 cygwin:BOOST_USE_WINDOWS_H - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/242 - cygwin:BOOST_LOG_WITHOUT_IPC cygwin:ws2_32 cygwin:mswsock cygwin:advapi32 diff --git a/doc/changelog.qbk b/doc/changelog.qbk index f8f379dc45..c6158b42c3 100644 --- a/doc/changelog.qbk +++ b/doc/changelog.qbk @@ -9,6 +9,10 @@ [section:changelog Changelog] +[heading 2.34, Boost 1.91] + +* Enabled building interprocess communication support on Cygwin by default. + [heading 2.33, Boost 1.90] * Fixed a missed optimization in `value_ref` visitation. From d70b528bc5cf0684c4fff341af1cc745e3bae340 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Wed, 17 Dec 2025 04:16:11 +0300 Subject: [PATCH 305/309] Fixed typos in comments. --- src/dump_avx2.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dump_avx2.cpp b/src/dump_avx2.cpp index a6745046db..5b3a44045f 100644 --- a/src/dump_avx2.cpp +++ b/src/dump_avx2.cpp @@ -227,7 +227,7 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b store_characters_x3(mm_output1, mm_output2, mm_output3, buf); - _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call + _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compiler generates around the function call strm.write(buf_begin, prealign_size * 3u - 1u); buf_begin = buf; @@ -251,7 +251,7 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b store_characters_x3(mm_output1, mm_output2, mm_output3, b); } - _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call + _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compiler generates around the function call strm.write(buf_begin, buf_end - buf_begin); buf_begin = buf; } @@ -276,7 +276,7 @@ BOOST_FORCEINLINE void dump_data_avx2(const void* data, std::size_t size, std::b tail_size -= 16u; } - _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compler generates around the function call + _mm256_zeroall(); // need to zero all ymm registers to avoid register spills/restores the compiler generates around the function call for (unsigned int i = 0; i < tail_size; ++i, ++p, b += 3u) { uint32_t n = *p; From 2fc825acfeabf42cf30443e08ea0d9d420c0a7e7 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 26 Dec 2025 16:00:53 +0300 Subject: [PATCH 306/309] Use new Boost.Filesystem platform API macros. --- src/text_file_backend.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/text_file_backend.cpp b/src/text_file_backend.cpp index bb234e8719..61519740a6 100644 --- a/src/text_file_backend.cpp +++ b/src/text_file_backend.cpp @@ -78,7 +78,7 @@ BOOST_LOG_ANONYMOUS_NAMESPACE { //! A possible Boost.Filesystem extension - renames or moves the file to the target storage inline void move_file(filesystem::path const& from, filesystem::path const& to) { -#if defined(BOOST_WINDOWS_API) +#if defined(BOOST_FILESYSTEM_WINDOWS_API) // On Windows MoveFile already does what we need filesystem::rename(from, to); #else From 3efa06b889525ea55d8218cd5e83c701922f06a0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 26 Dec 2025 17:22:43 +0300 Subject: [PATCH 307/309] Removed disablement of IPC utilities on Cygwin in tests and examples. --- example/doc/Jamfile.v2 | 3 --- test/Jamfile.v2 | 3 --- 2 files changed, 6 deletions(-) diff --git a/example/doc/Jamfile.v2 b/example/doc/Jamfile.v2 index c84959ef1d..c1786d9b12 100644 --- a/example/doc/Jamfile.v2 +++ b/example/doc/Jamfile.v2 @@ -81,9 +81,6 @@ project intel-linux:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" intel-darwin:"-wd177,780,2196,1782,193,304,981,1418,411,734,279" - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 - cygwin:BOOST_LOG_WITHOUT_IPC - /boost/log//boost_log /boost/log//boost_log_setup /boost/date_time//boost_date_time diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index a685dff195..f71f3af3a2 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -48,9 +48,6 @@ project gcc:-fno-strict-aliasing # avoids strict aliasing violations in other Boost components - # Boost.Interprocess does not compile on Cygwin: https://github.com/boostorg/interprocess/issues/76 - cygwin:BOOST_LOG_WITHOUT_IPC - /boost/log//boost_log /boost/log//boost_log_setup /boost/filesystem//boost_filesystem From f461ca6fe6166dbf9a62d52d73caff87767393c8 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Fri, 26 Dec 2025 17:35:03 +0300 Subject: [PATCH 308/309] Removed redundant checks for __CYGWIN__ that are excluded by BOOST_WINDOWS. --- include/boost/log/detail/timestamp.hpp | 6 +++--- src/timestamp.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/boost/log/detail/timestamp.hpp b/include/boost/log/detail/timestamp.hpp index da7e0b8073..91d6e560a2 100644 --- a/include/boost/log/detail/timestamp.hpp +++ b/include/boost/log/detail/timestamp.hpp @@ -18,7 +18,7 @@ #include #include -#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) #include #endif #include @@ -43,7 +43,7 @@ class duration public: explicit duration(int64_t ticks = 0) BOOST_NOEXCEPT : m_ticks(ticks) {} -#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) int64_t milliseconds() const { return m_ticks; } #else BOOST_LOG_API int64_t milliseconds() const; @@ -74,7 +74,7 @@ class timestamp * be affected by clock changes, either manual or seasonal. Also, it * should be as fast as possible. */ -#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) typedef uint64_t (BOOST_WINAPI_WINAPI_CC* get_tick_count_t)(); extern BOOST_LOG_API get_tick_count_t get_tick_count; diff --git a/src/timestamp.cpp b/src/timestamp.cpp index 05e5e50c73..3bdfac5bab 100644 --- a/src/timestamp.cpp +++ b/src/timestamp.cpp @@ -16,7 +16,7 @@ #include #include -#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) #include #include #include @@ -47,7 +47,7 @@ BOOST_LOG_OPEN_NAMESPACE namespace aux { -#if defined(BOOST_WINDOWS) && !defined(__CYGWIN__) +#if defined(BOOST_WINDOWS) #if BOOST_USE_WINAPI_VERSION >= BOOST_WINAPI_VERSION_WIN6 From f0d196ee03609d8cea8448bc4ad5889d52d9e4a0 Mon Sep 17 00:00:00 2001 From: Andrey Semashev Date: Tue, 30 Dec 2025 11:23:54 +0300 Subject: [PATCH 309/309] Avoid signed/unsigned mismatch warning when time_t is 32-bit (e.g. on Cygwin32). --- src/posix/ipc_reliable_message_queue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/posix/ipc_reliable_message_queue.cpp b/src/posix/ipc_reliable_message_queue.cpp index 696e6d3e6c..3a80289fb0 100644 --- a/src/posix/ipc_reliable_message_queue.cpp +++ b/src/posix/ipc_reliable_message_queue.cpp @@ -325,7 +325,7 @@ struct reliable_message_queue::implementation } std::time_t now = std::time(NULL); - if (BOOST_UNLIKELY((now - start_time) >= region_open_or_create_timeout)) + if (BOOST_UNLIKELY((now - start_time) >= static_cast< std::time_t >(region_open_or_create_timeout))) BOOST_LOG_THROW_DESCR(setup_error, "Boost.Log interprocess message queue cannot be created or opened: shared memory segment failed to be created or opened until timeout (possible livelock)"); if (i < region_open_or_create_short_yield_loops)