Compare commits

..

1 Commits

Author SHA1 Message Date
Sergiu Deitsch
e4ef97e07a wip 2023-12-20 07:45:04 +01:00
106 changed files with 6530 additions and 7133 deletions

View File

@ -1,8 +1,8 @@
--- ---
tasks: tasks:
ubuntu1804: ubuntu1804:
name: "Ubuntu 22.04" name: "Ubuntu 18.04"
platform: ubuntu2204 platform: ubuntu1804
build_flags: build_flags:
- "--features=layering_check" - "--features=layering_check"
- "--copt=-Werror" - "--copt=-Werror"

View File

@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4 ContinuationIndentWidth: 4
Cpp11BracedListStyle: true Cpp11BracedListStyle: true
DeriveLineEnding: true DeriveLineEnding: true
DerivePointerAlignment: false DerivePointerAlignment: true
DisableFormat: false DisableFormat: false
ExperimentalAutoDetectBinPacking: false ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true FixNamespaceComments: true
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: '' IncludeIsMainSourceRegex: ''
IndentCaseLabels: true IndentCaseLabels: true
IndentGotoLabels: true IndentGotoLabels: true
IndentPPDirectives: AfterHash IndentPPDirectives: None
IndentWidth: 2 IndentWidth: 2
IndentWrappedFunctionNames: false IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave JavaScriptQuotes: Leave

View File

@ -2,6 +2,7 @@
Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*' Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*'
WarningsAsErrors: '' WarningsAsErrors: ''
HeaderFilterRegex: '' HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: file FormatStyle: file
CheckOptions: CheckOptions:
- key: cert-dcl16-c.NewSuffixes - key: cert-dcl16-c.NewSuffixes

View File

@ -5,7 +5,7 @@ on: [push, pull_request]
jobs: jobs:
build-android: build-android:
name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}} name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04-8core
permissions: permissions:
actions: read actions: read
contents: read contents: read

View File

@ -8,7 +8,7 @@ jobs:
run: run:
shell: bash shell: bash
name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}} name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04-8core
permissions: permissions:
actions: read actions: read
contents: read contents: read
@ -40,11 +40,18 @@ jobs:
env: env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}} CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}
run: | run: |
emcmake cmake -S . -B build_${{matrix.build_type}} \ cmake -S . -B build_${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \ -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
-DCMAKE_AR=$(which emar) \
-DCMAKE_CXX_COMPILER=$(which em++) \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \ -DCMAKE_CXX_STANDARD=${{matrix.std}} \
-DCMAKE_CXX_STANDARD_REQUIRED=ON \ -DCMAKE_CXX_STANDARD_REQUIRED=ON \
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \ -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
-DCMAKE_RANLIB=$(which emranlib) \
-G Ninja \ -G Ninja \
-Werror -Werror

View File

@ -8,7 +8,7 @@ jobs:
run: run:
shell: bash shell: bash
name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}} name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04-8core
permissions: permissions:
actions: read actions: read
contents: read contents: read
@ -31,20 +31,42 @@ jobs:
- name: Setup Dependencies - name: Setup Dependencies
run: | run: |
sudo apt-get update sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-suggests --no-install-recommends \ DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
g++ \ build-essential \
cmake \ cmake \
gcovr \ gcovr \
libgflags-dev \ libgflags-dev \
libgmock-dev \
libgtest-dev \
libunwind-dev \ libunwind-dev \
ninja-build ninja-build
- name: Cache GTest
id: cache-gtest
uses: actions/cache@v3
with:
path: gtest/
key: ${{runner.os}}-gtest-1.11
- name: Download GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
wget https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz
tar xvf release-1.11.0.tar.gz
- name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
cmake -S googletest-release-1.11.0 -B build-googletest \
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest \
-G Ninja
cmake --build build-googletest --target install
- name: Setup Environment - name: Setup Environment
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
echo 'GTest_ROOT=${{github.workspace}}/gtest' >> $GITHUB_ENV
- name: Configure - name: Configure
env: env:
@ -106,10 +128,17 @@ jobs:
run: | run: |
cd build_${{matrix.build_type}} cd build_${{matrix.build_type}}
gcovr -r .. . -s --xml coverage.xml gcovr -r .. . -s --xml coverage.xml
cd ..
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
done
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml files: build_${{matrix.build_type}}/coverage.xml

View File

@ -63,12 +63,18 @@ jobs:
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
cd build_${{matrix.build_type}} cd build_${{matrix.build_type}}
rm -r Tests/
gcovr -r .. . -s --cobertura coverage.xml gcovr -r .. . -s --cobertura coverage.xml
cd ..
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "" "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
done
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml files: build_${{matrix.build_type}}/coverage.xml

View File

@ -42,21 +42,21 @@ jobs:
- name: Cache GTest - name: Cache GTest
id: cache-gtest id: cache-gtest
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: gtest/ path: gtest/
key: ${{runner.os}}-gtest-1.14-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}} key: ${{runner.os}}-gtest-1.11-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
- name: Download GTest - name: Download GTest
if: steps.cache-gtest.outputs.cache-hit != 'true' if: steps.cache-gtest.outputs.cache-hit != 'true'
run: | run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip", "v1.14.0.zip") (New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip", "release-1.11.0.zip")
Expand-Archive v1.14.0.zip . Expand-Archive release-1.11.0.zip .
- name: Build GTest - name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true' if: steps.cache-gtest.outputs.cache-hit != 'true'
run: | run: |
cmake -S googletest-1.14.0 -B build-googletest ` cmake -S googletest-release-1.11.0 -B build-googletest `
-A ${{matrix.arch}} ` -A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} ` -DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-Dgtest_force_shared_crt=ON ` -Dgtest_force_shared_crt=ON `
@ -67,7 +67,7 @@ jobs:
- name: Cache gflags - name: Cache gflags
id: cache-gflags id: cache-gflags
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: gflags/ path: gflags/
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}} key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
@ -188,7 +188,7 @@ jobs:
- name: Setup Coverage Dependencies - name: Setup Coverage Dependencies
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
run: | run: |
pip install 'gcovr==7.0' pip install 'gcovr==6.0'
- name: Setup Environment - name: Setup Environment
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
@ -231,10 +231,17 @@ jobs:
run: | run: |
cd build_${{matrix.build_type}} cd build_${{matrix.build_type}}
gcovr -r .. . -s --cobertura coverage.xml gcovr -r .. . -s --cobertura coverage.xml
cd ..
for file in src/glog/*.h.in; do
name=$(basename ${file})
name_we=${name%.h.in}
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
done
- name: Upload Coverage to Codecov - name: Upload Coverage to Codecov
if: matrix.build_type == 'Debug' if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5 uses: codecov/codecov-action@v3
with: with:
token: ${{ secrets.CODECOV_TOKEN }} token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml files: build_${{matrix.build_type}}/coverage.xml

3
.gitignore vendored
View File

@ -1,6 +1,3 @@
*.orig *.orig
/build*/ /build*/
/site/
bazel-* bazel-*
# Bzlmod lockfile
/MODULE.bazel.lock

View File

@ -17,6 +17,6 @@ platform(
constraint_values = [ constraint_values = [
"@platforms//cpu:x86_64", "@platforms//cpu:x86_64",
"@platforms//os:windows", "@platforms//os:windows",
"@rules_cc//cc/private/toolchain:clang-cl", "@bazel_tools//tools/cpp:clang-cl",
], ],
) )

View File

@ -1,6 +1,6 @@
cmake_minimum_required (VERSION 3.22) cmake_minimum_required (VERSION 3.21)
project (glog project (glog
VERSION 0.8.0 VERSION 0.7.0
DESCRIPTION "C++ implementation of the Google logging module" DESCRIPTION "C++ implementation of the Google logging module"
HOMEPAGE_URL https://github.com/google/glog HOMEPAGE_URL https://github.com/google/glog
LANGUAGES CXX LANGUAGES CXX
@ -8,17 +8,20 @@ project (glog
set (CPACK_PACKAGE_NAME glog) set (CPACK_PACKAGE_NAME glog)
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library") set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library")
set (CPACK_PACKAGE_VERSION_MAJOR ${glog_VERSION_MAJOR}) set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
set (CPACK_PACKAGE_VERSION_MINOR ${glog_VERSION_MINOR}) set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
set (CPACK_PACKAGE_VERSION_PATCH ${glog_VERSION_PATCH}) set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
set (CPACK_PACKAGE_VERSION ${glog_VERSION}) set (CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
list (APPEND CMAKE_MODULE_PATH ${glog_SOURCE_DIR}/cmake) list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include (CheckCXXCompilerFlag)
include (CheckCXXSourceCompiles) include (CheckCXXSourceCompiles)
include (CheckCXXSourceRuns) include (CheckCXXSourceRuns)
include (CheckCXXSymbolExists) include (CheckCXXSymbolExists)
include (CheckFunctionExists)
include (CheckIncludeFileCXX) include (CheckIncludeFileCXX)
include (CheckLibraryExists)
include (CheckStructHasMember) include (CheckStructHasMember)
include (CheckTypeSize) include (CheckTypeSize)
include (CMakeDependentOption) include (CMakeDependentOption)
@ -32,39 +35,42 @@ include (GetCacheVariables)
include (GNUInstallDirs) include (GNUInstallDirs)
option (BUILD_SHARED_LIBS "Build shared libraries" ON) option (BUILD_SHARED_LIBS "Build shared libraries" ON)
option (BUILD_EXAMPLES "Build examples" ON)
option (PRINT_UNSYMBOLIZED_STACK_TRACES option (PRINT_UNSYMBOLIZED_STACK_TRACES
"Print file offsets in traces instead of symbolizing" OFF) "Print file offsets in traces instead of symbolizing" OFF)
option (WITH_GFLAGS "Use gflags" ON) option (WITH_GFLAGS "Use gflags" ON)
option (WITH_GTEST "Use Google Test" ON) option (WITH_GTEST "Use Google Test" ON)
option (WITH_PKGCONFIG "Enable pkg-config support" OFF) option (WITH_PKGCONFIG "Enable pkg-config support" ON)
option (WITH_SYMBOLIZE "Enable symbolize module" ON) option (WITH_SYMBOLIZE "Enable symbolize module" ON)
option (WITH_THREADS "Enable multithreading support" ON)
option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON) option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON)
option (WITH_UNWIND "Enable libunwind support" ON)
set (WITH_UNWIND libunwind CACHE STRING "unwind driver")
set_property (CACHE WITH_UNWIND PROPERTY STRINGS none unwind libunwind)
cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF) cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF)
set (WITH_FUZZING none CACHE STRING "Fuzzing engine") set (WITH_FUZZING none CACHE STRING "Fuzzing engine")
set_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz) set_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz)
if (WITH_UNWIND STREQUAL none) if (NOT WITH_UNWIND)
set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON) set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON)
endif (WITH_UNWIND STREQUAL none) endif (NOT WITH_UNWIND)
if (NOT WITH_GTEST) if (NOT WITH_GTEST)
set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON) set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)
endif (NOT WITH_GTEST) endif (NOT WITH_GTEST)
if (NOT WITH_THREADS)
set (CMAKE_DISABLE_FIND_PACKAGE_Threads ON)
endif (NOT WITH_THREADS)
set (CMAKE_C_VISIBILITY_PRESET hidden) set (CMAKE_C_VISIBILITY_PRESET hidden)
set (CMAKE_CXX_VISIBILITY_PRESET hidden) set (CMAKE_CXX_VISIBILITY_PRESET hidden)
set (CMAKE_POSITION_INDEPENDENT_CODE ON) set (CMAKE_POSITION_INDEPENDENT_CODE ON)
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON) set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
set (CMAKE_DEBUG_POSTFIX d) set (CMAKE_DEBUG_POSTFIX d)
set (CMAKE_THREAD_PREFER_PTHREAD 1)
find_package (GTest 1.11 COMPONENTS GTest OPTIONAL_COMPONENTS GMock NO_MODULE) find_package (GTest NO_MODULE)
if (GTest_FOUND) if (GTest_FOUND)
set (HAVE_LIB_GTEST 1) set (HAVE_LIB_GTEST 1)
@ -83,54 +89,25 @@ if (WITH_GFLAGS)
endif (gflags_FOUND) endif (gflags_FOUND)
endif (WITH_GFLAGS) endif (WITH_GFLAGS)
find_package (Threads REQUIRED) find_package (Threads)
find_package (Unwind) find_package (Unwind)
if (Unwind_FOUND) if (Unwind_FOUND)
cmake_push_check_state (RESET) set (HAVE_LIB_UNWIND 1)
set (CMAKE_REQUIRED_LIBRARIES unwind::unwind) else (Unwind_FOUND)
# Check whether linking actually succeeds. ARM toolchains of LLVM unwind # Check whether linking actually succeeds. ARM toolchains of LLVM unwind
# implementation do not necessarily provide the _Unwind_Backtrace function # implementation do not necessarily provide the _Unwind_Backtrace function
# which causes the previous check to succeed but the linking to fail. # which causes the previous check to succeed but the linking to fail.
check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE) check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE)
check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP) check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP)
check_cxx_symbol_exists (unw_get_reg libunwind.h HAVE_UNW_GET_REG)
check_cxx_symbol_exists (unw_getcontext libunwind.h HAVE_UNW_GETCONTEXT)
check_cxx_symbol_exists (unw_init_local libunwind.h HAVE_UNW_INIT_LOCAL)
check_cxx_symbol_exists (unw_step libunwind.h HAVE_UNW_STEP)
if (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)
set (_HAVE_UNWIND 1)
endif (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)
if (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)
set (_HAVE_LIBUNWIND 1)
endif (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)
if (WITH_UNWIND STREQUAL unwind)
if (_HAVE_UNWIND)
set (HAVE_UNWIND 1)
endif (_HAVE_UNWIND)
elseif (WITH_UNWIND STREQUAL libunwind)
if (_HAVE_LIBUNWIND)
set (HAVE_LIBUNWIND 1)
endif (_HAVE_LIBUNWIND)
endif (WITH_UNWIND STREQUAL unwind)
unset (_HAVE_LIBUNWIND)
unset (_HAVE_UNWIND)
cmake_pop_check_state ()
endif (Unwind_FOUND) endif (Unwind_FOUND)
check_include_file_cxx (dlfcn.h HAVE_DLFCN_H) check_include_file_cxx (dlfcn.h HAVE_DLFCN_H)
check_include_file_cxx (elf.h HAVE_ELF_H)
check_include_file_cxx (glob.h HAVE_GLOB_H) check_include_file_cxx (glob.h HAVE_GLOB_H)
check_include_file_cxx (link.h HAVE_LINK_H) check_include_file_cxx (memory.h HAVE_MEMORY_H)
check_include_file_cxx (pwd.h HAVE_PWD_H) check_include_file_cxx (pwd.h HAVE_PWD_H)
check_include_file_cxx (sys/exec_elf.h HAVE_SYS_EXEC_ELF_H) check_include_file_cxx (strings.h HAVE_STRINGS_H)
check_include_file_cxx (sys/stat.h HAVE_SYS_STAT_H)
check_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H) check_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H)
check_include_file_cxx (sys/time.h HAVE_SYS_TIME_H) check_include_file_cxx (sys/time.h HAVE_SYS_TIME_H)
check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H) check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)
@ -144,38 +121,93 @@ check_include_file_cxx (unistd.h HAVE_UNISTD_H)
check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX) check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)
check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX) check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)
check_cxx_symbol_exists (dladdr dlfcn.h HAVE_DLADDR) check_function_exists (dladdr HAVE_DLADDR)
check_cxx_symbol_exists (fcntl fcntl.h HAVE_FCNTL) check_function_exists (fcntl HAVE_FCNTL)
check_cxx_symbol_exists (posix_fadvise fcntl.h HAVE_POSIX_FADVISE) check_function_exists (pread HAVE_PREAD)
check_cxx_symbol_exists (pread unistd.h HAVE_PREAD) check_function_exists (pwrite HAVE_PWRITE)
check_cxx_symbol_exists (pwrite unistd.h HAVE_PWRITE) check_function_exists (sigaction HAVE_SIGACTION)
check_cxx_symbol_exists (sigaction csignal HAVE_SIGACTION) check_function_exists (sigaltstack HAVE_SIGALTSTACK)
check_cxx_symbol_exists (sigaltstack csignal HAVE_SIGALTSTACK)
check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE) check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
check_cxx_symbol_exists (backtrace_symbols execinfo.h check_cxx_symbol_exists (backtrace_symbols execinfo.h
HAVE_EXECINFO_BACKTRACE_SYMBOLS) HAVE_EXECINFO_BACKTRACE_SYMBOLS)
check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S) check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)
# NOTE gcc does not fail if you pass a non-existent -Wno-* option as an
# argument. However, it will happily fail if you pass the corresponding -W*
# option. So, we check whether options that disable warnings exist by testing
# the availability of the corresponding option that enables the warning. This
# eliminates the need to check for compiler for several (mainly Clang) options.
check_cxx_compiler_flag (-Wdeprecated HAVE_NO_DEPRECATED)
check_cxx_compiler_flag (-Wunnamed-type-template-args
HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
cmake_push_check_state (RESET) cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES dbghelp)
check_cxx_symbol_exists (UnDecorateSymbolName "windows.h;dbghelp.h" HAVE_DBGHELP) if (Threads_FOUND)
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
endif (Threads_FOUND)
check_cxx_symbol_exists (pthread_threadid_np "pthread.h" HAVE_PTHREAD_THREADID_NP)
cmake_pop_check_state () cmake_pop_check_state ()
if (WITH_FUZZING STREQUAL none) # NOTE: Cannot use check_function_exists here since >=vc-14.0 can define
# Disable compiler demangler if fuzzing is active; we only want to use the # snprintf as an inline function
# glog demangler then. check_cxx_symbol_exists (snprintf cstdio HAVE_SNPRINTF)
check_cxx_symbol_exists (abi::__cxa_demangle cxxabi.h HAVE___CXA_DEMANGLE)
endif (WITH_FUZZING STREQUAL none)
check_cxx_symbol_exists (__argv cstdlib HAVE___ARGV) check_library_exists (dbghelp UnDecorateSymbolName "" HAVE_DBGHELP)
check_cxx_symbol_exists (getprogname cstdlib HAVE_GETPROGNAME)
check_cxx_symbol_exists (program_invocation_short_name cerrno HAVE_PROGRAM_INVOCATION_SHORT_NAME) check_cxx_source_compiles ("
check_cxx_source_compiles ([=[
#include <cstdlib> #include <cstdlib>
extern char* __progname; static void foo(void) __attribute__ ((unused));
int main() { return __progname != nullptr ? EXIT_SUCCESS : EXIT_FAILURE; } int main(void) { return 0; }
]=] HAVE___PROGNAME) " HAVE___ATTRIBUTE__)
check_cxx_source_compiles ("
#include <cstdlib>
static void foo(void) __attribute__ ((visibility(\"default\")));
int main(void) { return 0; }
" HAVE___ATTRIBUTE__VISIBILITY_DEFAULT)
check_cxx_source_compiles ("
#include <cstdlib>
static void foo(void) __attribute__ ((visibility(\"hidden\")));
int main(void) { return 0; }
" HAVE___ATTRIBUTE__VISIBILITY_HIDDEN)
check_cxx_source_compiles ("
int main(void) { if (__builtin_expect(0, 0)) return 1; return 0; }
" HAVE___BUILTIN_EXPECT)
check_cxx_source_compiles ("
int main(void)
{
int a; if (__sync_val_compare_and_swap(&a, 0, 1)) return 1; return 0;
}
" HAVE___SYNC_VAL_COMPARE_AND_SWAP)
if (Threads_FOUND)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
check_cxx_source_compiles ("
#define _XOPEN_SOURCE 500
#include <pthread.h>
int main(void)
{
pthread_rwlock_t l;
pthread_rwlock_init(&l, NULL);
pthread_rwlock_rdlock(&l);
return 0;
}
" HAVE_RWLOCK)
cmake_pop_check_state ()
endif (Threads_FOUND)
check_cxx_source_compiles ("
__declspec(selectany) int a;
int main(void) { return 0; }
" HAVE___DECLSPEC)
if (WITH_TLS) if (WITH_TLS)
set (GLOG_THREAD_LOCAL_STORAGE 1) set (GLOG_THREAD_LOCAL_STORAGE 1)
@ -238,6 +270,58 @@ if (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
cmake_pop_check_state () cmake_pop_check_state ()
endif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT) endif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
set (GOOGLE_NAMESPACE google)
set (_START_GOOGLE_NAMESPACE_ "namespace ${GOOGLE_NAMESPACE} {")
set (_END_GOOGLE_NAMESPACE_ "}")
set (ac_cv_have_glog_export 1)
if (HAVE_LIB_GFLAGS)
set (ac_cv_have_libgflags 1)
else (HAVE_LIB_GFLAGS)
set (ac_cv_have_libgflags 0)
endif (HAVE_LIB_GFLAGS)
if (HAVE_SYS_TYPES_H)
set (ac_cv_have_systypes_h 1)
else (HAVE_SYS_TYPES_H)
set (ac_cv_have_systypes_h 0)
endif (HAVE_SYS_TYPES_H)
if (HAVE_SSIZE_T)
set (ac_cv_have_ssize_t 1)
else (HAVE_SSIZE_T)
set (ac_cv_have_ssize_t 0)
endif (HAVE_SSIZE_T)
if (HAVE_MODE_T)
set (ac_cv_have_mode_t 1)
else (HAVE_MODE_T)
set (ac_cv_have_mode_t 0)
endif (HAVE_MODE_T)
if (HAVE_UNISTD_H)
set (ac_cv_have_unistd_h 1)
else (HAVE_UNISTD_H)
set (ac_cv_have_unistd_h 0)
endif (HAVE_UNISTD_H)
set (ac_google_namespace ${GOOGLE_NAMESPACE})
set (ac_google_end_namespace ${_END_GOOGLE_NAMESPACE_})
set (ac_google_start_namespace ${_START_GOOGLE_NAMESPACE_})
if (HAVE___ATTRIBUTE__)
set (ac_cv___attribute___noinline "__attribute__((noinline))")
set (ac_cv___attribute___printf_4_5 "__attribute__((__format__(__printf__, 4, 5)))")
elseif (HAVE___DECLSPEC)
#set (ac_cv___attribute___noinline "__declspec(noinline)")
endif (HAVE___ATTRIBUTE__)
if (HAVE___BUILTIN_EXPECT)
set (ac_cv_have___builtin_expect 1)
else (HAVE___BUILTIN_EXPECT)
set (ac_cv_have___builtin_expect 0)
endif (HAVE___BUILTIN_EXPECT)
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS) if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
set (HAVE_STACKTRACE 1) set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS) endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
@ -278,12 +362,19 @@ if (WITH_SYMBOLIZE)
if (HAVE_SYMBOLIZE) if (HAVE_SYMBOLIZE)
set (HAVE_STACKTRACE 1) set (HAVE_STACKTRACE 1)
endif (HAVE_SYMBOLIZE) endif (HAVE_SYMBOLIZE)
elseif (UNIX)
cmake_push_check_state (RESET)
check_cxx_source_compiles ([=[
int main()
{
#ifndef __ELF__
#error __ELF__ not defined
#endif
}
]=] HAVE_SYMBOLIZE)
cmake_pop_check_state ()
elseif (APPLE AND HAVE_DLADDR) elseif (APPLE AND HAVE_DLADDR)
set (HAVE_SYMBOLIZE 1) set (HAVE_SYMBOLIZE 1)
elseif (UNIX)
if (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)
set (HAVE_SYMBOLIZE 1)
endif (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)
endif (WIN32 OR CYGWIN) endif (WIN32 OR CYGWIN)
endif (WITH_SYMBOLIZE) endif (WITH_SYMBOLIZE)
@ -291,23 +382,46 @@ endif (WITH_SYMBOLIZE)
# building the library. # building the library.
add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION) add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)
check_cxx_symbol_exists (gmtime_r "cstdlib;ctime" HAVE_GMTIME_R) check_cxx_source_compiles ("
check_cxx_symbol_exists (localtime_r "cstdlib;ctime" HAVE_LOCALTIME_R) #include <cstdlib>
#include <ctime>
int main()
{
time_t timep;
struct tm result;
localtime_r(&timep, &result);
return EXIT_SUCCESS;
}
" HAVE_LOCALTIME_R)
set (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P}) set (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
if (WITH_THREADS AND Threads_FOUND)
if (CMAKE_USE_PTHREADS_INIT)
set (HAVE_PTHREAD 1)
endif (CMAKE_USE_PTHREADS_INIT)
else (WITH_THREADS AND Threads_FOUND)
set (NO_THREADS 1)
endif (WITH_THREADS AND Threads_FOUND)
# fopen/open on Cygwin can not handle unix-type paths like /home/.... # fopen/open on Cygwin can not handle unix-type paths like /home/....
# therefore we translate TEST_SRC_DIR to windows-path. # therefore we translate TEST_SRC_DIR to windows-path.
if (CYGWIN) if (CYGWIN)
execute_process (COMMAND cygpath.exe -m ${glog_SOURCE_DIR} execute_process (COMMAND cygpath.exe -m ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
OUTPUT_VARIABLE TEST_SRC_DIR) OUTPUT_VARIABLE TEST_SRC_DIR)
set (TEST_SRC_DIR \"${TEST_SRC_DIR}\") set (TEST_SRC_DIR \"${TEST_SRC_DIR}\")
else (CYGWIN) else (CYGWIN)
set (TEST_SRC_DIR \"${glog_SOURCE_DIR}\") set (TEST_SRC_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")
endif (CYGWIN) endif (CYGWIN)
configure_file (src/config.h.cmake.in config.h) configure_file (src/config.h.cmake.in config.h)
configure_file (src/glog/logging.h.in glog/logging.h @ONLY)
configure_file (src/glog/raw_logging.h.in glog/raw_logging.h @ONLY)
configure_file (src/glog/stl_logging.h.in glog/stl_logging.h @ONLY)
configure_file (src/glog/vlog_is_on.h.in glog/vlog_is_on.h @ONLY)
add_compile_options ($<$<AND:$<BOOL:${HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS}>,$<NOT:$<CXX_COMPILER_ID:GNU>>>:-Wno-unnamed-type-template-args>)
set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR}) set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})
set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR}) set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
@ -317,14 +431,14 @@ set (_glog_CMake_INSTALLDIR ${_glog_CMake_LIBDIR}/cmake/glog)
set (_glog_CMake_DIR glog/cmake) set (_glog_CMake_DIR glog/cmake)
set (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR}) set (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR})
set (_glog_BINARY_CMake_DATADIR set (_glog_BINARY_CMake_DATADIR
${glog_BINARY_DIR}/${_glog_CMake_DATADIR}) ${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
# Add additional CMake find modules here. # Add additional CMake find modules here.
set (_glog_CMake_MODULES) set (_glog_CMake_MODULES)
if (Unwind_FOUND) if (Unwind_FOUND)
# Copy the module only if libunwind is actually used. # Copy the module only if libunwind is actually used.
list (APPEND _glog_CMake_MODULES ${glog_SOURCE_DIR}/cmake/FindUnwind.cmake) list (APPEND _glog_CMake_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindUnwind.cmake)
endif (Unwind_FOUND) endif (Unwind_FOUND)
# Generate file name for each module in the binary directory # Generate file name for each module in the binary directory
@ -348,29 +462,25 @@ if (_glog_CMake_MODULES)
endif (_glog_CMake_MODULES) endif (_glog_CMake_MODULES)
set (GLOG_PUBLIC_H set (GLOG_PUBLIC_H
${glog_BINARY_DIR}/glog/export.h ${CMAKE_CURRENT_BINARY_DIR}/glog/export.h
${CMAKE_CURRENT_BINARY_DIR}/glog/logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/raw_logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/stl_logging.h
${CMAKE_CURRENT_BINARY_DIR}/glog/vlog_is_on.h
src/glog/log_severity.h src/glog/log_severity.h
src/glog/logging.h
src/glog/platform.h src/glog/platform.h
src/glog/raw_logging.h
src/glog/stl_logging.h
src/glog/types.h
src/glog/flags.h
src/glog/vlog_is_on.h
) )
set (GLOG_SRCS set (GLOG_SRCS
${GLOG_PUBLIC_H} ${GLOG_PUBLIC_H}
src/base/commandlineflags.h src/base/commandlineflags.h
src/base/googleinit.h src/base/googleinit.h
src/base/mutex.h
src/demangle.cc src/demangle.cc
src/demangle.h src/demangle.h
src/flags.cc
src/logging.cc src/logging.cc
src/raw_logging.cc src/raw_logging.cc
src/signalhandler.cc src/signalhandler.cc
src/stacktrace.cc
src/stacktrace.h
src/symbolize.cc src/symbolize.cc
src/symbolize.h src/symbolize.h
src/utilities.cc src/utilities.cc
@ -378,14 +488,12 @@ set (GLOG_SRCS
src/vlog_is_on.cc src/vlog_is_on.cc
) )
# NOTE MSYS2 defines both WIN32 and UNIX. Do not use windows port in this case. if (CYGWIN OR WIN32)
if ((CYGWIN OR WIN32) AND NOT UNIX)
list (APPEND GLOG_SRCS list (APPEND GLOG_SRCS
src/windows/port.cc src/windows/port.cc
src/windows/port.h src/windows/port.h
) )
set (_glog_USE_WINDOWS_PORT TRUE) endif (CYGWIN OR WIN32)
endif ((CYGWIN OR WIN32) AND NOT UNIX)
add_library (glog_internal OBJECT add_library (glog_internal OBJECT
${_glog_BINARY_CMake_MODULES} ${_glog_BINARY_CMake_MODULES}
@ -413,26 +521,6 @@ add_library (glog::glog ALIAS glog)
set (glog_libraries_options_for_static_linking) set (glog_libraries_options_for_static_linking)
# CMake always uses the generated export header
target_compile_definitions (glog PUBLIC GLOG_USE_GLOG_EXPORT)
if (_glog_USE_WINDOWS_PORT)
target_compile_definitions (glog PRIVATE GLOG_USE_WINDOWS_PORT)
endif (_glog_USE_WINDOWS_PORT)
unset (_glog_USE_WINDOWS_PORT)
if (WIN32)
# Do not define min and max as macros
target_compile_definitions (glog PRIVATE NOMINMAX)
# Exclude unnecessary funcitonality
target_compile_definitions (glog PRIVATE WIN32_LEAN_AND_MEAN)
endif (WIN32)
if (HAVE_LIB_GFLAGS)
target_compile_definitions (glog PUBLIC GLOG_USE_GFLAGS)
endif (HAVE_LIB_GFLAGS)
if (Unwind_FOUND) if (Unwind_FOUND)
target_link_libraries (glog PRIVATE unwind::unwind) target_link_libraries (glog PRIVATE unwind::unwind)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind") set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind")
@ -444,11 +532,13 @@ if (HAVE_DBGHELP)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp") set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp")
endif (HAVE_DBGHELP) endif (HAVE_DBGHELP)
target_link_libraries (glog PRIVATE Threads::Threads) if (HAVE_PTHREAD)
target_link_libraries (glog PRIVATE ${CMAKE_THREAD_LIBS_INIT})
if (CMAKE_THREAD_LIBS_INIT) if (CMAKE_THREAD_LIBS_INIT)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}") set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}")
endif (CMAKE_THREAD_LIBS_INIT) endif (CMAKE_THREAD_LIBS_INIT)
endif (HAVE_PTHREAD)
if (gflags_FOUND) if (gflags_FOUND)
# Prefer the gflags target that uses double colon convention # Prefer the gflags target that uses double colon convention
@ -466,8 +556,8 @@ if (ANDROID)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -llog") set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -llog")
endif (ANDROID) endif (ANDROID)
set_target_properties (glog PROPERTIES VERSION ${glog_VERSION}) set_target_properties (glog PROPERTIES VERSION ${PROJECT_VERSION})
set_target_properties (glog PROPERTIES SOVERSION 3) set_target_properties (glog PROPERTIES SOVERSION 1)
if (CYGWIN OR WIN32) if (CYGWIN OR WIN32)
target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES) target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)
@ -476,20 +566,20 @@ endif (CYGWIN OR WIN32)
set_target_properties (glog PROPERTIES PUBLIC_HEADER "${GLOG_PUBLIC_H}") set_target_properties (glog PROPERTIES PUBLIC_HEADER "${GLOG_PUBLIC_H}")
target_include_directories (glog BEFORE PUBLIC target_include_directories (glog BEFORE PUBLIC
"$<BUILD_INTERFACE:${glog_BINARY_DIR}>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
"$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>" "$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>"
PRIVATE ${glog_BINARY_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
PRIVATE ${glog_SOURCE_DIR}/src) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
if (CYGWIN OR WIN32) if (CYGWIN OR WIN32)
target_include_directories (glog_internal PUBLIC target_include_directories (glog_internal PUBLIC
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
PRIVATE ${glog_SOURCE_DIR}/src/windows) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
target_include_directories (glog PUBLIC target_include_directories (glog PUBLIC
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>" "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
PRIVATE ${glog_SOURCE_DIR}/src/windows) PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
endif (CYGWIN OR WIN32) endif (CYGWIN OR WIN32)
set_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL) set_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)
@ -502,20 +592,20 @@ target_compile_definitions (glog_internal PUBLIC
generate_export_header (glog generate_export_header (glog
EXPORT_MACRO_NAME GLOG_EXPORT EXPORT_MACRO_NAME GLOG_EXPORT
EXPORT_FILE_NAME ${glog_BINARY_DIR}/glog/export.h) EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/glog/export.h)
string (STRIP "${glog_libraries_options_for_static_linking}" glog_libraries_options_for_static_linking) string (STRIP "${glog_libraries_options_for_static_linking}" glog_libraries_options_for_static_linking)
if (WITH_PKGCONFIG) if (WITH_PKGCONFIG)
set (VERSION ${glog_VERSION}) set (VERSION ${PROJECT_VERSION})
set (prefix ${CMAKE_INSTALL_PREFIX}) set (prefix ${CMAKE_INSTALL_PREFIX})
set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR}) set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR})
set (libdir ${CMAKE_INSTALL_FULL_LIBDIR}) set (libdir ${CMAKE_INSTALL_FULL_LIBDIR})
set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR}) set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
configure_file ( configure_file (
"${glog_SOURCE_DIR}/libglog.pc.in" "${PROJECT_SOURCE_DIR}/libglog.pc.in"
"${glog_BINARY_DIR}/libglog.pc" "${PROJECT_BINARY_DIR}/libglog.pc"
@ONLY @ONLY
) )
@ -570,6 +660,16 @@ if (BUILD_TESTING)
target_link_libraries (stl_logging_unittest PRIVATE glog_test) target_link_libraries (stl_logging_unittest PRIVATE glog_test)
if (HAVE_NO_DEPRECATED)
set_property (TARGET stl_logging_unittest APPEND PROPERTY COMPILE_OPTIONS
-Wno-deprecated)
endif (HAVE_NO_DEPRECATED)
if (HAVE_EXT_SLIST)
target_compile_definitions (stl_logging_unittest PRIVATE
GLOG_STL_LOGGING_FOR_EXT_SLIST)
endif (HAVE_EXT_SLIST)
if (HAVE_SYMBOLIZE) if (HAVE_SYMBOLIZE)
add_executable (symbolize_unittest add_executable (symbolize_unittest
src/symbolize_unittest.cc src/symbolize_unittest.cc
@ -584,13 +684,6 @@ if (BUILD_TESTING)
target_link_libraries (demangle_unittest PRIVATE glog_test) target_link_libraries (demangle_unittest PRIVATE glog_test)
add_test (NAME demangle COMMAND demangle_unittest)
if (HAVE___CXA_DEMANGLE)
# Demangle tests use a different (reduced) representation of symbols
set_tests_properties (demangle PROPERTIES DISABLED ON)
endif (HAVE___CXA_DEMANGLE)
if (HAVE_STACKTRACE) if (HAVE_STACKTRACE)
add_executable (stacktrace_unittest add_executable (stacktrace_unittest
src/stacktrace_unittest.cc src/stacktrace_unittest.cc
@ -613,6 +706,7 @@ if (BUILD_TESTING)
target_link_libraries (signalhandler_unittest PRIVATE glog_test) target_link_libraries (signalhandler_unittest PRIVATE glog_test)
endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE) endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
add_test (NAME demangle COMMAND demangle_unittest)
add_test (NAME logging COMMAND logging_unittest) add_test (NAME logging COMMAND logging_unittest)
set_tests_properties (logging PROPERTIES TIMEOUT 30) set_tests_properties (logging PROPERTIES TIMEOUT 30)
@ -665,15 +759,15 @@ if (BUILD_TESTING)
get_cache_variables (_CACHEVARS) get_cache_variables (_CACHEVARS)
set (_INITIAL_CACHE set (_INITIAL_CACHE
${glog_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake) ${CMAKE_CURRENT_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake)
# Package config test # Package config test
add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND} add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND}
-DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config -DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config
-DINITIAL_CACHE=${_INITIAL_CACHE} -DINITIAL_CACHE=${_INITIAL_CACHE}
-DCACHEVARS=${_CACHEVARS} -DCACHEVARS=${_CACHEVARS}
-P ${glog_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake
) )
add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND} add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND}
@ -681,21 +775,21 @@ if (BUILD_TESTING)
-DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} -DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET} -DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-DINITIAL_CACHE=${_INITIAL_CACHE} -DINITIAL_CACHE=${_INITIAL_CACHE}
-DPACKAGE_DIR=${glog_BINARY_DIR} -DPACKAGE_DIR=${CMAKE_CURRENT_BINARY_DIR}
-DPATH=$ENV{PATH} -DPATH=$ENV{PATH}
-DSOURCE_DIR=${glog_SOURCE_DIR}/src/package_config_unittest/working_config -DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/package_config_unittest/working_config
-DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config/working_config -DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
-P ${glog_SOURCE_DIR}/cmake/TestPackageConfig.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestPackageConfig.cmake
) )
add_test (NAME cmake_package_config_build COMMAND add_test (NAME cmake_package_config_build COMMAND
${CMAKE_COMMAND} --build ${glog_BINARY_DIR}/test_package_config/working_config ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
--config $<CONFIG> --config $<CONFIG>
) )
add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E
remove_directory remove_directory
${glog_BINARY_DIR}/test_package_config ${CMAKE_CURRENT_BINARY_DIR}/test_package_config
) )
# Fixtures setup # Fixtures setup
@ -729,7 +823,7 @@ if (BUILD_TESTING)
target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE glog_test) target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE glog_test)
set (CLEANUP_LOG_DIR ${glog_BINARY_DIR}/cleanup_tests) set (CLEANUP_LOG_DIR ${CMAKE_CURRENT_BINARY_DIR}/cleanup_tests)
add_test (NAME cleanup_init COMMAND add_test (NAME cleanup_init COMMAND
${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR}) ${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR})
@ -740,21 +834,21 @@ if (BUILD_TESTING)
-DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest> -DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest>
# NOTE The trailing slash is important # NOTE The trailing slash is important
-DTEST_DIR=${CLEANUP_LOG_DIR}/ -DTEST_DIR=${CLEANUP_LOG_DIR}/
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest1.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest1.cmake
WORKING_DIRECTORY ${glog_BINARY_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test (NAME cleanup_with_absolute_prefix COMMAND add_test (NAME cleanup_with_absolute_prefix COMMAND
${CMAKE_COMMAND} ${CMAKE_COMMAND}
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest> -DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest>
-DTEST_DIR=${glog_BINARY_DIR}/ -DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest2.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest2.cmake
WORKING_DIRECTORY ${glog_BINARY_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
add_test (NAME cleanup_with_relative_prefix COMMAND add_test (NAME cleanup_with_relative_prefix COMMAND
${CMAKE_COMMAND} ${CMAKE_COMMAND}
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest> -DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest>
-DTEST_DIR=${glog_BINARY_DIR}/ -DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
-DTEST_SUBDIR=test_subdir/ -DTEST_SUBDIR=test_subdir/
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest3.cmake -P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest3.cmake
WORKING_DIRECTORY ${glog_BINARY_DIR}) WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
# Fixtures setup # Fixtures setup
set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest) set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest)
@ -764,208 +858,8 @@ if (BUILD_TESTING)
set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest) set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest)
set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest) set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest) set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
add_executable (striplog0_unittest
src/striplog_unittest.cc
)
target_compile_definitions (striplog0_unittest PRIVATE GOOGLE_STRIP_LOG=0)
target_link_libraries (striplog0_unittest PRIVATE glog_test)
add_test (NAME striplog0 COMMAND striplog0_unittest)
add_executable (striplog2_unittest
src/striplog_unittest.cc
)
target_compile_definitions (striplog2_unittest PRIVATE GOOGLE_STRIP_LOG=2)
target_link_libraries (striplog2_unittest PRIVATE glog_test)
add_test (NAME striplog2 COMMAND striplog2_unittest)
add_executable (striplog10_unittest
src/striplog_unittest.cc
)
target_compile_definitions (striplog10_unittest PRIVATE GOOGLE_STRIP_LOG=10)
target_link_libraries (striplog10_unittest PRIVATE glog_test)
add_test (NAME striplog10 COMMAND striplog10_unittest)
set_tests_properties (
striplog0
striplog2
striplog10
PROPERTIES WILL_FAIL ON
)
add_test (NAME log_severity_constants COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/log_severity_unittest"
"${glog_BINARY_DIR}/Tests/log_severity_constants"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_log_severity_constants
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
set_tests_properties (log_severity_constants PROPERTIES
PASS_REGULAR_EXPRESSION "COMPACT_GOOGLE_LOG_[1-3]"
)
add_test (NAME log_severity_conversion COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/log_severity_unittest"
"${glog_BINARY_DIR}/Tests/log_severity_conversion"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_log_severity_conversion
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
if (CMAKE_COMPILER_IS_GNUCXX)
set_tests_properties (log_severity_conversion PROPERTIES
PASS_REGULAR_EXPRESSION "error: invalid conversion from (|')int(|')"
)
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
set_tests_properties (log_severity_conversion PROPERTIES
PASS_REGULAR_EXPRESSION "no known conversion from 'int'"
)
elseif (MSVC)
set_tests_properties (log_severity_conversion PROPERTIES
PASS_REGULAR_EXPRESSION "error C2440"
)
else (CMAKE_COMPILER_IS_GNUCXX)
message (AUTHOR_WARNING
"Unsupported C++ compiler ${CMAKE_CXX_COMPILER_ID}: "
"log_severity_conversion test will be disabled"
)
set_tests_properties (log_severity_conversion DISABLED ON)
endif (CMAKE_COMPILER_IS_GNUCXX)
add_test (NAME includes_logging COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/includes_unittest"
"${glog_BINARY_DIR}/Tests/includes_logging"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_includes_logging
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
add_test (NAME includes_vlog_is_on COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/includes_unittest"
"${glog_BINARY_DIR}/Tests/includes_vlog_is_on"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_includes_vlog_is_on
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
add_test (NAME includes_raw_logging COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/includes_unittest"
"${glog_BINARY_DIR}/Tests/includes_raw_logging"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_includes_raw_logging
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
add_test (NAME includes_stl_logging COMMAND ${CMAKE_CTEST_COMMAND}
--build-config $<CONFIG>
--build-and-test
"${glog_SOURCE_DIR}/src/includes_unittest"
"${glog_BINARY_DIR}/Tests/includes_stl_logging"
--build-generator ${CMAKE_GENERATOR}
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_includes_stl_logging
--build-options
-DCMAKE_BUILD_TYPE=$<CONFIG>
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
-Dglog_DIR=${glog_BINARY_DIR}
)
add_test (NAME dcheck_on COMMAND ${CMAKE_CTEST_COMMAND}
--build-config Debug
--build-and-test
"${glog_SOURCE_DIR}/src/dcheck_unittest"
"${glog_BINARY_DIR}/Tests/dcheck_on"
--build-generator ${CMAKE_GENERATOR}
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_dcheck
--build-options
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
-Dglog_DIR=${glog_BINARY_DIR}
--test-command glog_dcheck
)
set_tests_properties (dcheck_on PROPERTIES
DISABLED $<NOT:$<CONFIG:Debug,RelWithDebInfo>>
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>"
PASS_REGULAR_EXPRESSION "Assert failed: false"
)
add_test (NAME dcheck_off COMMAND ${CMAKE_CTEST_COMMAND}
--build-config Release
--build-and-test
"${glog_SOURCE_DIR}/src/dcheck_unittest"
"${glog_BINARY_DIR}/Tests/dcheck_off"
--build-generator ${CMAKE_GENERATOR}
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
--build-target glog_dcheck
--build-options
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
-Dglog_DIR=${glog_BINARY_DIR}
--test-command glog_dcheck
)
# There should be no output
set_tests_properties (dcheck_off PROPERTIES
DISABLED $<NOT:$<CONFIG:Release,MinSizeRel>>
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>"
PASS_REGULAR_EXPRESSION ""
)
endif (BUILD_TESTING) endif (BUILD_TESTING)
if (BUILD_EXAMPLES)
add_executable (custom_sink_example examples/custom_sink.cc)
target_link_libraries (custom_sink_example PRIVATE glog::glog)
endif (BUILD_EXAMPLES)
install (TARGETS glog install (TARGETS glog
EXPORT glog-targets EXPORT glog-targets
RUNTIME DESTINATION ${_glog_CMake_BINDIR} RUNTIME DESTINATION ${_glog_CMake_BINDIR}
@ -975,7 +869,7 @@ install (TARGETS glog
if (WITH_PKGCONFIG) if (WITH_PKGCONFIG)
install ( install (
FILES "${glog_BINARY_DIR}/libglog.pc" FILES "${PROJECT_BINARY_DIR}/libglog.pc"
DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig" DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig"
) )
endif (WITH_PKGCONFIG) endif (WITH_PKGCONFIG)
@ -996,12 +890,12 @@ if (gflags_FOUND)
endif (gflags_FOUND) endif (gflags_FOUND)
configure_package_config_file (glog-config.cmake.in configure_package_config_file (glog-config.cmake.in
${glog_BINARY_DIR}/glog-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR} INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR}
NO_CHECK_REQUIRED_COMPONENTS_MACRO) NO_CHECK_REQUIRED_COMPONENTS_MACRO)
write_basic_package_version_file ( write_basic_package_version_file (
${glog_BINARY_DIR}/glog-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
COMPATIBILITY SameMajorVersion) COMPATIBILITY SameMajorVersion)
export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake) export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)
@ -1019,10 +913,10 @@ get_filename_component (glog_REL_CMake_DATADIR ${glog_REL_CMake_MODULES}
DIRECTORY) DIRECTORY)
set (glog_FULL_CMake_DATADIR set (glog_FULL_CMake_DATADIR
${glog_BINARY_DIR}/${_glog_CMake_DATADIR}) ${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
configure_file (glog-modules.cmake.in configure_file (glog-modules.cmake.in
${glog_BINARY_DIR}/glog-modules.cmake @ONLY) ${CMAKE_CURRENT_BINARY_DIR}/glog-modules.cmake @ONLY)
install (CODE install (CODE
" "
@ -1033,10 +927,10 @@ if (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
set (glog_DATADIR_DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${glog_DATADIR_DESTINATION}\") set (glog_DATADIR_DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${glog_DATADIR_DESTINATION}\")
endif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR}) endif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
configure_file (\"${glog_SOURCE_DIR}/glog-modules.cmake.in\" configure_file (\"${CMAKE_CURRENT_SOURCE_DIR}/glog-modules.cmake.in\"
\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" @ONLY) \"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" @ONLY)
file (INSTALL file (INSTALL
\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" \"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\"
DESTINATION DESTINATION
\"\${glog_DATADIR_DESTINATION}\") \"\${glog_DATADIR_DESTINATION}\")
" "
@ -1044,8 +938,8 @@ file (INSTALL
) )
install (FILES install (FILES
${glog_BINARY_DIR}/glog-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
${glog_BINARY_DIR}/glog-config-version.cmake ${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
DESTINATION ${_glog_CMake_INSTALLDIR}) DESTINATION ${_glog_CMake_INSTALLDIR})
# Find modules in share/glog/cmake # Find modules in share/glog/cmake

65
COPYING Normal file
View File

@ -0,0 +1,65 @@
Copyright (c) 2008, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
A function gettimeofday in utilities.cc is based on
http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/COPYING&q=GetSystemTimeAsFileTime%20license:bsd
The license of this code is:
Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name(s) of the above-listed copyright holder(s) nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,13 +1,3 @@
2024-06-08 Google Inc. <opensource@google.com>
* google-glog: version 0.7.1.
* See git log for the details.
2024-02-17 Google Inc. <opensource@google.com>
* google-glog: version 0.7.0.
* See git log for the details.
2022-04-05 Google Inc. <opensource@google.com> 2022-04-05 Google Inc. <opensource@google.com>
* google-glog: version 0.6.0. * google-glog: version 0.6.0.

View File

@ -1,27 +0,0 @@
Copyright © 2024, Google Inc.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
* Neither the name of Google Inc. nor the names of its contributors may be used
to endorse or promote products derived from this software without specific
prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,13 +0,0 @@
module(
name = "glog",
compatibility_level = 1,
)
bazel_dep(name = "gflags", version = "2.2.2")
bazel_dep(name = "googletest", version = "1.14.0", dev_dependency = True)
bazel_dep(name = "platforms", version = "0.0.10")
bazel_dep(name = "rules_cc", version = "0.0.12")
# Required for Windows clang-cl build: --extra_toolchains=@local_config_cc//:cc-toolchain-arm64_windows
cc_configure = use_extension("@rules_cc//cc:extensions.bzl", "cc_configure_extension")
use_repo(cc_configure, "local_config_cc")

View File

@ -7,10 +7,877 @@ Google Logging (glog) is a C++14 library that implements application-level
logging. The library provides logging APIs based on C++-style streams and logging. The library provides logging APIs based on C++-style streams and
various helper macros. various helper macros.
.. role:: cmake(code)
:language: cmake
.. role:: cmd(code)
:language: bash
.. role:: cpp(code)
:language: cpp
.. role:: bazel(code)
:language: starlark
Getting Started Getting Started
--------------- ---------------
Please refer to project's `documentation <https://google.github.io/glog/>`_. You can log a message by simply streaming things to ``LOG``\ (<a
particular `severity level <#severity-levels>`__>), e.g.,
.. code:: cpp
#include <glog/logging.h>
int main(int argc, char* argv[]) {
// Initialize Googles logging library.
google::InitGoogleLogging(argv[0]);
// ...
LOG(INFO) << "Found " << num_cookies << " cookies";
}
For a detailed overview of glog features and their usage, please refer
to the `user guide <#user-guide>`__.
.. contents:: Table of Contents
Building from Source
--------------------
glog supports multiple build systems for compiling the project from
source: `Bazel <#bazel>`__, `CMake <#cmake>`__, `vcpkg <#vcpkg>`__, and `conan <#conan>`__.
Bazel
~~~~~
To use glog within a project which uses the
`Bazel <https://bazel.build/>`__ build tool, add the following lines to
your ``WORKSPACE`` file:
.. code:: bazel
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_github_gflags_gflags",
sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
strip_prefix = "gflags-2.2.2",
urls = ["https://github.com/gflags/gflags/archive/v2.2.2.tar.gz"],
)
http_archive(
name = "com_github_google_glog",
sha256 = "122fb6b712808ef43fbf80f75c52a21c9760683dae470154f02bddfc61135022",
strip_prefix = "glog-0.6.0",
urls = ["https://github.com/google/glog/archive/v0.6.0.zip"],
)
You can then add :bazel:`@com_github_google_glog//:glog` to the deps section
of a :bazel:`cc_binary` or :bazel:`cc_library` rule, and :code:`#include
<glog/logging.h>` to include it in your source code. Heres a simple example:
.. code:: bazel
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = ["@com_github_google_glog//:glog"],
)
CMake
~~~~~
glog also supports CMake that can be used to build the project on a wide
range of platforms. If you dont have CMake installed already, you can
download it for from CMakes `official
website <http://www.cmake.org>`__.
CMake works by generating native makefiles or build projects that can be
used in the compiler environment of your choice. You can either build
glog with CMake as a standalone project or it can be incorporated into
an existing CMake build for another project.
Building glog with CMake
^^^^^^^^^^^^^^^^^^^^^^^^
When building glog as a standalone project, on Unix-like systems with
GNU Make as build tool, the typical workflow is:
1. Get the source code and change to it. e.g., cloning with git:
.. code:: bash
git clone https://github.com/google/glog.git
cd glog
2. Run CMake to configure the build tree.
.. code:: bash
cmake -S . -B build -G "Unix Makefiles"
CMake provides different generators, and by default will pick the most
relevant one to your environment. If you need a specific version of Visual
Studio, use :cmd:`cmake . -G <generator-name>`, and see :cmd:`cmake --help`
for the available generators. Also see :cmd:`-T <toolset-name>`, which can
be used to request the native x64 toolchain with :cmd:`-T host=x64`.
3. Afterwards, generated files can be used to compile the project.
.. code:: bash
cmake --build build
4. Test the build software (optional).
.. code:: bash
cmake --build build --target test
5. Install the built files (optional).
.. code:: bash
cmake --build build --target install
Consuming glog in a CMake Project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you have glog installed in your system, you can use the CMake command
:cmake:`find_package` to build against glog in your CMake Project as follows:
.. code:: cmake
cmake_minimum_required (VERSION 3.16)
project (myproj VERSION 1.0)
find_package (glog 0.6.0 REQUIRED)
add_executable (myapp main.cpp)
target_link_libraries (myapp glog::glog)
Compile definitions and options will be added automatically to your
target as needed.
Incorporating glog into a CMake Project
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can also use the CMake command :cmake:`add_subdirectory` to include glog
directly from a subdirectory of your project by replacing the
:cmake:`find_package` call from the previous example by
:cmake:`add_subdirectory`. The :cmake:`glog::glog` target is in this case an
:cmake:`ALIAS` library target for the ``glog`` library target.
Again, compile definitions and options will be added automatically to
your target as needed.
vcpkg
~~~~~
You can download and install glog using the `vcpkg
<https://github.com/Microsoft/vcpkg>`__ dependency manager:
.. code:: bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install glog
The glog port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please create an
issue or pull request on the vcpkg repository.
conan
~~~~~
You can download and install glog using the `conan
<https://conan.io>`__ package manager:
.. code:: bash
pip install conan
conan install -r conancenter glog/<glog-version>@
The glog recipe in conan center is kept up to date by conan center index community
contributors. If the version is out of date, please create an
issue or pull request on the `conan-center-index
<https://github.com/conan-io/conan-center-index>`__ repository.
User Guide
----------
glog defines a series of macros that simplify many common logging tasks.
You can log messages by severity level, control logging behavior from
the command line, log based on conditionals, abort the program when
expected conditions are not met, introduce your own verbose logging
levels, customize the prefix attached to log messages, and more.
Following sections describe the functionality supported by glog. Please note
this description may not be complete but limited to the most useful ones. If you
want to find less common features, please check header files under `src/glog
<src/glog>`__ directory.
Severity Levels
~~~~~~~~~~~~~~~
You can specify one of the following severity levels (in increasing
order of severity): ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL``.
Logging a ``FATAL`` message terminates the program (after the message is
logged). Note that messages of a given severity are logged not only in
the logfile for that severity, but also in all logfiles of lower
severity. E.g., a message of severity ``FATAL`` will be logged to the
logfiles of severity ``FATAL``, ``ERROR``, ``WARNING``, and ``INFO``.
The ``DFATAL`` severity logs a ``FATAL`` error in debug mode (i.e.,
there is no ``NDEBUG`` macro defined), but avoids halting the program in
production by automatically reducing the severity to ``ERROR``.
Unless otherwise specified, glog writes to the filename
``/tmp/\<program name\>.\<hostname\>.\<user name\>.log.\<severity level\>.\<date\>-\<time\>.\<pid\>``
(e.g.,
``/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474``).
By default, glog copies the log messages of severity level ``ERROR`` or
``FATAL`` to standard error (``stderr``) in addition to log files.
Setting Flags
~~~~~~~~~~~~~
Several flags influence glogs output behavior. If the `Google gflags library
<https://github.com/gflags/gflags>`__ is installed on your machine, the build
system will automatically detect and use it, allowing you to pass flags on the
command line. For example, if you want to turn the flag :cmd:`--logtostderr` on,
you can start your application with the following command line:
.. code:: bash
./your_application --logtostderr=1
If the Google gflags library isnt installed, you set flags via
environment variables, prefixing the flag name with ``GLOG_``, e.g.,
.. code:: bash
GLOG_logtostderr=1 ./your_application
The following flags are most commonly used:
``logtostderr`` (``bool``, default=\ ``false``)
Log messages to ``stderr`` instead of logfiles. Note: you can set
binary flags to ``true`` by specifying ``1``, ``true``, or ``yes``
(case insensitive). Also, you can set binary flags to ``false`` by
specifying ``0``, ``false``, or ``no`` (again, case insensitive).
``stderrthreshold`` (``int``, default=2, which is ``ERROR``)
Copy log messages at or above this level to stderr in addition to
logfiles. The numbers of severity levels ``INFO``, ``WARNING``,
``ERROR``, and ``FATAL`` are 0, 1, 2, and 3, respectively.
``minloglevel`` (``int``, default=0, which is ``INFO``)
Log messages at or above this level. Again, the numbers of severity
levels ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL`` are 0, 1, 2,
and 3, respectively.
``log_dir`` (``string``, default="")
If specified, logfiles are written into this directory instead of the
default logging directory.
``v`` (``int``, default=0)
Show all ``VLOG(m)`` messages for ``m`` less or equal the value of
this flag. Overridable by :cmd:`--vmodule`. See `the section about
verbose logging <#verbose-logging>`__ for more detail.
``vmodule`` (``string``, default="")
Per-module verbose level. The argument has to contain a
comma-separated list of <module name>=<log level>. <module name> is a
glob pattern (e.g., ``gfs*`` for all modules whose name starts with
"gfs"), matched against the filename base (that is, name ignoring
.cc/.h./-inl.h). <log level> overrides any value given by :cmd:`--v`.
See also `the section about verbose logging <#verbose-logging>`__.
There are some other flags defined in logging.cc. Please grep the source
code for ``DEFINE_`` to see a complete list of all flags.
You can also modify flag values in your program by modifying global
variables ``FLAGS_*`` . Most settings start working immediately after
you update ``FLAGS_*`` . The exceptions are the flags related to
destination files. For example, you might want to set ``FLAGS_log_dir``
before calling :cpp:`google::InitGoogleLogging` . Here is an example:
.. code:: cpp
LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This wont change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";
Conditional / Occasional Logging
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sometimes, you may only want to log a message under certain conditions.
You can use the following macros to perform conditional logging:
.. code:: cpp
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
The "Got lots of cookies" message is logged only when the variable
``num_cookies`` exceeds 10. If a line of code is executed many times, it
may be useful to only log a message at certain intervals. This kind of
logging is most useful for informational messages.
.. code:: cpp
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
The above line outputs a log messages on the 1st, 11th, 21st, ... times
it is executed. Note that the special ``google::COUNTER`` value is used
to identify which repetition is happening.
You can combine conditional and occasional logging with the following
macro.
.. code:: cpp
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
<< "th big cookie";
Instead of outputting a message every nth time, you can also limit the
output to the first n occurrences:
.. code:: cpp
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
Outputs log messages for the first 20 times it is executed. Again, the
``google::COUNTER`` identifier indicates which repetition is happening.
Other times, it is desired to only log a message periodically based on a time.
So for example, to log a message every 10ms:
.. code:: cpp
LOG_EVERY_T(INFO, 0.01) << "Got a cookie";
Or every 2.35s:
.. code:: cpp
LOG_EVERY_T(INFO, 2.35) << "Got a cookie";
Debug Mode Support
~~~~~~~~~~~~~~~~~~
Special "debug mode" logging macros only have an effect in debug mode
and are compiled away to nothing for non-debug mode compiles. Use these
macros to avoid slowing down your production application due to
excessive logging.
.. code:: cpp
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
``CHECK`` Macros
~~~~~~~~~~~~~~~~
It is a good practice to check expected conditions in your program
frequently to detect errors as early as possible. The ``CHECK`` macro
provides the ability to abort the application when a condition is not
met, similar to the ``assert`` macro defined in the standard C library.
``CHECK`` aborts the application if a condition is not true. Unlike
``assert``, it is \*not\* controlled by ``NDEBUG``, so the check will be
executed regardless of compilation mode. Therefore, ``fp->Write(x)`` in
the following example is always executed:
.. code:: cpp
CHECK(fp->Write(x) == 4) << "Write failed!";
There are various helper macros for equality/inequality checks -
``CHECK_EQ``, ``CHECK_NE``, ``CHECK_LE``, ``CHECK_LT``, ``CHECK_GE``,
and ``CHECK_GT``. They compare two values, and log a ``FATAL`` message
including the two values when the result is not as expected. The values
must have :cpp:`operator<<(ostream, ...)` defined.
You may append to the error message like so:
.. code:: cpp
CHECK_NE(1, 2) << ": The world must be ending!";
We are very careful to ensure that each argument is evaluated exactly
once, and that anything which is legal to pass as a function argument is
legal here. In particular, the arguments may be temporary expressions
which will end up being destroyed at the end of the apparent statement,
for example:
.. code:: cpp
CHECK_EQ(string("abc")[1], b);
The compiler reports an error if one of the arguments is a pointer and the other
is :cpp:`nullptr`. To work around this, simply :cpp:`static_cast` :cpp:`nullptr` to
the type of the desired pointer.
.. code:: cpp
CHECK_EQ(some_ptr, static_cast<SomeType*>(nullptr));
Better yet, use the ``CHECK_NOTNULL`` macro:
.. code:: cpp
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
Since this macro returns the given pointer, this is very useful in
constructor initializer lists.
.. code:: cpp
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
Note that you cannot use this macro as a C++ stream due to this feature.
Please use ``CHECK_EQ`` described above to log a custom message before
aborting the application.
If you are comparing C strings (:cpp:`char *`), a handy set of macros performs
case sensitive as well as case insensitive comparisons - ``CHECK_STREQ``,
``CHECK_STRNE``, ``CHECK_STRCASEEQ``, and ``CHECK_STRCASENE``. The CASE versions
are case-insensitive. You can safely pass :cpp:`nullptr` pointers for this macro. They
treat :cpp:`nullptr` and any non-:cpp:`nullptr` string as not equal. Two :cpp:`nullptr`\
s are equal.
Note that both arguments may be temporary strings which are destructed
at the end of the current "full expression" (e.g.,
:cpp:`CHECK_STREQ(Foo().c_str(), Bar().c_str())` where ``Foo`` and ``Bar``
return C++s :cpp:`std::string`).
The ``CHECK_DOUBLE_EQ`` macro checks the equality of two floating point
values, accepting a small error margin. ``CHECK_NEAR`` accepts a third
floating point argument, which specifies the acceptable error margin.
Verbose Logging
~~~~~~~~~~~~~~~
When you are chasing difficult bugs, thorough log messages are very useful.
However, you may want to ignore too verbose messages in usual development. For
such verbose logging, glog provides the ``VLOG`` macro, which allows you to
define your own numeric logging levels. The :cmd:`--v` command line option
controls which verbose messages are logged:
.. code:: cpp
VLOG(1) << "Im printed when you run the program with --v=1 or higher";
VLOG(2) << "Im printed when you run the program with --v=2 or higher";
With ``VLOG``, the lower the verbose level, the more likely messages are to be
logged. For example, if :cmd:`--v==1`, ``VLOG(1)`` will log, but ``VLOG(2)``
will not log. This is opposite of the severity level, where ``INFO`` is 0, and
``ERROR`` is 2. :cmd:`--minloglevel` of 1 will log ``WARNING`` and above. Though
you can specify any integers for both ``VLOG`` macro and :cmd:`--v` flag, the
common values for them are small positive integers. For example, if you write
``VLOG(0)``, you should specify :cmd:`--v=-1` or lower to silence it. This is
less useful since we may not want verbose logs by default in most cases. The
``VLOG`` macros always log at the ``INFO`` log level (when they log at all).
Verbose logging can be controlled from the command line on a per-module
basis:
.. code:: bash
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
will:
(a) Print ``VLOG(2)`` and lower messages from mapreduce.{h,cc}
(b) Print ``VLOG(1)`` and lower messages from file.{h,cc}
(c) Print ``VLOG(3)`` and lower messages from files prefixed with "gfs"
(d) Print ``VLOG(0)`` and lower messages from elsewhere
The wildcarding functionality shown by (c) supports both * (matches 0
or more characters) and ? (matches any single character) wildcards.
Please also check the section about `command line flags <#setting-flags>`__.
Theres also ``VLOG_IS_ON(n)`` "verbose level" condition macro. This
macro returns true when the :cmd:`--v` is equal or greater than ``n``. To
be used as
.. code:: cpp
if (VLOG_IS_ON(2)) {
// do some logging preparation and logging
// that cant be accomplished with just VLOG(2) << ...;
}
Verbose level condition macros ``VLOG_IF``, ``VLOG_EVERY_N`` and
``VLOG_IF_EVERY_N`` behave analogous to ``LOG_IF``, ``LOG_EVERY_N``,
``LOF_IF_EVERY``, but accept a numeric verbosity level as opposed to a
severity level.
.. code:: cpp
VLOG_IF(1, (size > 1024))
<< "Im printed when size is more than 1024 and when you run the "
"program with --v=1 or more";
VLOG_EVERY_N(1, 10)
<< "Im printed every 10th occurrence, and when you run the program "
"with --v=1 or more. Present occurrence is " << google::COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
<< "Im printed on every 10th occurrence of case when size is more "
" than 1024, when you run the program with --v=1 or more. ";
"Present occurrence is " << google::COUNTER;
Custom Log Prefix Format
~~~~~~~~~~~~~~~~~~~~~~~~
glog supports changing the format of the prefix attached to log messages by
receiving a user-provided callback to be used to generate such strings.
For each log entry, the callback will be invoked with a ``LogMessageInfo``
struct containing the severity, filename, line number, thread ID, and time of
the event. It will also be given a reference to the output stream, whose
contents will be prepended to the actual message in the final log line.
For example:
.. code:: cpp
/* This function writes a prefix that matches glog's default format.
* (The third parameter can be used to receive user-supplied data, and is
* nullptr by default.)
*/
void CustomPrefix(std::ostream &s, const LogMessageInfo &l, void*) {
s << l.severity[0]
<< setw(4) << 1900 + l.time.year()
<< setw(2) << 1 + l.time.month()
<< setw(2) << l.time.day()
<< ' '
<< setw(2) << l.time.hour() << ':'
<< setw(2) << l.time.min() << ':'
<< setw(2) << l.time.sec() << "."
<< setw(6) << l.time.usec()
<< ' '
<< setfill(' ') << setw(5)
<< l.thread_id << setfill('0')
<< ' '
<< l.filename << ':' << l.line_number << "]";
}
To enable the use of ``CustomPrefix()``, simply give glog a pointer to it
during initialization: ``InitGoogleLogging(argv[0], &CustomPrefix);``.
Optionally, ``InitGoogleLogging()`` takes a third argument of type ``void*``
to pass on to the callback function.
Failure Signal Handler
~~~~~~~~~~~~~~~~~~~~~~
The library provides a convenient signal handler that will dump useful
information when the program crashes on certain signals such as ``SIGSEGV``. The
signal handler can be installed by :cpp:`google::InstallFailureSignalHandler()`.
The following is an example of output from the signal handler.
::
*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ***
*** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***
PC: @ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f892fb417d0 (unknown)
@ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f89304f7f06 google::LogMessage::SendToLog()
@ 0x7f89304f35af google::LogMessage::Flush()
@ 0x7f89304f3739 google::LogMessage::~LogMessage()
@ 0x408cf4 TestLogSinkWaitTillSent()
@ 0x4115de main
@ 0x7f892f7ef1c4 (unknown)
@ 0x4046f9 (unknown)
By default, the signal handler writes the failure dump to the standard
error. You can customize the destination by :cpp:`InstallFailureWriter()`.
Performance of Messages
~~~~~~~~~~~~~~~~~~~~~~~
The conditional logging macros provided by glog (e.g., ``CHECK``,
``LOG_IF``, ``VLOG``, etc.) are carefully implemented and dont execute
the right hand side expressions when the conditions are false. So, the
following check may not sacrifice the performance of your application.
.. code:: cpp
CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
User-defined Failure Function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``FATAL`` severity level messages or unsatisfied ``CHECK`` condition
terminate your program. You can change the behavior of the termination
by :cpp:`InstallFailureFunction`.
.. code:: cpp
void YourFailureFunction() {
// Reports something...
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&YourFailureFunction);
}
By default, glog tries to dump stacktrace and makes the program exit
with status 1. The stacktrace is produced only when you run the program
on an architecture for which glog supports stack tracing (as of
September 2008, glog supports stack tracing for x86 and x86_64).
Raw Logging
~~~~~~~~~~~
The header file ``<glog/raw_logging.h>`` can be used for thread-safe logging,
which does not allocate any memory or acquire any locks. Therefore, the macros
defined in this header file can be used by low-level memory allocation and
synchronization code. Please check `src/glog/raw_logging.h.in
<src/glog/raw_logging.h.in>`__ for detail.
Google Style ``perror()``
~~~~~~~~~~~~~~~~~~~~~~~~~
``PLOG()`` and ``PLOG_IF()`` and ``PCHECK()`` behave exactly like their
``LOG*`` and ``CHECK`` equivalents with the addition that they append a
description of the current state of errno to their output lines. E.g.
.. code:: cpp
PCHECK(write(1, nullptr, 2) >= 0) << "Write nullptr failed";
This check fails with the following error message.
::
F0825 185142 test.cc:22] Check failed: write(1, nullptr, 2) >= 0 Write nullptr failed: Bad address [14]
Syslog
~~~~~~
``SYSLOG``, ``SYSLOG_IF``, and ``SYSLOG_EVERY_N`` macros are available.
These log to syslog in addition to the normal logs. Be aware that
logging to syslog can drastically impact performance, especially if
syslog is configured for remote logging! Make sure you understand the
implications of outputting to syslog before you use these macros. In
general, its wise to use these macros sparingly.
Strip Logging Messages
~~~~~~~~~~~~~~~~~~~~~~
Strings used in log messages can increase the size of your binary and
present a privacy concern. You can therefore instruct glog to remove all
strings which fall below a certain severity level by using the
``GOOGLE_STRIP_LOG`` macro:
If your application has code like this:
.. code:: cpp
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include <glog/logging.h>
The compiler will remove the log messages whose severities are less than
the specified integer value. Since ``VLOG`` logs at the severity level
``INFO`` (numeric value ``0``), setting ``GOOGLE_STRIP_LOG`` to 1 or
greater removes all log messages associated with ``VLOG``\ s as well as
``INFO`` log statements.
Automatically Remove Old Logs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To enable the log cleaner:
.. code:: cpp
google::EnableLogCleaner(3); // keep your logs for 3 days
And then glog will check if there are overdue logs whenever a flush is
performed. In this example, any log file from your project whose last
modified time is greater than 3 days will be unlink()ed.
This feature can be disabled at any time (if it has been enabled)
.. code:: cpp
google::DisableLogCleaner();
Notes for Windows Users
~~~~~~~~~~~~~~~~~~~~~~~
glog defines a severity level ``ERROR``, which is also defined in
``windows.h`` . You can make glog not define ``INFO``, ``WARNING``,
``ERROR``, and ``FATAL`` by defining ``GLOG_NO_ABBREVIATED_SEVERITIES``
before including ``glog/logging.h`` . Even with this macro, you can
still use the iostream like logging facilities:
.. code:: cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";
However, you cannot use ``INFO``, ``WARNING``, ``ERROR``, and ``FATAL``
anymore for functions defined in ``glog/logging.h`` .
.. code:: cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
// This wont work.
// google::FlushLogFiles(google::ERROR);
// Use this instead.
google::FlushLogFiles(google::GLOG_ERROR);
If you dont need ``ERROR`` defined by ``windows.h``, there are a couple
of more workarounds which sometimes dont work:
- ``#define WIN32_LEAN_AND_MEAN`` or ``NOGDI`` **before** you
``#include windows.h``.
- ``#undef ERROR`` **after** you ``#include windows.h`` .
See `this
issue <http://code.google.com/p/google-glog/issues/detail?id=33>`__ for
more detail.
Installation Notes for 64-bit Linux Systems
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The glibc built-in stack-unwinder on 64-bit systems has some problems with glog.
(In particular, if you are using :cpp:`InstallFailureSignalHandler()`, the
signal may be raised in the middle of malloc, holding some malloc-related locks
when they invoke the stack unwinder. The built-in stack unwinder may call malloc
recursively, which may require the thread to acquire a lock it already holds:
deadlock.)
For that reason, if you use a 64-bit system and you need
:cpp:`InstallFailureSignalHandler()`, we strongly recommend you install
``libunwind`` before trying to configure or install google glog.
libunwind can be found
`here <http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz>`__.
Even if you already have ``libunwind`` installed, you will probably
still need to install from the snapshot to get the latest version.
Caution: if you install libunwind from the URL above, be aware that you
may have trouble if you try to statically link your binary with glog:
that is, if you link with ``gcc -static -lgcc_eh ...``. This is because
both ``libunwind`` and ``libgcc`` implement the same C++ exception
handling APIs, but they implement them differently on some platforms.
This is not likely to be a problem on ia64, but may be on x86-64.
Also, if you link binaries statically, make sure that you add
:cmd:`-Wl,--eh-frame-hdr` to your linker options. This is required so that
``libunwind`` can find the information generated by the compiler required for
stack unwinding.
Using :cmd:`-static` is rare, though, so unless you know this will affect you it
probably wont.
If you cannot or do not wish to install libunwind, you can still try to
use two kinds of stack-unwinder: 1. glibc built-in stack-unwinder and 2.
frame pointer based stack-unwinder.
1. As we already mentioned, glibcs unwinder has a deadlock issue.
However, if you dont use :cpp:`InstallFailureSignalHandler()` or you
dont worry about the rare possibilities of deadlocks, you can use
this stack-unwinder. If you specify no options and ``libunwind``
isnt detected on your system, the configure script chooses this
unwinder by default.
2. The frame pointer based stack unwinder requires that your
application, the glog library, and system libraries like libc, all be
compiled with a frame pointer. This is *not* the default for x86-64.
How to Contribute
-----------------
Wed love to accept your patches and contributions to this project.
There are a just a few small guidelines you need to follow.
Contributor License Agreement (CLA)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply
gives Google permission to use and redistribute your contributions as
part of the project.
* If you are an individual writing original source code and youre sure
you own the intellectual property, then youll need to sign an
`individual
CLA <https://developers.google.com/open-source/cla/individual>`__.
* If you work for a company that wants to allow you to contribute your
work, then youll need to sign a `corporate
CLA <https://developers.google.com/open-source/cla/corporate>`__.
You generally only need to submit a CLA once, so if youve already
submitted one (even if it was for a different project), you probably
dont need to do it again.
Once your CLA is submitted (or if you already submitted one for another
Google project), make a commit adding yourself to the
`AUTHORS <./AUTHORS>`__ and `CONTRIBUTORS <./CONTRIBUTORS>`__ files. This
commit can be part of your first `pull
request <https://help.github.com/articles/creating-a-pull-request>`__.
Submitting a Patch
~~~~~~~~~~~~~~~~~~
1. Its generally best to start by opening a new issue describing the
bug or feature youre intending to fix. Even if you think its
relatively minor, its helpful to know what people are working on.
Mention in the initial issue that you are planning to work on that
bug or feature so that it can be assigned to you.
2. Follow the normal process of
`forking <https://help.github.com/articles/fork-a-repo>`__ the
project, and setup a new branch to work in. Its important that each
group of changes be done in separate branches in order to ensure that
a pull request only includes the commits related to that bug or
feature.
3. Do your best to have `well-formed commit
messages <http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html>`__
for each change. This provides consistency throughout the project,
and ensures that commit messages are able to be formatted properly by
various git tools.
4. Finally, push the commits to your fork and submit a `pull
request <https://help.github.com/articles/creating-a-pull-request>`__.
.. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg .. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg

18
WORKSPACE Normal file
View File

@ -0,0 +1,18 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "com_github_gflags_gflags",
sha256 = "34af2f15cf7367513b352bdcd2493ab14ce43692d2dcd9dfc499492966c64dcf",
strip_prefix = "gflags-2.2.2",
urls = [
"https://mirror.bazel.build/github.com/gflags/gflags/archive/v2.2.2.tar.gz",
"https://github.com/gflags/gflags/archive/v2.2.2.tar.gz",
],
)
http_archive(
name = "com_github_google_googletest",
sha256 = "258f33ab1a8ee17adf48ec65e821d0ea9eafcbedeff6110f9eaed78472e73dde",
strip_prefix = "googletest-15460959cbbfa20e66ef0b5ab497367e47fc0a04",
urls = ["https://github.com/google/googletest/archive/15460959cbbfa20e66ef0b5ab497367e47fc0a04.tar.gz"],
)

View File

@ -1 +0,0 @@
# WORKSPACE marker file needed by Bazel

View File

@ -4,6 +4,6 @@ cc_test(
srcs = ["main.cc"], srcs = ["main.cc"],
deps = [ deps = [
"//:glog", "//:glog",
"@gflags//:gflags", "@com_github_gflags_gflags//:gflags",
], ],
) )

View File

@ -25,7 +25,13 @@ expand_template = rule(
}, },
) )
def glog_library(with_gflags = 1, **kwargs): def dict_union(x, y):
z = {}
z.update(x)
z.update(y)
return z
def glog_library(namespace = "google", with_gflags = 1, **kwargs):
if native.repository_name() != "@": if native.repository_name() != "@":
repo_name = native.repository_name()[1:] # Strip the first leading @ repo_name = native.repository_name()[1:] # Strip the first leading @
gendir = "$(GENDIR)/external/" + repo_name gendir = "$(GENDIR)/external/" + repo_name
@ -48,8 +54,12 @@ def glog_library(with_gflags = 1, **kwargs):
common_copts = [ common_copts = [
"-std=c++14", "-std=c++14",
"-DGLOG_BAZEL_BUILD",
# Inject a C++ namespace.
"-DGOOGLE_NAMESPACE='%s'" % namespace,
"-DHAVE_STRING_H",
"-I%s/glog_internal" % gendir, "-I%s/glog_internal" % gendir,
] + (["-DGLOG_USE_GFLAGS"] if with_gflags else []) ] + (["-DHAVE_LIB_GFLAGS"] if with_gflags else [])
wasm_copts = [ wasm_copts = [
# Disable warnings that exists in glog. # Disable warnings that exists in glog.
@ -57,32 +67,27 @@ def glog_library(with_gflags = 1, **kwargs):
"-Wno-unused-function", "-Wno-unused-function",
"-Wno-unused-local-typedefs", "-Wno-unused-local-typedefs",
"-Wno-unused-variable", "-Wno-unused-variable",
# Allows src/base/mutex.h to include pthread.h.
"-DHAVE_PTHREAD",
# Allows src/logging.cc to determine the host name. # Allows src/logging.cc to determine the host name.
"-DHAVE_SYS_UTSNAME_H", "-DHAVE_SYS_UTSNAME_H",
# For src/utilities.cc. # For src/utilities.cc.
"-DHAVE_SYS_TIME_H", "-DHAVE_SYS_TIME_H",
# NOTE: users could optionally patch -DHAVE_UNWIND off if "-DHAVE__UNWIND_BACKTRACE",
# stacktrace dumping is not needed "-DHAVE__UNWIND_GETIP",
"-DHAVE_UNWIND",
# Enable dumping stacktrace upon sigaction. # Enable dumping stacktrace upon sigaction.
"-DHAVE_SIGACTION", "-DHAVE_SIGACTION",
# For logging.cc. # For logging.cc.
"-DHAVE_PREAD", "-DHAVE_PREAD",
# -DHAVE_MODE_T prevent repeated typedef mode_t leading "-DHAVE___ATTRIBUTE__",
# to emcc compilation failure
"-DHAVE_MODE_T",
"-DHAVE_UNISTD_H",
] ]
linux_or_darwin_copts = wasm_copts + [ linux_or_darwin_copts = wasm_copts + [
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))", "-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"-DGLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"-DHAVE_POSIX_FADVISE",
"-DHAVE_SSIZE_T",
"-DHAVE_SYS_TYPES_H",
# For src/utilities.cc. # For src/utilities.cc.
"-DHAVE_SYS_SYSCALL_H", "-DHAVE_SYS_SYSCALL_H",
# For src/logging.cc to create symlinks. # For src/logging.cc to create symlinks.
"-DHAVE_UNISTD_H",
"-fvisibility-inlines-hidden", "-fvisibility-inlines-hidden",
"-fvisibility=hidden", "-fvisibility=hidden",
] ]
@ -90,30 +95,26 @@ def glog_library(with_gflags = 1, **kwargs):
freebsd_only_copts = [ freebsd_only_copts = [
# Enable declaration of _Unwind_Backtrace # Enable declaration of _Unwind_Backtrace
"-D_GNU_SOURCE", "-D_GNU_SOURCE",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
] ]
linux_only_copts = [ linux_only_copts = [
# For utilities.h. # For utilities.h.
"-DHAVE_EXECINFO_H", "-DHAVE_EXECINFO_H",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
] ]
darwin_only_copts = [ darwin_only_copts = [
# For stacktrace. # For stacktrace.
"-DHAVE_DLADDR", "-DHAVE_DLADDR",
# Avoid deprecated syscall().
"-DHAVE_PTHREAD_THREADID_NP",
] ]
windows_only_copts = [ windows_only_copts = [
# Override -DGLOG_EXPORT= from the cc_library's defines. # Override -DGLOG_EXPORT= from the cc_library's defines.
"-DGLOG_EXPORT=__declspec(dllexport)", "-DGLOG_EXPORT=__declspec(dllexport)",
"-DGLOG_NO_ABBREVIATED_SEVERITIES", "-DGLOG_NO_ABBREVIATED_SEVERITIES",
"-DGLOG_NO_EXPORT=", "-DHAVE_SNPRINTF",
"-DGLOG_USE_WINDOWS_PORT",
"-DHAVE__CHSIZE_S", "-DHAVE__CHSIZE_S",
"-DHAVE_DBGHELP",
"-I" + src_windows, "-I" + src_windows,
] ]
@ -123,26 +124,25 @@ def glog_library(with_gflags = 1, **kwargs):
] ]
windows_only_srcs = [ windows_only_srcs = [
"src/glog/log_severity.h",
"src/windows/dirent.h", "src/windows/dirent.h",
"src/windows/port.cc", "src/windows/port.cc",
"src/windows/port.h", "src/windows/port.h",
] ]
gflags_deps = ["@gflags//:gflags"] if with_gflags else [] gflags_deps = ["@com_github_gflags_gflags//:gflags"] if with_gflags else []
final_lib_defines = select({ final_lib_defines = select({
# GLOG_EXPORT is normally set by export.h, but that's not # GLOG_EXPORT is normally set by export.h, but that's not
# generated for Bazel. # generated for Bazel.
"@bazel_tools//src/conditions:windows": [ "@bazel_tools//src/conditions:windows": [
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_EXPORT=", "GLOG_EXPORT=",
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_NO_ABBREVIATED_SEVERITIES", "GLOG_NO_ABBREVIATED_SEVERITIES",
"GLOG_NO_EXPORT=",
], ],
"//conditions:default": [ "//conditions:default": [
"GLOG_DEPRECATED=__attribute__((deprecated))", "GLOG_DEPRECATED=__attribute__((deprecated))",
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))", "GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"GLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
], ],
}) })
@ -162,6 +162,7 @@ def glog_library(with_gflags = 1, **kwargs):
name = "shared_headers", name = "shared_headers",
srcs = [ srcs = [
"src/base/commandlineflags.h", "src/base/commandlineflags.h",
"src/base/mutex.h",
"src/stacktrace.h", "src/stacktrace.h",
"src/utilities.h", "src/utilities.h",
] ]
@ -176,12 +177,9 @@ def glog_library(with_gflags = 1, **kwargs):
"src/base/googleinit.h", "src/base/googleinit.h",
"src/demangle.cc", "src/demangle.cc",
"src/demangle.h", "src/demangle.h",
"src/flags.cc",
"src/logging.cc", "src/logging.cc",
"src/raw_logging.cc", "src/raw_logging.cc",
"src/signalhandler.cc", "src/signalhandler.cc",
"src/stacktrace.cc",
"src/stacktrace.h",
"src/stacktrace_generic-inl.h", "src/stacktrace_generic-inl.h",
"src/stacktrace_libunwind-inl.h", "src/stacktrace_libunwind-inl.h",
"src/stacktrace_powerpc-inl.h", "src/stacktrace_powerpc-inl.h",
@ -191,21 +189,18 @@ def glog_library(with_gflags = 1, **kwargs):
"src/symbolize.cc", "src/symbolize.cc",
"src/symbolize.h", "src/symbolize.h",
"src/utilities.cc", "src/utilities.cc",
"src/utilities.h",
"src/vlog_is_on.cc", "src/vlog_is_on.cc",
] + select({ ] + select({
"@bazel_tools//src/conditions:windows": windows_only_srcs, "@bazel_tools//src/conditions:windows": windows_only_srcs,
"//conditions:default": [], "//conditions:default": [],
}), }),
hdrs = [ hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h", "src/glog/log_severity.h",
"src/glog/logging.h",
"src/glog/platform.h", "src/glog/platform.h",
"src/glog/raw_logging.h", ":logging_h",
"src/glog/stl_logging.h", ":raw_logging_h",
"src/glog/types.h", ":stl_logging_h",
"src/glog/vlog_is_on.h", ":vlog_is_on_h",
], ],
# https://github.com/google/glog/issues/837: Replacing # https://github.com/google/glog/issues/837: Replacing
# `strip_include_prefix` with `includes` would avoid spamming # `strip_include_prefix` with `includes` would avoid spamming
@ -222,10 +217,6 @@ def glog_library(with_gflags = 1, **kwargs):
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"], "@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
"//conditions:default": [], "//conditions:default": [],
}), }),
linkopts = select({
"@bazel_tools//src/conditions:windows": ["dbghelp.lib"],
"//conditions:default": [],
}),
**kwargs **kwargs
) )
@ -261,7 +252,7 @@ def glog_library(with_gflags = 1, **kwargs):
copts = final_lib_copts + test_only_copts, copts = final_lib_copts + test_only_copts,
deps = gflags_deps + [ deps = gflags_deps + [
":glog", ":glog",
"@googletest//:gtest", "@com_github_google_googletest//:gtest",
], ],
**kwargs **kwargs
) )
@ -271,14 +262,11 @@ def glog_library(with_gflags = 1, **kwargs):
native.cc_library( native.cc_library(
name = "strip_include_prefix_hack", name = "strip_include_prefix_hack",
hdrs = [ hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h", "src/glog/log_severity.h",
"src/glog/logging.h", ":logging_h",
"src/glog/platform.h", ":raw_logging_h",
"src/glog/raw_logging.h", ":stl_logging_h",
"src/glog/stl_logging.h", ":vlog_is_on_h",
"src/glog/types.h",
"src/glog/vlog_is_on.h",
], ],
) )
@ -288,3 +276,51 @@ def glog_library(with_gflags = 1, **kwargs):
out = "glog_internal/config.h", out = "glog_internal/config.h",
substitutions = {"#cmakedefine": "//cmakedefine"}, substitutions = {"#cmakedefine": "//cmakedefine"},
) )
common_config = {
"@ac_cv_have_u_int16_t@": "0",
"@ac_cv_have_glog_export@": "0",
"@ac_google_start_namespace@": "namespace google {",
"@ac_google_end_namespace@": "}",
"@ac_google_namespace@": "google",
}
posix_config = dict_union(common_config, {
"@ac_cv___attribute___noinline@": "__attribute__((noinline))",
"@ac_cv___attribute___printf_4_5@": "__attribute__((__format__(__printf__, 4, 5)))",
"@ac_cv_have___builtin_expect@": "1",
"@ac_cv_have_libgflags@": "1" if with_gflags else "0",
"@ac_cv_have_mode_t@": "1",
"@ac_cv_have_ssize_t@": "1",
"@ac_cv_have_systypes_h@": "1",
"@ac_cv_have_unistd_h@": "1",
})
windows_config = dict_union(common_config, {
"@ac_cv___attribute___noinline@": "",
"@ac_cv___attribute___printf_4_5@": "",
"@ac_cv_have___builtin_expect@": "0",
"@ac_cv_have_libgflags@": "0",
"@ac_cv_have_mode_t@": "0",
"@ac_cv_have_ssize_t@": "0",
"@ac_cv_have_systypes_h@": "0",
"@ac_cv_have_unistd_h@": "0",
})
[
expand_template(
name = "%s_h" % f,
template = "src/glog/%s.h.in" % f,
out = "src/glog/%s.h" % f,
substitutions = select({
"@bazel_tools//src/conditions:windows": windows_config,
"//conditions:default": posix_config,
}),
)
for f in [
"vlog_is_on",
"stl_logging",
"raw_logging",
"logging",
]
]

View File

@ -7,20 +7,16 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar) file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (WIN32) if (NOT NUM_FILES EQUAL 1)
# On Windows open files cannot be removed and will result in a permission message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}")
# denied error while unlinking such file. Therefore, the last file will be endif (NOT NUM_FILES EQUAL 1)
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)

View File

@ -7,20 +7,16 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo) file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (WIN32) if (NOT NUM_FILES EQUAL 1)
# On Windows open files cannot be removed and will result in a permission message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}")
# denied error while unlinking such file. Therefore, the last file will be endif (NOT NUM_FILES EQUAL 1)
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)

View File

@ -10,23 +10,19 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0) if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})") message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
endif (NOT _RESULT EQUAL 0) endif (NOT _RESULT EQUAL 0)
# Ensure the log files to have different modification timestamps such that
# exactly one log file remains at the end. Otherwise all log files will be
# retained.
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 2)
endforeach (iter) endforeach (iter)
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo) file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
list (LENGTH LOG_FILES NUM_FILES) list (LENGTH LOG_FILES NUM_FILES)
if (WIN32) if (NOT NUM_FILES EQUAL 1)
# On Windows open files cannot be removed and will result in a permission message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
# denied error while unlinking such file. Therefore, the last file will be endif (NOT NUM_FILES EQUAL 1)
# retained.
set (_expected 1)
else (WIN32)
set (_expected 0)
endif (WIN32)
if (NOT NUM_FILES EQUAL _expected)
message (SEND_ERROR "Expected ${_expected} log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL _expected)
# Remove the subdirectory required by this unit test. # Remove the subdirectory required by this unit test.
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR}) file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})

View File

@ -1,11 +1,4 @@
comment:
layout: "diff, flags, files"
behavior: default
require_changes: false
require_base: false
require_head: true
ignore: ignore:
- "**/*_unittest.cc" - "**/*_unittest.cc"
- "src/*_unittest/**"
- "src/googletest.h" - "src/googletest.h"
- "src/mock-log.h" - "src/mock-log.h"

View File

@ -1,66 +0,0 @@
# Building from Source
## Bazel
To use glog within a project which uses the [Bazel](https://bazel.build/) build
tool, add the following lines to your `MODULE.bazel` file:
``` bazel title="MODULE.bazel"
bazel_dep(name = "glog")
archive_override(
module_name = "glog",
urls = "https://github.com/google/glog/archive/cc0de6c200375b33d907ee7632eee2f173b33a09.tar.gz",
strip_prefix = "glog-cc0de6c200375b33d907ee7632eee2f173b33a09", # Latest commit as of 2024-06-08.
integrity = "sha256-rUrv4EBkdc+4Wbhfxp+KoRstlj2Iw842/OpLfDq0ivg=",
)
```
You can then add `@glog//:glog` to
the deps section of a `cc_binary` or
`cc_library` rule, and `#!cpp #include <glog/logging.h>` to
include it in your source code.
!!! example "Using glog in a Bazel project"
``` bazel
cc_binary(
name = "main",
srcs = ["main.cc"],
deps = ["@glog//:glog"],
)
```
## CMake
glog can be compiled using [CMake](http://www.cmake.org) on a wide range of
platforms. The typical workflow for building glog on a Unix-like system with GNU
Make as build tool is as follows:
1. Clone the repository and change into source directory.
``` bash
git clone https://github.com/google/glog.git
cd glog
```
2. Run CMake to configure the build tree.
``` bash
cmake -S . -B build -G "Unix Makefiles"
```
CMake provides different generators, and by default will pick the most
relevant one to your environment. If you need a specific version of Visual
Studio, use `#!bash cmake . -G <generator-name>`, and see `#!bash cmake
--help` for the available generators. Also see `-T <toolset-name>`, which can
be used to request the native x64 toolchain with `-T host=x64`.
3. Afterwards, generated files can be used to compile the project.
``` bash
cmake --build build
```
4. Test the build software (optional).
``` bash
cmake --build build --target test
```
5. Install the built files (optional).
``` bash
cmake --build build --target install
```
Once successfully built, glog can be [integrated into own projects](usage.md).

View File

@ -1,50 +0,0 @@
# How to Contribute
We'd love to accept your patches and contributions to this project.
There are a just a few small guidelines you need to follow.
## Contributor License Agreement (CLA)
Contributions to any Google project must be accompanied by a Contributor
License Agreement. This is not a copyright **assignment**, it simply
gives Google permission to use and redistribute your contributions as
part of the project.
- If you are an individual writing original source code and you're
sure you own the intellectual property, then you'll need to sign an
[individual
CLA](https://developers.google.com/open-source/cla/individual).
- If you work for a company that wants to allow you to contribute your
work, then you'll need to sign a [corporate
CLA](https://developers.google.com/open-source/cla/corporate).
You generally only need to submit a CLA once, so if you've already
submitted one (even if it was for a different project), you probably
don't need to do it again.
Once your CLA is submitted (or if you already submitted one for another Google
project), make a commit adding yourself to the
[AUTHORS](https://github.com/google/glog/blob/master/AUTHORS) and
[CONTRIBUTORS](https://github.com/google/glog/blob/master/CONTRIBUTORS) files.
This commit can be part of your first [pull
request](https://help.github.com/articles/creating-a-pull-request).
## Submitting a Patch
1. It's generally best to start by opening a new issue describing the
bug or feature you're intending to fix. Even if you think it's
relatively minor, it's helpful to know what people are working on.
Mention in the initial issue that you are planning to work on that
bug or feature so that it can be assigned to you.
2. Follow the normal process of
[forking](https://help.github.com/articles/fork-a-repo) the project,
and setup a new branch to work in. It's important that each group of
changes be done in separate branches in order to ensure that a pull
request only includes the commits related to that bug or feature.
3. Do your best to have [well-formed commit
messages](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html)
for each change. This provides consistency throughout the project,
and ensures that commit messages are able to be formatted properly
by various git tools.
4. Finally, push the commits to your fork and submit a [pull
request](https://help.github.com/articles/creating-a-pull-request).

View File

@ -1,73 +0,0 @@
# Failure Signal Handler
## Stacktrace as Default Failure Handler
The library provides a convenient signal handler that will dump useful
information when the program crashes on certain signals such as `SIGSEGV`. The
signal handler can be installed by `#!cpp
google::InstallFailureSignalHandler()`. The following is an example of output
from the signal handler.
*** Aborted at 1225095260 (unix time) try "date -d @1225095260" if you are using GNU date ***
*** SIGSEGV (@0x0) received by PID 17711 (TID 0x7f893090a6f0) from PID 0; stack trace: ***
PC: @ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f892fb417d0 (unknown)
@ 0x412eb1 TestWaitingLogSink::send()
@ 0x7f89304f7f06 google::LogMessage::SendToLog()
@ 0x7f89304f35af google::LogMessage::Flush()
@ 0x7f89304f3739 google::LogMessage::~LogMessage()
@ 0x408cf4 TestLogSinkWaitTillSent()
@ 0x4115de main
@ 0x7f892f7ef1c4 (unknown)
@ 0x4046f9 (unknown)
## Customizing Handler Output
By default, the signal handler writes the failure dump to the standard error.
However, it is possible to customize the destination by installing a callback
using the `#!cpp google::InstallFailureWriter()` function. The function expects
a pointer to a function with the following signature:
``` cpp
void YourFailureWriter(const char* message/* (1)! */, std::size_t length/* (2)! */);
```
1. The pointer references the start of the failure message.
!!! danger
The string is **not null-terminated**.
2. The message length in characters.
!!! warning "Possible overflow errors"
Users should not expect the `message` string to be null-terminated.
## User-defined Failure Function
`FATAL` severity level messages or unsatisfied `CHECK` condition
terminate your program. You can change the behavior of the termination
by `google::InstallFailureFunction`.
``` cpp
void YourFailureFunction() {
// Reports something...
exit(EXIT_FAILURE);
}
int main(int argc, char* argv[]) {
google::InstallFailureFunction(&YourFailureFunction);
}
```
By default, glog tries to dump the stacktrace and calls `#!cpp std::abort`. The
stacktrace is generated only when running the application on a system
supported[^1] by glog.
[^1]: To extract the stack trace, glog currently supports the following targets:
* x86, x86_64,
* PowerPC architectures,
* `libunwind`,
* and the Debug Help Library (`dbghelp`) on Windows.

View File

@ -1,93 +0,0 @@
# Adjusting Output
Several flags influence glog's output behavior.
## Using Command-line Parameters and Environment Variables
If the [Google gflags
library](https://github.com/gflags/gflags) is installed on your machine,
the build system will automatically detect and use it, allowing you to
pass flags on the command line.
!!! example "Activate `--logtostderr` in an application from the command line"
A binary `you_application` that uses glog can be started using
``` bash
./your_application --logtostderr=1
```
to log to `stderr` instead of writing the output to a log file.
!!! tip
You can set boolean flags to `true` by specifying `1`, `true`, or `yes`. To
set boolean flags to `false`, specify `0`, `false`, or `no`. In either case
the spelling is case-insensitive.
If the Google gflags library isn't installed, you set flags via
environment variables, prefixing the flag name with `GLOG_`, e.g.,
!!! example "Activate `logtostderr` without gflags"
``` bash
GLOG_logtostderr=1 ./your_application
```
The following flags are most commonly used:
`logtostderr` (`bool`, default=`false`)
: Log messages to `stderr` instead of logfiles.
`stderrthreshold` (`int`, default=2, which is `ERROR`)
: Copy log messages at or above this level to `stderr` in addition to
logfiles. The numbers of severity levels `INFO`, `WARNING`, `ERROR`,
and `FATAL` are 0, 1, 2, and 3, respectively.
`minloglevel` (`int`, default=0, which is `INFO`)
: Log messages at or above this level. Again, the numbers of severity
levels `INFO`, `WARNING`, `ERROR`, and `FATAL` are 0, 1, 2, and 3,
respectively.
`log_dir` (`string`, default="")
: If specified, logfiles are written into this directory instead of
the default logging directory.
`v` (`int`, default=0)
: Show all `#!cpp VLOG(m)` messages for `m` less or equal the value of this
flag. Overridable by `#!bash --vmodule`. Refer to [verbose
logging](logging.md#verbose-logging) for more detail.
`vmodule` (`string`, default="")
: Per-module verbose level. The argument has to contain a
comma-separated list of `<module name>=<log level>`. `<module name>` is a
glob pattern (e.g., `gfs*` for all modules whose name starts with "gfs"),
matched against the filename base (that is, name ignoring .cc/.h./-inl.h).
`<log level>` overrides any value given by `--v`. See also [verbose
logging](logging.md#verbose-logging) for more details.
Additional flags are defined in
[flags.cc](https://github.com/google/glog/blob/master/src/flags.cc). Please see
the source for their complete list.
## Modifying Flags Programmatically
You can also modify flag values in your program by modifying global variables
`FLAGS_*`. Most settings start working immediately after you update `FLAGS_*`.
The exceptions are the flags related to destination files. For instance, you
might want to set `FLAGS_log_dir` before calling `google::InitGoogleLogging`.
!!! example "Setting `log_dir` at runtime"
``` cpp
LOG(INFO) << "file";
// Most flags work immediately after updating values.
FLAGS_logtostderr = 1;
LOG(INFO) << "stderr";
FLAGS_logtostderr = 0;
// This wont change the log destination. If you want to set this
// value, you should do this before google::InitGoogleLogging .
FLAGS_log_dir = "/some/log/directory";
LOG(INFO) << "the same file";
```

View File

@ -1,30 +0,0 @@
# Google Logging Library
Google Logging (glog) is a C++14 library that implements application-level
logging. The library provides logging APIs based on C++-style streams and
various helper macros.
# How to Use
You can log a message by simply streaming things to `LOG`(<a particular
[severity level](logging.md#severity-levels)\>), e.g.,
``` cpp title="main.cpp"
#include <glog/logging.h>
int main(int argc, char* argv[]) {
google::InitGoogleLogging(argv[0]); // (1)!
LOG(INFO) << "Found " << num_cookies << " cookies"; // (2)!
}
```
1. Initialize the Google Logging Library
2. Log a message with informational severity
The library can be installed using various [package managers](packages.md) or
compiled [from source](build.md). For a detailed overview of glog features and
their usage, please refer to the [user guide](logging.md).
!!! warning
The above example requires further [Bazel](build.md#bazel) or
[CMake](usage.md) setup for use in own projects.

View File

@ -1,3 +0,0 @@
# The 3-Clause BSD License
--8<-- "LICENSE.md"

View File

@ -1,24 +0,0 @@
# Automatically Remove Old Logs
To enable the log cleaner:
``` cpp
using namespace std::chrono_literals;
google::EnableLogCleaner(24h * 3); // keep your logs for 3 days
```
In C++20 (and later) this can be shortened to:
``` cpp
using namespace std::chrono_literals;
google::EnableLogCleaner(3d); // keep your logs for 3 days
```
And then glog will check if there are overdue logs whenever a flush is
performed. In this example, any log file from your project whose last
modified time is greater than 3 days will be `unlink`()ed.
This feature can be disabled at any time (if it has been enabled) using
``` cpp
google::DisableLogCleaner();
```

View File

@ -1,20 +0,0 @@
# Strip Logging Messages
Strings used in log messages can increase the size of your binary and
present a privacy concern. You can therefore instruct glog to remove all
strings which fall below a certain severity level by using the
`GOOGLE_STRIP_LOG` macro:
If your application has code like this:
``` cpp
#define GOOGLE_STRIP_LOG 1 // this must go before the #include!
#include <glog/logging.h>
```
The compiler will remove the log messages whose severities are less than
the specified integer value. Since `VLOG` logs at the severity level
`INFO` (numeric value `0`), setting `GOOGLE_STRIP_LOG` to 1 or greater
removes all log messages associated with `VLOG`s as well as `INFO` log
statements.

View File

@ -1,424 +0,0 @@
# Logging
glog defines a series of macros that simplify many common logging tasks. You can
log messages by [severity level](#severity-levels), [control logging](flags.md)
behavior from the command line, log based on
[conditionals](#conditional-occasional-logging), abort the program when
[expected conditions](#runtime-checks) are not met, introduce your [own logging
levels](#verbose-logging), [customize the prefix](#format-customization)
attached to log messages, and more.
## Severity Levels
You can specify one of the following severity levels (in increasing order of
severity):
1. `INFO`,
2. `WARNING`,
3. `ERROR`, and
4. `FATAL`.
Logging a `FATAL` message terminates the program (after the message is logged).
!!! note
Messages of a given severity are logged not only to corresponding severity
logfile but also to other logfiles of lower severity. For instance, a
message of severity `FATAL` will be logged to logfiles of severity `FATAL`,
`ERROR`, `WARNING`, and `INFO`.
The `DFATAL` severity logs a `FATAL` error in [debug mode](#debugging-support)
(i.e., there is no `NDEBUG` macro defined), but avoids halting the program in
production by automatically reducing the severity to `ERROR`.
## Log Files
Unless otherwise specified, glog uses the format
<tmp>/<program name>.<hostname>.<user name>.log.<severity level>.<date>-<time>.<pid>
for log filenames written to a directory designated as `<tmp>` and
determined according to the following rules.
**Windows**
: glog uses the
[GetTempPathA](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-gettemppatha)
API function to retrieve the directory for temporary files with a
fallback to
1. `C:\TMP\`
2. `C:\TEMP\`
(in the order given.)
**non-Windows**
: The directory is determined by referencing the environment variables
1. `TMPDIR`
2. `TMP`
if set with a fallback to `/tmp/`.
The default path to a log file on Linux, for instance, could be
/tmp/hello_world.example.com.hamaji.log.INFO.20080709-222411.10474
By default, glog echos `ERROR` and `FATAL` messages to standard error in
addition to log files.
## Log Line Prefix Format
Log lines have this form:
Lyyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg...
where the fields are defined as follows:
| Placeholder | Meaning |
| ------------------- | ----------------------------------------------------------------------|
| `L` | A single character, representing the log level (e.g., `I` for `INFO`) |
| `yyyy` | The year |
| `mm` | The month (zero padded; i.e., May is `05`) |
| `dd` | The day (zero padded) |
| `hh:mm:ss.uuuuuu` | Time in hours, minutes and fractional seconds |
| `threadid` | The space-padded thread ID |
| `file` | The file name |
| `line` | The line number |
| `msg` | The user-supplied message |
!!! example "Default log line prefix format"
```
I1103 11:57:31.739339 24395 google.cc:2341] Command line: ./some_prog
I1103 11:57:31.739403 24395 google.cc:2342] Process id 24395
```
!!! note
Although microseconds are useful for comparing events on a single machine,
clocks on different machines may not be well synchronized. Hence, use with
caution when comparing the low bits of timestamps from different machines.
### Format Customization
The predefined log line prefix can be replaced using a user-provided callback
that formats the corresponding output.
For each log entry, the callback will be invoked with a reference to a
`google::LogMessage` instance containing the severity, filename, line
number, thread ID, and time of the event. It will also be given a
reference to the output stream, whose contents will be prepended to the actual
message in the final log line.
To enable the use of a prefix formatter, use the
``` cpp
google::InstallPrefixFormatter(&MyPrefixFormatter);
```
function to pass a pointer to the corresponding `MyPrefixFormatter` callback
during initialization. `InstallPrefixFormatter` takes a second optional argument
of type `#!cpp void*` that allows supplying user data to the callback.
!!! example "Custom prefix formatter"
The following function outputs a prefix that matches glog's default format.
The third parameter `data` can be used to access user-supplied data which
unless specified defaults to `#!cpp nullptr`.
``` cpp
void MyPrefixFormatter(std::ostream& s, const google::LogMessage& m, void* /*data*/) {
s << google::GetLogSeverityName(m.severity())[0]
<< setw(4) << 1900 + m.time().year()
<< setw(2) << 1 + m.time().month()
<< setw(2) << m.time().day()
<< ' '
<< setw(2) << m.time().hour() << ':'
<< setw(2) << m.time().min() << ':'
<< setw(2) << m.time().sec() << "."
<< setw(6) << m.time().usec()
<< ' '
<< setfill(' ') << setw(5)
<< m.thread_id() << setfill('0')
<< ' '
<< m.basename() << ':' << m.line() << "]";
}
```
## Conditional / Occasional Logging
Sometimes, you may only want to log a message under certain conditions.
You can use the following macros to perform conditional logging:
``` cpp
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
```
The "Got lots of cookies" message is logged only when the variable
`num_cookies` exceeds 10. If a line of code is executed many times, it may be
useful to only log a message at certain intervals. This kind of logging is most
useful for informational messages.
``` cpp
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
```
The above line outputs a log messages on the 1st, 11th, 21st, ... times
it is executed.
!!! note
The placeholder `#!cpp google::COUNTER` identifies the recurring repetition.
You can combine conditional and occasional logging with the following
macro.
``` cpp
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
<< "th big cookie";
```
Instead of outputting a message every nth time, you can also limit the
output to the first n occurrences:
``` cpp
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
```
Outputs log messages for the first 20 times it is executed. The `#!cpp
google::COUNTER` identifier indicates which repetition is happening.
Other times, it is desired to only log a message periodically based on a
time. For instance, to log a message every 10ms:
``` cpp
LOG_EVERY_T(INFO, 0.01) << "Got a cookie";
```
Or every 2.35s:
``` cpp
LOG_EVERY_T(INFO, 2.35) << "Got a cookie";
```
## Verbose Logging
When you are chasing difficult bugs, thorough log messages are very
useful. However, you may want to ignore too verbose messages in usual
development. For such verbose logging, glog provides the `VLOG` macro, which
allows you to define your own numeric logging levels.
The `#!bash --v` command line option controls which verbose messages are logged:
``` cpp
VLOG(1) << "Im printed when you run the program with --v=1 or higher";
VLOG(2) << "Im printed when you run the program with --v=2 or higher";
```
With `VLOG`, the lower the verbose level, the more likely messages are to be
logged. For example, if `#!bash --v==1`, `#!cpp VLOG(1)` will log, but `#!cpp
VLOG(2)` will not log.
!!! warning
The `VLOG` behavior is opposite of the severity level logging, where
`INFO`, `ERROR`, etc. are defined in increasing order and thus
`#!bash --minloglevel` of 1 will only log `WARNING` and above.
Though you can specify any integers for both `VLOG` macro and `--v` flag, the
common values for them are small positive integers. For example, if you write
`#!cpp VLOG(0)`, you should specify `--v=-1` or lower to silence it. This is less
useful since we may not want verbose logs by default in most cases. The `VLOG`
macros always log at the `INFO` log level (when they log at all).
Verbose logging can be controlled from the command line on a per-module basis:
``` bash
--vmodule=mapreduce=2,file=1,gfs*=3 --v=0
```
Specifying these options will specifically:
1. Print `#!cpp VLOG(2)` and lower messages from mapreduce.{h,cc}
2. Print `#!cpp VLOG(1)` and lower messages from file.{h,cc}
3. Print `#!cpp VLOG(3)` and lower messages from files prefixed with "gfs"
4. Print `#!cpp VLOG(0)` and lower messages from elsewhere
The wildcarding functionality 3. supports both `*` (matches 0 or more
characters) and `?` (matches any single character) wildcards. Please also refer
to [command line flags](flags.md) for more information.
There's also `#!cpp VLOG_IS_ON(n)` "verbose level" condition macro. This macro
returns `#!cpp true` when the `--v` is equal to or greater than `n`. The macro can be
used as follows:
``` cpp
if (VLOG_IS_ON(2)) {
// (1)
}
```
1. Here we can perform some logging preparation and logging that cant be
accomplished with just `#!cpp VLOG(2) << "message ...";`
Verbose level condition macros `VLOG_IF`, `VLOG_EVERY_N` and `VLOG_IF_EVERY_N`
behave analogous to `LOG_IF`, `LOG_EVERY_N`, `LOG_IF_EVERY_N`, but accept a
numeric verbosity level as opposed to a severity level.
``` cpp
VLOG_IF(1, (size > 1024))
<< "Im printed when size is more than 1024 and when you run the "
"program with --v=1 or more";
VLOG_EVERY_N(1, 10)
<< "Im printed every 10th occurrence, and when you run the program "
"with --v=1 or more. Present occurrence is " << google::COUNTER;
VLOG_IF_EVERY_N(1, (size > 1024), 10)
<< "Im printed on every 10th occurrence of case when size is more "
" than 1024, when you run the program with --v=1 or more. ";
"Present occurrence is " << google::COUNTER;
```
!!! info "Performance"
The conditional logging macros provided by glog (e.g., `CHECK`, `LOG_IF`,
`VLOG`, etc.) are carefully implemented and don't execute the right hand
side expressions when the conditions are false. So, the following check may
not sacrifice the performance of your application.
``` cpp
CHECK(obj.ok) << obj.CreatePrettyFormattedStringButVerySlow();
```
## Debugging Support
Special debug mode logging macros only have an effect in debug mode and are
compiled away to nothing for non-debug mode compiles. Use these macros to avoid
slowing down your production application due to excessive logging.
``` cpp
DLOG(INFO) << "Found cookies";
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
DLOG_FIRST_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
DLOG_EVERY_T(INFO, 0.01) << "Got a cookie";
```
## Runtime Checks
It is a good practice to check expected conditions in your program
frequently to detect errors as early as possible. The `CHECK` macro
provides the ability to abort the application when a condition is not met,
similar to the `assert` macro defined in the standard C library.
`CHECK` aborts the application if a condition is not true. Unlike
`assert`, it is **not** controlled by `NDEBUG`, so the check will be executed
regardless of compilation mode. Therefore, `fp->Write(x)` in the following
example is always executed:
``` cpp
CHECK(fp->Write(x) == 4) << "Write failed!";
```
There are various helper macros for equality/inequality checks
-`CHECK_EQ`, `CHECK_NE`, `CHECK_LE`, `CHECK_LT`, `CHECK_GE`, and
`CHECK_GT`. They compare two values, and log a `FATAL` message including the two
values when the result is not as expected. The values must have
`#!cpp operator<<(ostream, ...)` defined.
You may append to the error message like so:
``` cpp
CHECK_NE(1, 2) << ": The world must be ending!";
```
We are very careful to ensure that each argument is evaluated exactly
once, and that anything which is legal to pass as a function argument is legal
here. In particular, the arguments may be temporary expressions which will end
up being destroyed at the end of the apparent statement, for example:
``` cpp
CHECK_EQ(string("abc")[1], b);
```
The compiler reports an error if one of the arguments is a pointer and the other
is `#!cpp nullptr`. To work around this, simply `#!cpp static_cast` `#!cpp
nullptr` to the type of the desired pointer.
``` cpp
CHECK_EQ(some_ptr, static_cast<SomeType*>(nullptr));
```
Better yet, use the `CHECK_NOTNULL` macro:
``` cpp
CHECK_NOTNULL(some_ptr);
some_ptr->DoSomething();
```
Since this macro returns the given pointer, this is very useful in
constructor initializer lists.
``` cpp
struct S {
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
Something* ptr_;
};
```
!!! warning
Due to the argument forwarding, `CHECK_NOTNULL` cannot be used to
simultaneously stream an additional custom message. To provide a custom
message, one can use the macro `CHECK_EQ` prior to the failing check.
If you are comparing C strings (`#!cpp char *`), a handy set of macros performs
both case sensitive and insensitive comparisons - `CHECK_STREQ`, `CHECK_STRNE`,
`CHECK_STRCASEEQ`, and `CHECK_STRCASENE`. The `CHECK_*CASE*` macro variants are
case-insensitive. You can safely pass `#!cpp nullptr` pointers to this macro.
They treat `#!cpp nullptr` and any non-`#!cpp nullptr` string as not equal. Two
`#!cpp nullptr`s are equal.
!!! note
Both arguments may be temporary objects which are destructed at the
end of the current *full expression*, such as
``` cpp
CHECK_STREQ(Foo().c_str(), Bar().c_str());
```
where `Foo` and `Bar` return `std::string`.
The `CHECK_DOUBLE_EQ` macro checks the equality of two floating point values,
accepting a small error margin. `CHECK_NEAR` accepts a third floating point
argument, which specifies the acceptable error margin.
## Raw Logging
The header file `<glog/raw_logging.h>` can be used for thread-safe logging,
which does not allocate any memory or acquire any locks. Therefore, the macros
defined in this header file can be used by low-level memory allocation and
synchronization code. Please check
[src/glog/raw_logging.h](https://github.com/google/glog/blob/master/src/glog/raw_logging.h)
for detail.
## Google Style `perror()`
`PLOG()` and `PLOG_IF()` and `PCHECK()` behave exactly like their `LOG*` and
`CHECK` equivalents with the addition that they append a description of the
current state of `errno` to their output lines. E.g.
``` cpp
PCHECK(write(1, nullptr, 2) >= 0) << "Write nullptr failed";
```
This check fails with the following error message.
F0825 185142 test.cc:22] Check failed: write(1, nullptr, 2) >= 0 Write nullptr failed: Bad address [14]
## Syslog
`SYSLOG`, `SYSLOG_IF`, and `SYSLOG_EVERY_N` macros are available. These log to
syslog in addition to the normal logs. Be aware that logging to syslog can
drastically impact performance, especially if syslog is configured for remote
logging! Make sure you understand the implications of outputting to syslog
before you use these macros. In general, it's wise to use these macros
sparingly.

View File

@ -1,8 +0,0 @@
{% extends "base.html" %}
{% block outdated %}
You're not viewing the latest version.
<a href="{{ '../' ~ base_url }}">
<strong>Click here to go to latest.</strong>
</a>
{% endblock %}

View File

@ -1,34 +0,0 @@
# Installation using Package Managers
## conan
You can download and install glog using the [conan](https://conan.io)
package manager:
``` bash
pip install conan
conan install -r conancenter glog/<glog-version>@
```
The glog recipe in conan center is kept up to date by conan center index
community contributors. If the version is out of date, please create an
issue or pull request on the
[conan-center-index](https://github.com/conan-io/conan-center-index)
repository.
## vcpkg
You can download and install glog using the
[vcpkg](https://github.com/Microsoft/vcpkg) dependency manager:
``` bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install glog
```
The glog port in vcpkg is kept up to date by Microsoft team members and
community contributors. If the version is out of date, please create an
issue or pull request on the vcpkg repository.

View File

@ -1,6 +0,0 @@
mike>=2.1.1
mkdocs-git-committers-plugin-2>=2.3.0
mkdocs-git-revision-date-localized-plugin>=1.2.6
mkdocs-material-extensions>=1.3.1
mkdocs-material>=9.5.26
mkdocs>=1.6.0

View File

@ -1,84 +0,0 @@
# Custom Sinks
Under certain circumstances, it is useful to send the log output to a
destination other than a file, `stderr` and/or `stdout`. In case, the library
provides the `#!cpp google::LogSink` interface whose implementations can be used
to write the log output to arbitrary locations.
## Basic Interface
The sink interface is defined as follows:
``` cpp
class LogSink {
public:
virtual void send(LogSeverity severity, const char* full_filename,
const char* base_filename, int line,
const LogMessageTime& time, const char* message,
size_t message_len);
};
```
The user must implement `#!cpp google::LogSink::send`, which is called by the
library every time a message is logged.
!!! warning "Possible deadlock due to nested logging"
This method can't use `LOG()` or `CHECK()` as logging system mutex(s) are
held during this call.
## Registering Log Sinks
To use the custom sink and instance of the above interface implementation must
be registered using `google::AddLogSink` which expects a pointer to the
`google::LogSink` instance. To unregister use `google::RemoveLogSink`. Both
functions are thread-safe.
!!! danger "`LogSink` ownership"
The `google::LogSink` instance must not be destroyed until the referencing
pointer is unregistered.
## Direct Logging
Instead of registering the sink, we can directly use to log messages. While `#!
LOG_TO_SINK(sink, severity)` allows to log both to the sink and to a global log
registry, e.g., a file, `#!cpp LOG_TO_SINK_BUT_NOT_TO_LOGFILE(sink, severity)`
will avoid the latter.
!!! example "Using a custom sink"
``` cpp title="custom_sink.cc"
-8<- "examples/custom_sink.cc:33:"
```
1. `MySink` implements a custom sink that sends log messages to `std::cout`.
2. The custom sink must be registered to for use with existing logging
macros.
3. Once the custom sink is no longer needed we remove it from the registry.
4. A sink does not need to be registered globally. However, then, messages
must be logged using dedicated macros.
Running the above example as `#!bash GLOG_log_dir=. ./custom_sink_example`
will produce
<div class="annotate" markdown>
``` title="Custom sink output"
INFO custom_sink.cc:63 logging to MySink
INFO custom_sink.cc:68 direct logging
INFO custom_sink.cc:69 direct logging but not to file (1)
```
</div>
1. This line is not present in the log file because we used
`LOG_TO_SINK_BUT_NOT_TO_LOGFILE` to log the message.
and the corresponding log file will contain
``` title="Log file generated with the custom sink"
Log file created at: 2024/06/11 13:24:27
Running on machine: pc
Running duration (h:mm:ss): 0:00:00
Log line format: [IWEF]yyyymmdd hh:mm:ss.uuuuuu threadid file:line] msg
I20240611 13:24:27.476620 126237946035776 custom_sink.cc:63] logging to MySink
I20240611 13:24:27.476796 126237946035776 custom_sink.cc:68] direct logging
```

View File

@ -1,57 +0,0 @@
# Installation Notes for 64-bit Linux Systems
!!! note
The description on this page is possibly not up-to-date.
The [glibc built-in stack-unwinder](#glibc-built-in-stack-unwinder) on 64-bit
systems has some problems with glog. In particular, if you are using
[`InstallFailureSignalHandler()`](failures.md), the signal may be raised in the
middle of `malloc`, holding some `malloc`-related locks when they invoke the
stack unwinder. The built-in stack unwinder may call `malloc` recursively, which
may require the thread to acquire a lock it already holds resulting in a
deadlock.
## Recommended Approach: `libunwind`
For above reason, if you use a 64-bit system and you need
`InstallFailureSignalHandler()`, we strongly recommend you install `libunwind`
before trying to configure or install google glog. libunwind can be found
[here](http://download.savannah.nongnu.org/releases/libunwind/libunwind-snap-070410.tar.gz).
Even if you already have `libunwind` installed, you will probably still need to
install from the snapshot to get the latest version.
!!! warning
If you install libunwind from the URL above, be aware that you may have
trouble if you try to statically link your binary with glog: that is, if you
link with `gcc -static -lgcc_eh ...`. This is because both `libunwind` and
`libgcc` implement the same C++ exception handling APIs, but they implement
them differently on some platforms. This is not likely to be a problem on
ia64, but may be on x86-64.
Also, if you link binaries statically, make sure that you add
`-Wl,--eh-frame-hdr` to your linker options. This is required so that
`libunwind` can find the information generated by the compiler required for
stack unwinding.
Using `-static` is rare, though, so unless you know this will affect you it
probably won't.
## Alternative Stack-unwinder
If you cannot or do not wish to install `libunwind`, you can still try to use
two kinds of stack-unwinder:
### glibc Built-in Stack-unwinder
As we already mentioned, glibc's unwinder has a deadlock issue. However, if you
don't use `InstallFailureSignalHandler()` or you don't worry about the rare
possibilities of deadlocks, you can use this stack-unwinder. If you specify no
options and `libunwind` isn't detected on your system, the configure script
chooses this unwinder by default.
### Frame Pointer based Stack-unwinder
The frame pointer based stack unwinder requires that your application, the glog
library, and system libraries like libc, all be compiled with a frame pointer.
This is *not* the default for x86-64.

View File

@ -1,24 +0,0 @@
# Using glog in a CMake Project
Assuming that glog was previously [built using CMake](build.md#cmake) or
installed using a package manager, you can use the CMake command `#!cmake
find_package` to build against glog in your CMake project as follows:
``` cmake title="CMakeLists.txt"
cmake_minimum_required (VERSION 3.16)
project (myproj VERSION 1.0)
find_package (glog 0.8.0 REQUIRED)
add_executable (myapp main.cpp)
target_link_libraries (myapp glog::glog)
```
Compile definitions and options will be added automatically to your target as
needed.
Alternatively, glog can be incorporated into using the CMake command `#!cmake
add_subdirectory` to include glog directly from a subdirectory of your project
by replacing the `#!cmake find_package` call from the previous snippet by
`add_subdirectory`. The `#!cmake glog::glog` target is in this case an `#!cmake
ALIAS` library target for the `glog` library target.

View File

@ -1,44 +0,0 @@
# Notes for Windows Users
glog defines the severity level `ERROR`, which is also defined by `windows.h`.
You can make glog not define `INFO`, `WARNING`, `ERROR`, and `FATAL` by defining
`GLOG_NO_ABBREVIATED_SEVERITIES` before including `glog/logging.h`. Even with
this macro, you can still use the iostream like logging facilities:
``` cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
LOG(ERROR) << "This should work";
LOG_IF(ERROR, x > y) << "This should be also OK";
```
However, you cannot use `INFO`, `WARNING`, `ERROR`, and `FATAL` anymore for
functions defined in `glog/logging.h`.
``` cpp
#define GLOG_NO_ABBREVIATED_SEVERITIES
#include <windows.h>
#include <glog/logging.h>
// ...
// This wont work.
// google::FlushLogFiles(google::ERROR);
// Use this instead.
google::FlushLogFiles(google::GLOG_ERROR);
```
If you don't need `ERROR` defined by `windows.h`, there are a couple of more
workarounds which sometimes don't work[^1]:
- `#!cpp #define WIN32_LEAN_AND_MEAN` or `NOGDI` **before**
`#!cpp #include <windows.h>`.
- `#!cpp #undef ERROR` **after** `#!cpp #include <windows.h>`.
[^1]: For more information refer to [this
issue](http://code.google.com/p/google-glog/issues/detail?id=33).

View File

@ -1,71 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
//
#include <glog/logging.h>
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <iterator>
namespace {
struct MyLogSink : google::LogSink { // (1)!
void send(google::LogSeverity severity, const char* /*full_filename*/,
const char* base_filename, int line,
const google::LogMessageTime& /*time*/, const char* message,
std::size_t message_len) override {
std::cout << google::GetLogSeverityName(severity) << ' ' << base_filename
<< ':' << line << ' ';
std::copy_n(message, message_len,
std::ostreambuf_iterator<char>{std::cout});
std::cout << '\n';
}
};
} // namespace
int main(int /*argc*/, char** argv) {
google::InitGoogleLogging(argv[0]);
MyLogSink sink;
google::AddLogSink(&sink); // (2)!
LOG(INFO) << "logging to MySink";
google::RemoveLogSink(&sink); // (3)!
// We can directly log to a sink without registering it
LOG_TO_SINK(&sink, INFO) << "direct logging"; // (4)!
LOG_TO_SINK_BUT_NOT_TO_LOGFILE(&sink, INFO)
<< "direct logging but not to file";
}

View File

@ -1,7 +1,6 @@
exclude = src/.*_unittest\.cc exclude = src/.*_unittest\.cc
exclude = src/googletest\.h exclude = src/googletest\.h
exclude = src/mock-log\.h exclude = src/mock-log\.h
exclude-directories = Tests/
exclude-throw-branches = yes exclude-throw-branches = yes
exclude-unreachable-branches = yes exclude-unreachable-branches = yes
filter = .*/glog/.*\.h filter = .*/glog/.*\.h

View File

@ -7,8 +7,6 @@ endif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
include (CMakeFindDependencyMacro) include (CMakeFindDependencyMacro)
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake) include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
find_dependency (Threads)
@gflags_DEPENDENCY@ @gflags_DEPENDENCY@
@Unwind_DEPENDENCY@ @Unwind_DEPENDENCY@

View File

@ -1,123 +0,0 @@
---
site_name: Google Logging Library
site_url: https://google.github.io/glog/
repo_url: https://github.com/google/glog
repo_name: google/glog
edit_uri: edit/master/docs/
copyright: Copyright &copy; 2024 Google Inc. &amp; contributors - <a href="#__consent">Change cookie settings</a>
markdown_extensions:
- admonition
- attr_list
- def_list
- footnotes
- md_in_html
- pymdownx.details
- pymdownx.highlight:
anchor_linenums: true
line_spans: __span
pygments_lang_class: true
- pymdownx.inlinehilite
- pymdownx.snippets:
base_path:
- '.'
check_paths: true
- pymdownx.superfences
- tables
- toc:
permalink: true
theme:
name: material
custom_dir: docs/overrides
icon:
annotation: material/chevron-right-circle
edit: material/pencil
repo: fontawesome/brands/git-alt
view: material/eye
language: en
features:
- content.action.edit
- content.code.annotate
- content.code.copy
- content.code.select
- header.autohide
- navigation.expand
- navigation.instant.preview
- navigation.instant.progress
- navigation.prune
- navigation.indexes
- toc.follow
- navigation.top
- navigation.path
# - navigation.sections
# - navigation.tabs
# - navigation.tabs.sticky
- navigation.tracking
- search.highlight
- search.share
- search.suggest
palette:
# Palette toggle for automatic mode
- media: "(prefers-color-scheme)"
toggle:
icon: material/brightness-auto
name: Switch to light mode
# Palette toggle for light mode
- media: "(prefers-color-scheme: light)"
scheme: default
primary: teal
accent: green
toggle:
icon: material/brightness-7
name: Switch to dark mode
# Palette toggle for dark mode
- media: "(prefers-color-scheme: dark)"
scheme: slate
primary: black
toggle:
icon: material/brightness-4
name: Switch to system preference
plugins:
- git-revision-date-localized:
enable_creation_date: true
- git-committers:
repository: google/glog
branch: master
- privacy
- search
- tags
extra:
version:
alias: true
default:
- dev
- stable
provider: mike
consent:
actions:
- manage
- accept
- reject
title: Cookie consent
description: >-
We use cookies to recognize your repeated visits and preferences, as well
as to measure the effectiveness of our documentation and whether users
find what they're searching for. With your consent, you're helping us to
make our documentation better.
nav:
- Getting Started:
- Overview: index.md
- Usage in CMake Projects: usage.md
- Building from Source: build.md
- Installation using Package Managers: packages.md
- User Guide:
- Logging: logging.md
- Adjusting Output: flags.md
- Custom Sinks: sinks.md
- Failure Handler: failures.md
- Log Removal: log_cleaner.md
- Stripping Log Messages: log_stripping.md
- System-specific Considerations:
- Usage on Windows: windows.md
- Linux Unwinder: unwinder.md
- Contributing: contribute.md
- License: license.md

View File

@ -48,13 +48,12 @@
#ifndef BASE_COMMANDLINEFLAGS_H__ #ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__ #define BASE_COMMANDLINEFLAGS_H__
#include "config.h"
#include <cstdlib> // for getenv #include <cstdlib> // for getenv
#include <cstring> // for memchr #include <cstring> // for memchr
#include <string> #include <string>
#include "config.h" #ifdef HAVE_LIB_GFLAGS
#ifdef GLOG_USE_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
@ -75,22 +74,24 @@
using fL##shorttype::FLAGS_##name using fL##shorttype::FLAGS_##name
// bool specialization // bool specialization
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool) #define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, B, name, bool)
#define DEFINE_bool(name, value, meaning) \ #define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, B, name, value, meaning, bool) DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
// int32 specialization // int32 specialization
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32) #define DECLARE_int32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
#define DEFINE_int32(name, value, meaning) \ #define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32) DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
// uint32 specialization // uint32 specialization
#ifndef DECLARE_uint32 #ifndef DECLARE_uint32
#define DECLARE_uint32(name) \ #define DECLARE_uint32(name) \
DECLARE_VARIABLE(google::uint32, U, name, uint32) DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32)
#endif // DECLARE_uint64 #endif // DECLARE_uint64
#define DEFINE_uint32(name, value, meaning) \ #define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32) DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32)
// Special case for string, because we have to specify the namespace // Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery. // std::string, which doesn't play nicely with our FLAG__namespace hackery.
@ -107,7 +108,7 @@
} \ } \
using fLS::FLAGS_##name using fLS::FLAGS_##name
#endif // GLOG_USE_GFLAGS #endif // HAVE_LIB_GFLAGS
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we // Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
// have GLOG_* environ variables even if we have gflags installed. // have GLOG_* environ variables even if we have gflags installed.
@ -131,7 +132,8 @@
// These macros (could be functions, but I don't want to bother with a .cc // These macros (could be functions, but I don't want to bother with a .cc
// file), make it easier to initialize flags from the environment. // file), make it easier to initialize flags from the environment.
#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname)) #define EnvToString(envname, dflt) \
(!getenv(envname) ? (dflt) : getenv(envname))
#define EnvToBool(envname, dflt) \ #define EnvToBool(envname, dflt) \
(!getenv(envname) ? (dflt) \ (!getenv(envname) ? (dflt) \

View File

@ -36,14 +36,16 @@
class GoogleInitializer { class GoogleInitializer {
public: public:
using void_function = void (*)(); using void_function = void (*)();
GoogleInitializer(const char*, void_function f) { f(); } GoogleInitializer(const char*, void_function f) {
f();
}
}; };
#define REGISTER_MODULE_INITIALIZER(name, body) \ #define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \ namespace { \
static void google_init_module_##name () { body; } \ static void google_init_module_##name () { body; } \
GoogleInitializer google_initializer_module_##name( \ GoogleInitializer google_initializer_module_##name(#name, \
#name, google_init_module_##name); \ google_init_module_##name); \
} }
#endif /* _GOOGLEINIT_H */ #endif /* _GOOGLEINIT_H */

333
src/base/mutex.h Normal file
View File

@ -0,0 +1,333 @@
// Copyright (c) 2007, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// ---
// Author: Craig Silverstein.
//
// A simple mutex wrapper, supporting locks and read-write locks.
// You should assume the locks are *not* re-entrant.
//
// To use: you should define the following macros in your configure.ac:
// ACX_PTHREAD
// AC_RWLOCK
// The latter is defined in ../autoconf.
//
// This class is meant to be internal-only and should be wrapped by an
// internal namespace. Before you use this module, please give the
// name of your internal namespace for this module. Or, if you want
// to expose it, you'll want to move it to the Google namespace. We
// cannot put this class in global namespace because there can be some
// problems when we have multiple versions of Mutex in each shared object.
//
// NOTE: by default, we have #ifdef'ed out the TryLock() method.
// This is for two reasons:
// 1) TryLock() under Windows is a bit annoying (it requires a
// #define to be defined very early).
// 2) TryLock() is broken for NO_THREADS mode, at least in NDEBUG
// mode.
// If you need TryLock(), and either these two caveats are not a
// problem for you, or you're willing to work around them, then
// feel free to #define GMUTEX_TRYLOCK, or to remove the #ifdefs
// in the code below.
//
// CYGWIN NOTE: Cygwin support for rwlock seems to be buggy:
// http://www.cygwin.com/ml/cygwin/2008-12/msg00017.html
// Because of that, we might as well use windows locks for
// cygwin. They seem to be more reliable than the cygwin pthreads layer.
//
// TRICKY IMPLEMENTATION NOTE:
// This class is designed to be safe to use during
// dynamic-initialization -- that is, by global constructors that are
// run before main() starts. The issue in this case is that
// dynamic-initialization happens in an unpredictable order, and it
// could be that someone else's dynamic initializer could call a
// function that tries to acquire this mutex -- but that all happens
// before this mutex's constructor has run. (This can happen even if
// the mutex and the function that uses the mutex are in the same .cc
// file.) Basically, because Mutex does non-trivial work in its
// constructor, it's not, in the naive implementation, safe to use
// before dynamic initialization has run on it.
//
// The solution used here is to pair the actual mutex primitive with a
// bool that is set to true when the mutex is dynamically initialized.
// (Before that it's false.) Then we modify all mutex routines to
// look at the bool, and not try to lock/unlock until the bool makes
// it to true (which happens after the Mutex constructor has run.)
//
// This works because before main() starts -- particularly, during
// dynamic initialization -- there are no threads, so a) it's ok that
// the mutex operations are a no-op, since we don't need locking then
// anyway; and b) we can be quite confident our bool won't change
// state between a call to Lock() and a call to Unlock() (that would
// require a global constructor in one translation unit to call Lock()
// and another global constructor in another translation unit to call
// Unlock() later, which is pretty perverse).
//
// That said, it's tricky, and can conceivably fail; it's safest to
// avoid trying to acquire a mutex in a global constructor, if you
// can. One way it can fail is that a really smart compiler might
// initialize the bool to true at static-initialization time (too
// early) rather than at dynamic-initialization time. To discourage
// that, we set is_safe_ to true in code (not the constructor
// colon-initializer) and set it to true via a function that always
// evaluates to true, but that the compiler can't know always
// evaluates to true. This should be good enough.
#ifndef GOOGLE_MUTEX_H_
#define GOOGLE_MUTEX_H_
#include "config.h" // to figure out pthreads support
#if defined(NO_THREADS)
typedef int MutexType; // to keep a lock-count
#elif defined(_WIN32) || defined(__CYGWIN__)
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN // We only need minimal includes
# endif
# ifdef GMUTEX_TRYLOCK
// We need Windows NT or later for TryEnterCriticalSection(). If you
// don't need that functionality, you can remove these _WIN32_WINNT
// lines, and change TryLock() to assert(0) or something.
# ifndef _WIN32_WINNT
# define _WIN32_WINNT 0x0400
# endif
# endif
// To avoid macro definition of ERROR.
# ifndef NOGDI
# define NOGDI
# endif
// To avoid macro definition of min/max.
# ifndef NOMINMAX
# define NOMINMAX
# endif
# include <windows.h>
typedef CRITICAL_SECTION MutexType;
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
// Needed for pthread_rwlock_*. If it causes problems, you could take it
// out, but then you'd have to unset HAVE_RWLOCK (at least on linux -- it
// *does* cause problems for FreeBSD, or MacOSX, but isn't needed
// for locking there.)
# ifdef __linux__
# ifndef _XOPEN_SOURCE // Some other header might have already set it for us.
# define _XOPEN_SOURCE 500 // may be needed to get the rwlock calls
# endif
# endif
# include <pthread.h>
using MutexType = pthread_rwlock_t;
#elif defined(HAVE_PTHREAD)
# include <pthread.h>
typedef pthread_mutex_t MutexType;
#else
# error Need to implement mutex.h for your architecture, or #define NO_THREADS
#endif
// We need to include these header files after defining _XOPEN_SOURCE
// as they may define the _XOPEN_SOURCE macro.
#include <cassert>
#include <cstdlib> // for abort()
#define MUTEX_NAMESPACE glog_internal_namespace_
namespace MUTEX_NAMESPACE {
class Mutex {
public:
// Create a Mutex that is not held by anybody. This constructor is
// typically used for Mutexes allocated on the heap or the stack.
// See below for a recommendation for constructing global Mutex
// objects.
inline Mutex();
// Destructor
inline ~Mutex();
inline void Lock(); // Block if needed until free then acquire exclusively
inline void Unlock(); // Release a lock acquired via Lock()
#ifdef GMUTEX_TRYLOCK
inline bool TryLock(); // If free, Lock() and return true, else return false
#endif
// Note that on systems that don't support read-write locks, these may
// be implemented as synonyms to Lock() and Unlock(). So you can use
// these for efficiency, but don't use them anyplace where being able
// to do shared reads is necessary to avoid deadlock.
inline void ReaderLock(); // Block until free or shared then acquire a share
inline void ReaderUnlock(); // Release a read share of this Mutex
inline void WriterLock() { Lock(); } // Acquire an exclusive lock
inline void WriterUnlock() { Unlock(); } // Release a lock from WriterLock()
// TODO(hamaji): Do nothing, implement correctly.
inline void AssertHeld() {}
private:
MutexType mutex_;
// We want to make sure that the compiler sets is_safe_ to true only
// when we tell it to, and never makes assumptions is_safe_ is
// always true. volatile is the most reliable way to do that.
volatile bool is_safe_;
inline void SetIsSafe() { is_safe_ = true; }
// Catch the error of writing Mutex when intending MutexLock.
explicit Mutex(Mutex * /*ignored*/) {}
// Disallow "evil" constructors
Mutex(const Mutex &) = delete;
void operator=(const Mutex &) = delete;
};
// Now the implementation of Mutex for various systems
#if defined(NO_THREADS)
// When we don't have threads, we can be either reading or writing,
// but not both. We can have lots of readers at once (in no-threads
// mode, that's most likely to happen in recursive function calls),
// but only one writer. We represent this by having mutex_ be -1 when
// writing and a number > 0 when reading (and 0 when no lock is held).
//
// In debug mode, we assert these invariants, while in non-debug mode
// we do nothing, for efficiency. That's why everything is in an
// assert.
Mutex::Mutex() : mutex_(0) { }
Mutex::~Mutex() { assert(mutex_ == 0); }
void Mutex::Lock() { assert(--mutex_ == -1); }
void Mutex::Unlock() { assert(mutex_++ == -1); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { if (mutex_) return false; Lock(); return true; }
#endif
void Mutex::ReaderLock() { assert(++mutex_ > 0); }
void Mutex::ReaderUnlock() { assert(mutex_-- > 0); }
#elif defined(_WIN32) || defined(__CYGWIN__)
Mutex::Mutex() { InitializeCriticalSection(&mutex_); SetIsSafe(); }
Mutex::~Mutex() { DeleteCriticalSection(&mutex_); }
void Mutex::Lock() { if (is_safe_) EnterCriticalSection(&mutex_); }
void Mutex::Unlock() { if (is_safe_) LeaveCriticalSection(&mutex_); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
TryEnterCriticalSection(&mutex_) != 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); } // we don't have read-write locks
void Mutex::ReaderUnlock() { Unlock(); }
#elif defined(HAVE_PTHREAD) && defined(HAVE_RWLOCK)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_rwlock_init(&mutex_, nullptr) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_rwlock_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_rwlock_wrlock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_rwlock_trywrlock(&mutex_) == 0 :
true; }
#endif
void Mutex::ReaderLock() { SAFE_PTHREAD(pthread_rwlock_rdlock); }
void Mutex::ReaderUnlock() { SAFE_PTHREAD(pthread_rwlock_unlock); }
#undef SAFE_PTHREAD
#elif defined(HAVE_PTHREAD)
#define SAFE_PTHREAD(fncall) do { /* run fncall if is_safe_ is true */ \
if (is_safe_ && fncall(&mutex_) != 0) abort(); \
} while (0)
Mutex::Mutex() {
SetIsSafe();
if (is_safe_ && pthread_mutex_init(&mutex_, nullptr) != 0) abort();
}
Mutex::~Mutex() { SAFE_PTHREAD(pthread_mutex_destroy); }
void Mutex::Lock() { SAFE_PTHREAD(pthread_mutex_lock); }
void Mutex::Unlock() { SAFE_PTHREAD(pthread_mutex_unlock); }
#ifdef GMUTEX_TRYLOCK
bool Mutex::TryLock() { return is_safe_ ?
pthread_mutex_trylock(&mutex_) == 0 : true; }
#endif
void Mutex::ReaderLock() { Lock(); }
void Mutex::ReaderUnlock() { Unlock(); }
#undef SAFE_PTHREAD
#endif
// --------------------------------------------------------------------------
// Some helper classes
// MutexLock(mu) acquires mu when constructed and releases it when destroyed.
class MutexLock {
public:
explicit MutexLock(Mutex *mu) : mu_(mu) { mu_->Lock(); }
~MutexLock() { mu_->Unlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
MutexLock(const MutexLock &) = delete;
void operator=(const MutexLock &) = delete;
};
// ReaderMutexLock and WriterMutexLock do the same, for rwlocks
class ReaderMutexLock {
public:
explicit ReaderMutexLock(Mutex *mu) : mu_(mu) { mu_->ReaderLock(); }
~ReaderMutexLock() { mu_->ReaderUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
ReaderMutexLock(const ReaderMutexLock &) = delete;
void operator=(const ReaderMutexLock &) = delete;
};
class WriterMutexLock {
public:
explicit WriterMutexLock(Mutex *mu) : mu_(mu) { mu_->WriterLock(); }
~WriterMutexLock() { mu_->WriterUnlock(); }
private:
Mutex * const mu_;
// Disallow "evil" constructors
WriterMutexLock(const WriterMutexLock &) = delete;
void operator=(const WriterMutexLock &) = delete;
};
// Catch bug where variable name is omitted, e.g. MutexLock (&mu);
#define MutexLock(x) COMPILE_ASSERT(0, mutex_lock_decl_missing_var_name)
#define ReaderMutexLock(x) COMPILE_ASSERT(0, rmutex_lock_decl_missing_var_name)
#define WriterMutexLock(x) COMPILE_ASSERT(0, wmutex_lock_decl_missing_var_name)
} // namespace MUTEX_NAMESPACE
using namespace MUTEX_NAMESPACE;
#undef MUTEX_NAMESPACE
#endif /* #define GOOGLE_MUTEX_H__ */

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2021, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
#include "glog/raw_logging.h" #include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
@ -42,7 +42,7 @@ using namespace GFLAGS_NAMESPACE;
#include "mock-log.h" #include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog; using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -52,12 +52,11 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace google; using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediately, logging) { TEST(CleanImmediately, logging) {
using namespace std::chrono_literals;
google::SetLogFilenameExtension(".foobar"); google::SetLogFilenameExtension(".foobar");
google::EnableLogCleaner(0h); google::EnableLogCleaner(0);
for (unsigned i = 0; i < 1000; ++i) { for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test"; LOG(INFO) << "cleanup test";
@ -69,7 +68,7 @@ TEST(CleanImmediately, logging) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2021, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
#include "glog/raw_logging.h" #include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
@ -42,7 +42,7 @@ using namespace GFLAGS_NAMESPACE;
#include "mock-log.h" #include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog; using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -52,11 +52,10 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace google; using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithAbsolutePrefix, logging) { TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
using namespace std::chrono_literals; google::EnableLogCleaner(0);
google::EnableLogCleaner(0h);
google::SetLogFilenameExtension(".barfoo"); google::SetLogFilenameExtension(".barfoo");
google::SetLogDestination(GLOG_INFO, "test_cleanup_"); google::SetLogDestination(GLOG_INFO, "test_cleanup_");
@ -74,7 +73,7 @@ TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2021, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -32,7 +32,7 @@
#include "glog/raw_logging.h" #include "glog/raw_logging.h"
#include "googletest.h" #include "googletest.h"
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
@ -42,7 +42,7 @@ using namespace GFLAGS_NAMESPACE;
#include "mock-log.h" #include "mock-log.h"
// Introduce several symbols from gmock. // Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog; using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_; using testing::_;
using testing::AllOf; using testing::AllOf;
using testing::AnyNumber; using testing::AnyNumber;
@ -52,11 +52,10 @@ using testing::StrictMock;
using testing::StrNe; using testing::StrNe;
#endif #endif
using namespace google; using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithRelativePrefix, logging) { TEST(CleanImmediatelyWithRelativePrefix, logging) {
using namespace std::chrono_literals; google::EnableLogCleaner(0);
google::EnableLogCleaner(0h);
google::SetLogFilenameExtension(".relativefoo"); google::SetLogFilenameExtension(".relativefoo");
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_"); google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
@ -70,7 +69,7 @@ TEST(CleanImmediatelyWithRelativePrefix, logging) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false; FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true; FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
// Make sure stderr is not buffered as stderr seems to be buffered // Make sure stderr is not buffered as stderr seems to be buffered

View File

@ -1,9 +1,15 @@
#ifndef GLOG_CONFIG_H #ifndef GLOG_CONFIG_H
#define GLOG_CONFIG_H #define GLOG_CONFIG_H
/* Namespace for Google classes */
#cmakedefine GOOGLE_NAMESPACE ${GOOGLE_NAMESPACE}
/* Define if you have the `dladdr' function */ /* Define if you have the `dladdr' function */
#cmakedefine HAVE_DLADDR #cmakedefine HAVE_DLADDR
/* Define if you have the `snprintf' function */
#cmakedefine HAVE_SNPRINTF
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#cmakedefine HAVE_DLFCN_H #cmakedefine HAVE_DLFCN_H
@ -19,6 +25,12 @@
/* Define to 1 if you have the <glob.h> header file. */ /* Define to 1 if you have the <glob.h> header file. */
#cmakedefine HAVE_GLOB_H #cmakedefine HAVE_GLOB_H
/* Define to 1 if you have the `pthread' library (-lpthread). */
#cmakedefine HAVE_LIBPTHREAD
/* define if you have google gflags library */
#cmakedefine HAVE_LIB_GFLAGS
/* define if you have google gmock library */ /* define if you have google gmock library */
#cmakedefine HAVE_LIB_GMOCK #cmakedefine HAVE_LIB_GMOCK
@ -28,11 +40,20 @@
/* define if you have dbghelp library */ /* define if you have dbghelp library */
#cmakedefine HAVE_DBGHELP #cmakedefine HAVE_DBGHELP
/* define if you have libunwind */
#cmakedefine HAVE_LIB_UNWIND
/* Define to 1 if you have the <memory.h> header file. */
#cmakedefine HAVE_MEMORY_H
/* define to disable multithreading support. */
#cmakedefine NO_THREADS
/* Define if you have the 'pread' function */ /* Define if you have the 'pread' function */
#cmakedefine HAVE_PREAD #cmakedefine HAVE_PREAD
/* Define if you have the 'posix_fadvise' function in <fcntl.h> */ /* Define if you have POSIX threads libraries and header files. */
#cmakedefine HAVE_POSIX_FADVISE #cmakedefine HAVE_PTHREAD
/* Define to 1 if you have the <pwd.h> header file. */ /* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H #cmakedefine HAVE_PWD_H
@ -40,26 +61,26 @@
/* Define if you have the 'pwrite' function */ /* Define if you have the 'pwrite' function */
#cmakedefine HAVE_PWRITE #cmakedefine HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
#cmakedefine HAVE_RWLOCK
/* Define if you have the 'sigaction' function */ /* Define if you have the 'sigaction' function */
#cmakedefine HAVE_SIGACTION #cmakedefine HAVE_SIGACTION
/* Define if you have the `sigaltstack' function */ /* Define if you have the `sigaltstack' function */
#cmakedefine HAVE_SIGALTSTACK #cmakedefine HAVE_SIGALTSTACK
/* Define to 1 if you have the <strings.h> header file. */
#cmakedefine HAVE_STRINGS_H
/* Define to 1 if you have the <syscall.h> header file. */ /* Define to 1 if you have the <syscall.h> header file. */
#cmakedefine HAVE_SYSCALL_H #cmakedefine HAVE_SYSCALL_H
/* Define to 1 if you have the <syslog.h> header file. */ /* Define to 1 if you have the <syslog.h> header file. */
#cmakedefine HAVE_SYSLOG_H #cmakedefine HAVE_SYSLOG_H
/* Define to 1 if you have the <elf.h> header file. */ /* Define to 1 if you have the <sys/stat.h> header file. */
#cmakedefine HAVE_ELF_H #cmakedefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/exec_elf.h> header file. */
#cmakedefine HAVE_SYS_EXEC_ELF_H
/* Define to 1 if you have the <link.h> header file. */
#cmakedefine HAVE_LINK_H
/* Define to 1 if you have the <sys/syscall.h> header file. */ /* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H #cmakedefine HAVE_SYS_SYSCALL_H
@ -68,7 +89,7 @@
#cmakedefine HAVE_SYS_TIME_H #cmakedefine HAVE_SYS_TIME_H
/* Define to 1 if you have the <sys/types.h> header file. */ /* Define to 1 if you have the <sys/types.h> header file. */
#cmakedefine HAVE_SYS_TYPES_H #cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
/* Define to 1 if you have the <sys/ucontext.h> header file. */ /* Define to 1 if you have the <sys/ucontext.h> header file. */
#cmakedefine HAVE_SYS_UCONTEXT_H #cmakedefine HAVE_SYS_UCONTEXT_H
@ -85,11 +106,20 @@
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H} #cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* define if you have unwind */ /* Define if you linking to _Unwind_Backtrace is possible. */
#cmakedefine HAVE_UNWIND #cmakedefine HAVE__UNWIND_BACKTRACE
/* define if you have libunwind */ /* Define if you linking to _Unwind_GetIP is possible. */
#cmakedefine HAVE_LIBUNWIND #cmakedefine HAVE__UNWIND_GETIP
/* define if your compiler has __attribute__ */
#cmakedefine HAVE___ATTRIBUTE__
/* define if your compiler has __builtin_expect */
#cmakedefine HAVE___BUILTIN_EXPECT ${HAVE___BUILTIN_EXPECT}
/* define if your compiler has __sync_val_compare_and_swap */
#cmakedefine HAVE___SYNC_VAL_COMPARE_AND_SWAP
/* define if symbolize support is available */ /* define if symbolize support is available */
#cmakedefine HAVE_SYMBOLIZE #cmakedefine HAVE_SYMBOLIZE
@ -103,11 +133,9 @@
/* define if _chsize_s is available in io.h */ /* define if _chsize_s is available in io.h */
#cmakedefine HAVE__CHSIZE_S #cmakedefine HAVE__CHSIZE_S
/* define if ssize_t is defined */ /* Define to the sub-directory in which libtool stores uninstalled libraries.
#cmakedefine HAVE_SSIZE_T */
#cmakedefine LT_OBJDIR
/* define if mode_t is defined */
#cmakedefine HAVE_MODE_T
/* How to access the PC from a struct ucontext */ /* How to access the PC from a struct ucontext */
#cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT} #cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}
@ -115,6 +143,10 @@
/* define if we should print file offsets in traces instead of symbolizing. */ /* define if we should print file offsets in traces instead of symbolizing. */
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES #cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
/* Define to necessary symbol if this constant uses a non-standard name on
your system. */
#cmakedefine PTHREAD_CREATE_JOINABLE
/* The size of `void *', as computed by sizeof. */ /* The size of `void *', as computed by sizeof. */
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P} #cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
@ -124,19 +156,25 @@
/* Define if thread-local storage is enabled. */ /* Define if thread-local storage is enabled. */
#cmakedefine GLOG_THREAD_LOCAL_STORAGE #cmakedefine GLOG_THREAD_LOCAL_STORAGE
/* define if abi::__cxa_demangle is available in cxxabi.h */ #ifdef GLOG_BAZEL_BUILD
#cmakedefine HAVE___CXA_DEMANGLE
/* define if __argv is available in cstdlib */ /* TODO(rodrigoq): remove this workaround once bazel#3979 is resolved:
#cmakedefine HAVE___ARGV * https://github.com/bazelbuild/bazel/issues/3979 */
#define _START_GOOGLE_NAMESPACE_ namespace GOOGLE_NAMESPACE {
/* define if __progname is available */ #define _END_GOOGLE_NAMESPACE_ }
#cmakedefine HAVE___PROGNAME
/* define if getprogname is available in cstdlib */ #else
#cmakedefine HAVE_GETPROGNAME
/* define if program_invocation_short_name is available in cerrno */ /* Stops putting the code inside the Google namespace */
#cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME #cmakedefine _END_GOOGLE_NAMESPACE_ ${_END_GOOGLE_NAMESPACE_}
/* Puts following code inside the Google namespace */
#cmakedefine _START_GOOGLE_NAMESPACE_ ${_START_GOOGLE_NAMESPACE_}
#endif
/* Replacement for deprecated syscall(SYS_gettid) on macOS. */
#cmakedefine HAVE_PTHREAD_THREADID_NP ${HAVE_PTHREAD_THREADID_NP}
#endif // GLOG_CONFIG_H #endif // GLOG_CONFIG_H

View File

@ -1,7 +0,0 @@
cmake_minimum_required (VERSION 3.16)
project (glog_log_severity LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_dcheck glog_dcheck.cc)
target_link_libraries (glog_dcheck PRIVATE glog::glog)

View File

@ -1,53 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main(int /*argc*/, char** argv) {
google::InitGoogleLogging(argv[0]);
google::InstallFailureSignalHandler();
#if defined(_MSC_VER)
// Avoid presenting an interactive dialog that will cause the test to time
// out.
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif // defined(_MSC_VER)
DLOG(INFO) << "no output";
DLOG(WARNING) << "no output";
DLOG(ERROR) << "no output";
// Must not fail in release build
DLOG_ASSERT(false);
// Must be the last expression
DLOG(FATAL) << "no output";
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -36,32 +36,26 @@
#include "demangle.h" #include "demangle.h"
#include <algorithm> #include <cstddef>
#include <cstdlib> #include <cstdio> // for nullptr
#include <limits> #include <limits>
#include "utilities.h" #include "utilities.h"
#if defined(HAVE___CXA_DEMANGLE)
# include <cxxabi.h>
#endif
#if defined(GLOG_OS_WINDOWS) #if defined(GLOG_OS_WINDOWS)
#include <dbghelp.h> #include <dbghelp.h>
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
#if !defined(GLOG_OS_WINDOWS) && !defined(HAVE___CXA_DEMANGLE) #if !defined(GLOG_OS_WINDOWS)
namespace {
struct AbbrevPair { struct AbbrevPair {
const char* const abbrev; const char *abbrev;
const char* const real_name; const char *real_name;
}; };
// List of operators from Itanium C++ ABI. // List of operators from Itanium C++ ABI.
const AbbrevPair kOperatorList[] = { static const AbbrevPair kOperatorList[] = {
{"nw", "new"}, {"na", "new[]"}, {"dl", "delete"}, {"da", "delete[]"}, {"nw", "new"}, {"na", "new[]"}, {"dl", "delete"}, {"da", "delete[]"},
{"ps", "+"}, {"ng", "-"}, {"ad", "&"}, {"de", "*"}, {"ps", "+"}, {"ng", "-"}, {"ad", "&"}, {"de", "*"},
{"co", "~"}, {"pl", "+"}, {"mi", "-"}, {"ml", "*"}, {"co", "~"}, {"pl", "+"}, {"mi", "-"}, {"ml", "*"},
@ -78,7 +72,7 @@ const AbbrevPair kOperatorList[] = {
}; };
// List of builtin types from Itanium C++ ABI. // List of builtin types from Itanium C++ ABI.
const AbbrevPair kBuiltinTypeList[] = { static const AbbrevPair kBuiltinTypeList[] = {
{"v", "void"}, {"w", "wchar_t"}, {"v", "void"}, {"w", "wchar_t"},
{"b", "bool"}, {"c", "char"}, {"b", "bool"}, {"c", "char"},
{"a", "signed char"}, {"h", "unsigned char"}, {"a", "signed char"}, {"h", "unsigned char"},
@ -89,11 +83,10 @@ const AbbrevPair kBuiltinTypeList[] = {
{"n", "__int128"}, {"o", "unsigned __int128"}, {"n", "__int128"}, {"o", "unsigned __int128"},
{"f", "float"}, {"d", "double"}, {"f", "float"}, {"d", "double"},
{"e", "long double"}, {"g", "__float128"}, {"e", "long double"}, {"g", "__float128"},
{"z", "ellipsis"}, {"Dn", "decltype(nullptr)"}, {"z", "ellipsis"}, {nullptr, nullptr}};
{nullptr, nullptr}};
// List of substitutions Itanium C++ ABI. // List of substitutions Itanium C++ ABI.
const AbbrevPair kSubstitutionList[] = { static const AbbrevPair kSubstitutionList[] = {
{"St", ""}, {"St", ""},
{"Sa", "allocator"}, {"Sa", "allocator"},
{"Sb", "basic_string"}, {"Sb", "basic_string"},
@ -125,7 +118,7 @@ struct State {
// We don't use strlen() in libc since it's not guaranteed to be async // We don't use strlen() in libc since it's not guaranteed to be async
// signal safe. // signal safe.
size_t StrLen(const char* str) { static size_t StrLen(const char *str) {
size_t len = 0; size_t len = 0;
while (*str != '\0') { while (*str != '\0') {
++str; ++str;
@ -135,7 +128,7 @@ size_t StrLen(const char* str) {
} }
// Returns true if "str" has at least "n" characters remaining. // Returns true if "str" has at least "n" characters remaining.
bool AtLeastNumCharsRemaining(const char* str, ssize_t n) { static bool AtLeastNumCharsRemaining(const char *str, ssize_t n) {
for (ssize_t i = 0; i < n; ++i) { for (ssize_t i = 0; i < n; ++i) {
if (str[i] == '\0') { if (str[i] == '\0') {
return false; return false;
@ -145,15 +138,17 @@ bool AtLeastNumCharsRemaining(const char* str, ssize_t n) {
} }
// Returns true if "str" has "prefix" as a prefix. // Returns true if "str" has "prefix" as a prefix.
bool StrPrefix(const char* str, const char* prefix) { static bool StrPrefix(const char *str, const char *prefix) {
size_t i = 0; size_t i = 0;
while (str[i] != '\0' && prefix[i] != '\0' && str[i] == prefix[i]) { while (str[i] != '\0' && prefix[i] != '\0' &&
str[i] == prefix[i]) {
++i; ++i;
} }
return prefix[i] == '\0'; // Consumed everything in "prefix". return prefix[i] == '\0'; // Consumed everything in "prefix".
} }
void InitState(State* state, const char* mangled, char* out, size_t out_size) { static void InitState(State *state, const char *mangled,
char *out, size_t out_size) {
state->mangled_cur = mangled; state->mangled_cur = mangled;
state->out_cur = out; state->out_cur = out;
state->out_begin = out; state->out_begin = out;
@ -171,7 +166,7 @@ void InitState(State* state, const char* mangled, char* out, size_t out_size) {
// Returns true and advances "mangled_cur" if we find "one_char_token" // Returns true and advances "mangled_cur" if we find "one_char_token"
// at "mangled_cur" position. It is assumed that "one_char_token" does // at "mangled_cur" position. It is assumed that "one_char_token" does
// not contain '\0'. // not contain '\0'.
bool ParseOneCharToken(State* state, const char one_char_token) { static bool ParseOneCharToken(State *state, const char one_char_token) {
if (state->mangled_cur[0] == one_char_token) { if (state->mangled_cur[0] == one_char_token) {
++state->mangled_cur; ++state->mangled_cur;
return true; return true;
@ -182,7 +177,7 @@ bool ParseOneCharToken(State* state, const char one_char_token) {
// Returns true and advances "mangled_cur" if we find "two_char_token" // Returns true and advances "mangled_cur" if we find "two_char_token"
// at "mangled_cur" position. It is assumed that "two_char_token" does // at "mangled_cur" position. It is assumed that "two_char_token" does
// not contain '\0'. // not contain '\0'.
bool ParseTwoCharToken(State* state, const char* two_char_token) { static bool ParseTwoCharToken(State *state, const char *two_char_token) {
if (state->mangled_cur[0] == two_char_token[0] && if (state->mangled_cur[0] == two_char_token[0] &&
state->mangled_cur[1] == two_char_token[1]) { state->mangled_cur[1] == two_char_token[1]) {
state->mangled_cur += 2; state->mangled_cur += 2;
@ -193,7 +188,7 @@ bool ParseTwoCharToken(State* state, const char* two_char_token) {
// Returns true and advances "mangled_cur" if we find any character in // Returns true and advances "mangled_cur" if we find any character in
// "char_class" at "mangled_cur" position. // "char_class" at "mangled_cur" position.
bool ParseCharClass(State* state, const char* char_class) { static bool ParseCharClass(State *state, const char *char_class) {
const char *p = char_class; const char *p = char_class;
for (; *p != '\0'; ++p) { for (; *p != '\0'; ++p) {
if (state->mangled_cur[0] == *p) { if (state->mangled_cur[0] == *p) {
@ -205,11 +200,13 @@ bool ParseCharClass(State* state, const char* char_class) {
} }
// This function is used for handling an optional non-terminal. // This function is used for handling an optional non-terminal.
bool Optional(bool) { return true; } static bool Optional(bool) {
return true;
}
// This function is used for handling <non-terminal>+ syntax. // This function is used for handling <non-terminal>+ syntax.
using ParseFunc = bool (*)(State *); using ParseFunc = bool (*)(State *);
bool OneOrMore(ParseFunc parse_func, State* state) { static bool OneOrMore(ParseFunc parse_func, State *state) {
if (parse_func(state)) { if (parse_func(state)) {
while (parse_func(state)) { while (parse_func(state)) {
} }
@ -222,7 +219,7 @@ bool OneOrMore(ParseFunc parse_func, State* state) {
// always returns true and must be followed by a termination token or a // always returns true and must be followed by a termination token or a
// terminating sequence not handled by parse_func (e.g. // terminating sequence not handled by parse_func (e.g.
// ParseOneCharToken(state, 'E')). // ParseOneCharToken(state, 'E')).
bool ZeroOrMore(ParseFunc parse_func, State* state) { static bool ZeroOrMore(ParseFunc parse_func, State *state) {
while (parse_func(state)) { while (parse_func(state)) {
} }
return true; return true;
@ -231,7 +228,7 @@ bool ZeroOrMore(ParseFunc parse_func, State* state) {
// Append "str" at "out_cur". If there is an overflow, "overflowed" // Append "str" at "out_cur". If there is an overflow, "overflowed"
// is set to true for later use. The output string is ensured to // is set to true for later use. The output string is ensured to
// always terminate with '\0' as long as there is no overflow. // always terminate with '\0' as long as there is no overflow.
void Append(State* state, const char* const str, ssize_t length) { static void Append(State *state, const char * const str, ssize_t length) {
if (state->out_cur == nullptr) { if (state->out_cur == nullptr) {
state->overflowed = true; state->overflowed = true;
return; return;
@ -251,19 +248,23 @@ void Append(State* state, const char* const str, ssize_t length) {
} }
// We don't use equivalents in libc to avoid locale issues. // We don't use equivalents in libc to avoid locale issues.
bool IsLower(char c) { return c >= 'a' && c <= 'z'; } static bool IsLower(char c) {
return c >= 'a' && c <= 'z';
}
bool IsAlpha(char c) { static bool IsAlpha(char c) {
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
} }
bool IsDigit(char c) { return c >= '0' && c <= '9'; } static bool IsDigit(char c) {
return c >= '0' && c <= '9';
}
// Returns true if "str" is a function clone suffix. These suffixes are used // Returns true if "str" is a function clone suffix. These suffixes are used
// by GCC 4.5.x and later versions to indicate functions which have been // by GCC 4.5.x and later versions to indicate functions which have been
// cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as // cloned during optimization. We treat any sequence (.<alpha>+.<digit>+)+ as
// a function clone suffix. // a function clone suffix.
bool IsFunctionCloneSuffix(const char* str) { static bool IsFunctionCloneSuffix(const char *str) {
size_t i = 0; size_t i = 0;
while (str[i] != '\0') { while (str[i] != '\0') {
// Consume a single .<alpha>+.<digit>+ sequence. // Consume a single .<alpha>+.<digit>+ sequence.
@ -287,7 +288,7 @@ bool IsFunctionCloneSuffix(const char* str) {
// Append "str" with some tweaks, iff "append" state is true. // Append "str" with some tweaks, iff "append" state is true.
// Returns true so that it can be placed in "if" conditions. // Returns true so that it can be placed in "if" conditions.
void MaybeAppendWithLength(State* state, const char* const str, static void MaybeAppendWithLength(State *state, const char * const str,
ssize_t length) { ssize_t length) {
if (state->append && length > 0) { if (state->append && length > 0) {
// Append a space if the output buffer ends with '<' and "str" // Append a space if the output buffer ends with '<' and "str"
@ -306,7 +307,7 @@ void MaybeAppendWithLength(State* state, const char* const str,
} }
// A convenient wrapper around MaybeAppendWithLength(). // A convenient wrapper around MaybeAppendWithLength().
bool MaybeAppend(State* state, const char* const str) { static bool MaybeAppend(State *state, const char * const str) {
if (state->append) { if (state->append) {
size_t length = StrLen(str); size_t length = StrLen(str);
MaybeAppendWithLength(state, str, static_cast<ssize_t>(length)); MaybeAppendWithLength(state, str, static_cast<ssize_t>(length));
@ -315,45 +316,45 @@ bool MaybeAppend(State* state, const char* const str) {
} }
// This function is used for handling nested names. // This function is used for handling nested names.
bool EnterNestedName(State* state) { static bool EnterNestedName(State *state) {
state->nest_level = 0; state->nest_level = 0;
return true; return true;
} }
// This function is used for handling nested names. // This function is used for handling nested names.
bool LeaveNestedName(State* state, short prev_value) { static bool LeaveNestedName(State *state, short prev_value) {
state->nest_level = prev_value; state->nest_level = prev_value;
return true; return true;
} }
// Disable the append mode not to print function parameters, etc. // Disable the append mode not to print function parameters, etc.
bool DisableAppend(State* state) { static bool DisableAppend(State *state) {
state->append = false; state->append = false;
return true; return true;
} }
// Restore the append mode to the previous state. // Restore the append mode to the previous state.
bool RestoreAppend(State* state, bool prev_value) { static bool RestoreAppend(State *state, bool prev_value) {
state->append = prev_value; state->append = prev_value;
return true; return true;
} }
// Increase the nest level for nested names. // Increase the nest level for nested names.
void MaybeIncreaseNestLevel(State* state) { static void MaybeIncreaseNestLevel(State *state) {
if (state->nest_level > -1) { if (state->nest_level > -1) {
++state->nest_level; ++state->nest_level;
} }
} }
// Appends :: for nested names if necessary. // Appends :: for nested names if necessary.
void MaybeAppendSeparator(State* state) { static void MaybeAppendSeparator(State *state) {
if (state->nest_level >= 1) { if (state->nest_level >= 1) {
MaybeAppend(state, "::"); MaybeAppend(state, "::");
} }
} }
// Cancel the last separator if necessary. // Cancel the last separator if necessary.
void MaybeCancelLastSeparator(State* state) { static void MaybeCancelLastSeparator(State *state) {
if (state->nest_level >= 1 && state->append && if (state->nest_level >= 1 && state->append &&
state->out_begin <= state->out_cur - 2) { state->out_begin <= state->out_cur - 2) {
state->out_cur -= 2; state->out_cur -= 2;
@ -363,53 +364,53 @@ void MaybeCancelLastSeparator(State* state) {
// Returns true if the identifier of the given length pointed to by // Returns true if the identifier of the given length pointed to by
// "mangled_cur" is anonymous namespace. // "mangled_cur" is anonymous namespace.
bool IdentifierIsAnonymousNamespace(State* state, ssize_t length) { static bool IdentifierIsAnonymousNamespace(State *state, ssize_t length) {
const char anon_prefix[] = "_GLOBAL__N_"; static const char anon_prefix[] = "_GLOBAL__N_";
return (length > static_cast<ssize_t>(sizeof(anon_prefix)) - return (length > static_cast<ssize_t>(sizeof(anon_prefix)) -
1 && // Should be longer. 1 && // Should be longer.
StrPrefix(state->mangled_cur, anon_prefix)); StrPrefix(state->mangled_cur, anon_prefix));
} }
// Forward declarations of our parsing functions. // Forward declarations of our parsing functions.
bool ParseMangledName(State* state); static bool ParseMangledName(State *state);
bool ParseEncoding(State* state); static bool ParseEncoding(State *state);
bool ParseName(State* state); static bool ParseName(State *state);
bool ParseUnscopedName(State* state); static bool ParseUnscopedName(State *state);
bool ParseUnscopedTemplateName(State* state); static bool ParseUnscopedTemplateName(State *state);
bool ParseNestedName(State* state); static bool ParseNestedName(State *state);
bool ParsePrefix(State* state); static bool ParsePrefix(State *state);
bool ParseUnqualifiedName(State* state); static bool ParseUnqualifiedName(State *state);
bool ParseSourceName(State* state); static bool ParseSourceName(State *state);
bool ParseLocalSourceName(State* state); static bool ParseLocalSourceName(State *state);
bool ParseNumber(State* state, int* number_out); static bool ParseNumber(State *state, int *number_out);
bool ParseFloatNumber(State* state); static bool ParseFloatNumber(State *state);
bool ParseSeqId(State* state); static bool ParseSeqId(State *state);
bool ParseIdentifier(State* state, ssize_t length); static bool ParseIdentifier(State *state, ssize_t length);
bool ParseAbiTags(State* state); static bool ParseAbiTags(State *state);
bool ParseAbiTag(State* state); static bool ParseAbiTag(State *state);
bool ParseOperatorName(State* state); static bool ParseOperatorName(State *state);
bool ParseSpecialName(State* state); static bool ParseSpecialName(State *state);
bool ParseCallOffset(State* state); static bool ParseCallOffset(State *state);
bool ParseNVOffset(State* state); static bool ParseNVOffset(State *state);
bool ParseVOffset(State* state); static bool ParseVOffset(State *state);
bool ParseCtorDtorName(State* state); static bool ParseCtorDtorName(State *state);
bool ParseType(State* state); static bool ParseType(State *state);
bool ParseCVQualifiers(State* state); static bool ParseCVQualifiers(State *state);
bool ParseBuiltinType(State* state); static bool ParseBuiltinType(State *state);
bool ParseFunctionType(State* state); static bool ParseFunctionType(State *state);
bool ParseBareFunctionType(State* state); static bool ParseBareFunctionType(State *state);
bool ParseClassEnumType(State* state); static bool ParseClassEnumType(State *state);
bool ParseArrayType(State* state); static bool ParseArrayType(State *state);
bool ParsePointerToMemberType(State* state); static bool ParsePointerToMemberType(State *state);
bool ParseTemplateParam(State* state); static bool ParseTemplateParam(State *state);
bool ParseTemplateTemplateParam(State* state); static bool ParseTemplateTemplateParam(State *state);
bool ParseTemplateArgs(State* state); static bool ParseTemplateArgs(State *state);
bool ParseTemplateArg(State* state); static bool ParseTemplateArg(State *state);
bool ParseExpression(State* state); static bool ParseExpression(State *state);
bool ParseExprPrimary(State* state); static bool ParseExprPrimary(State *state);
bool ParseLocalName(State* state); static bool ParseLocalName(State *state);
bool ParseDiscriminator(State* state); static bool ParseDiscriminator(State *state);
bool ParseSubstitution(State* state); static bool ParseSubstitution(State *state);
// Implementation note: the following code is a straightforward // Implementation note: the following code is a straightforward
// translation of the Itanium C++ ABI defined in BNF with a couple of // translation of the Itanium C++ ABI defined in BNF with a couple of
@ -442,14 +443,14 @@ bool ParseSubstitution(State* state);
// <http://www.codesourcery.com/cxx-abi/abi.html#mangling> // <http://www.codesourcery.com/cxx-abi/abi.html#mangling>
// <mangled-name> ::= _Z <encoding> // <mangled-name> ::= _Z <encoding>
bool ParseMangledName(State* state) { static bool ParseMangledName(State *state) {
return ParseTwoCharToken(state, "_Z") && ParseEncoding(state); return ParseTwoCharToken(state, "_Z") && ParseEncoding(state);
} }
// <encoding> ::= <(function) name> <bare-function-type> // <encoding> ::= <(function) name> <bare-function-type>
// ::= <(data) name> // ::= <(data) name>
// ::= <special-name> // ::= <special-name>
bool ParseEncoding(State* state) { static bool ParseEncoding(State *state) {
State copy = *state; State copy = *state;
if (ParseName(state) && ParseBareFunctionType(state)) { if (ParseName(state) && ParseBareFunctionType(state)) {
return true; return true;
@ -466,13 +467,14 @@ bool ParseEncoding(State* state) {
// ::= <unscoped-template-name> <template-args> // ::= <unscoped-template-name> <template-args>
// ::= <unscoped-name> // ::= <unscoped-name>
// ::= <local-name> // ::= <local-name>
bool ParseName(State* state) { static bool ParseName(State *state) {
if (ParseNestedName(state) || ParseLocalName(state)) { if (ParseNestedName(state) || ParseLocalName(state)) {
return true; return true;
} }
State copy = *state; State copy = *state;
if (ParseUnscopedTemplateName(state) && ParseTemplateArgs(state)) { if (ParseUnscopedTemplateName(state) &&
ParseTemplateArgs(state)) {
return true; return true;
} }
*state = copy; *state = copy;
@ -486,13 +488,14 @@ bool ParseName(State* state) {
// <unscoped-name> ::= <unqualified-name> // <unscoped-name> ::= <unqualified-name>
// ::= St <unqualified-name> // ::= St <unqualified-name>
bool ParseUnscopedName(State* state) { static bool ParseUnscopedName(State *state) {
if (ParseUnqualifiedName(state)) { if (ParseUnqualifiedName(state)) {
return true; return true;
} }
State copy = *state; State copy = *state;
if (ParseTwoCharToken(state, "St") && MaybeAppend(state, "std::") && if (ParseTwoCharToken(state, "St") &&
MaybeAppend(state, "std::") &&
ParseUnqualifiedName(state)) { ParseUnqualifiedName(state)) {
return true; return true;
} }
@ -502,16 +505,18 @@ bool ParseUnscopedName(State* state) {
// <unscoped-template-name> ::= <unscoped-name> // <unscoped-template-name> ::= <unscoped-name>
// ::= <substitution> // ::= <substitution>
bool ParseUnscopedTemplateName(State* state) { static bool ParseUnscopedTemplateName(State *state) {
return ParseUnscopedName(state) || ParseSubstitution(state); return ParseUnscopedName(state) || ParseSubstitution(state);
} }
// <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E // <nested-name> ::= N [<CV-qualifiers>] <prefix> <unqualified-name> E
// ::= N [<CV-qualifiers>] <template-prefix> <template-args> E // ::= N [<CV-qualifiers>] <template-prefix> <template-args> E
bool ParseNestedName(State* state) { static bool ParseNestedName(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'N') && EnterNestedName(state) && if (ParseOneCharToken(state, 'N') &&
Optional(ParseCVQualifiers(state)) && ParsePrefix(state) && EnterNestedName(state) &&
Optional(ParseCVQualifiers(state)) &&
ParsePrefix(state) &&
LeaveNestedName(state, copy.nest_level) && LeaveNestedName(state, copy.nest_level) &&
ParseOneCharToken(state, 'E')) { ParseOneCharToken(state, 'E')) {
return true; return true;
@ -531,11 +536,12 @@ bool ParseNestedName(State* state) {
// <template-prefix> ::= <prefix> <(template) unqualified-name> // <template-prefix> ::= <prefix> <(template) unqualified-name>
// ::= <template-param> // ::= <template-param>
// ::= <substitution> // ::= <substitution>
bool ParsePrefix(State* state) { static bool ParsePrefix(State *state) {
bool has_something = false; bool has_something = false;
while (true) { while (true) {
MaybeAppendSeparator(state); MaybeAppendSeparator(state);
if (ParseTemplateParam(state) || ParseSubstitution(state) || if (ParseTemplateParam(state) ||
ParseSubstitution(state) ||
ParseUnscopedName(state)) { ParseUnscopedName(state)) {
has_something = true; has_something = true;
MaybeIncreaseNestLevel(state); MaybeIncreaseNestLevel(state);
@ -555,14 +561,15 @@ bool ParsePrefix(State* state) {
// ::= <ctor-dtor-name> // ::= <ctor-dtor-name>
// ::= <source-name> [<abi-tags>] // ::= <source-name> [<abi-tags>]
// ::= <local-source-name> [<abi-tags>] // ::= <local-source-name> [<abi-tags>]
bool ParseUnqualifiedName(State* state) { static bool ParseUnqualifiedName(State *state) {
return (ParseOperatorName(state) || ParseCtorDtorName(state) || return (ParseOperatorName(state) ||
ParseCtorDtorName(state) ||
(ParseSourceName(state) && Optional(ParseAbiTags(state))) || (ParseSourceName(state) && Optional(ParseAbiTags(state))) ||
(ParseLocalSourceName(state) && Optional(ParseAbiTags(state)))); (ParseLocalSourceName(state) && Optional(ParseAbiTags(state))));
} }
// <source-name> ::= <positive length number> <identifier> // <source-name> ::= <positive length number> <identifier>
bool ParseSourceName(State* state) { static bool ParseSourceName(State *state) {
State copy = *state; State copy = *state;
int length = -1; int length = -1;
if (ParseNumber(state, &length) && ParseIdentifier(state, length)) { if (ParseNumber(state, &length) && ParseIdentifier(state, length)) {
@ -577,7 +584,7 @@ bool ParseSourceName(State* state) {
// References: // References:
// http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775 // http://gcc.gnu.org/bugzilla/show_bug.cgi?id=31775
// http://gcc.gnu.org/viewcvs?view=rev&revision=124467 // http://gcc.gnu.org/viewcvs?view=rev&revision=124467
bool ParseLocalSourceName(State* state) { static bool ParseLocalSourceName(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'L') && ParseSourceName(state) && if (ParseOneCharToken(state, 'L') && ParseSourceName(state) &&
Optional(ParseDiscriminator(state))) { Optional(ParseDiscriminator(state))) {
@ -590,7 +597,7 @@ bool ParseLocalSourceName(State* state) {
// <number> ::= [n] <non-negative decimal integer> // <number> ::= [n] <non-negative decimal integer>
// If "number_out" is non-null, then *number_out is set to the value of the // If "number_out" is non-null, then *number_out is set to the value of the
// parsed number on success. // parsed number on success.
bool ParseNumber(State* state, int* number_out) { static bool ParseNumber(State *state, int *number_out) {
int sign = 1; int sign = 1;
if (ParseOneCharToken(state, 'n')) { if (ParseOneCharToken(state, 'n')) {
sign = -1; sign = -1;
@ -630,7 +637,7 @@ bool ParseNumber(State* state, int* number_out) {
// Floating-point literals are encoded using a fixed-length lowercase // Floating-point literals are encoded using a fixed-length lowercase
// hexadecimal string. // hexadecimal string.
bool ParseFloatNumber(State* state) { static bool ParseFloatNumber(State *state) {
const char *p = state->mangled_cur; const char *p = state->mangled_cur;
for (;*p != '\0'; ++p) { for (;*p != '\0'; ++p) {
if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) { if (!IsDigit(*p) && !(*p >= 'a' && *p <= 'f')) {
@ -646,7 +653,7 @@ bool ParseFloatNumber(State* state) {
// The <seq-id> is a sequence number in base 36, // The <seq-id> is a sequence number in base 36,
// using digits and upper case letters // using digits and upper case letters
bool ParseSeqId(State* state) { static bool ParseSeqId(State *state) {
const char *p = state->mangled_cur; const char *p = state->mangled_cur;
for (;*p != '\0'; ++p) { for (;*p != '\0'; ++p) {
if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) { if (!IsDigit(*p) && !(*p >= 'A' && *p <= 'Z')) {
@ -661,8 +668,9 @@ bool ParseSeqId(State* state) {
} }
// <identifier> ::= <unqualified source code identifier> (of given length) // <identifier> ::= <unqualified source code identifier> (of given length)
bool ParseIdentifier(State* state, ssize_t length) { static bool ParseIdentifier(State *state, ssize_t length) {
if (length == -1 || !AtLeastNumCharsRemaining(state->mangled_cur, length)) { if (length == -1 ||
!AtLeastNumCharsRemaining(state->mangled_cur, length)) {
return false; return false;
} }
if (IdentifierIsAnonymousNamespace(state, length)) { if (IdentifierIsAnonymousNamespace(state, length)) {
@ -679,7 +687,7 @@ bool ParseIdentifier(State* state, ssize_t length) {
} }
// <abi-tags> ::= <abi-tag> [<abi-tags>] // <abi-tags> ::= <abi-tag> [<abi-tags>]
bool ParseAbiTags(State* state) { static bool ParseAbiTags(State *state) {
State copy = *state; State copy = *state;
DisableAppend(state); DisableAppend(state);
if (OneOrMore(ParseAbiTag, state)) { if (OneOrMore(ParseAbiTag, state)) {
@ -691,21 +699,23 @@ bool ParseAbiTags(State* state) {
} }
// <abi-tag> ::= B <source-name> // <abi-tag> ::= B <source-name>
bool ParseAbiTag(State* state) { static bool ParseAbiTag(State *state) {
return ParseOneCharToken(state, 'B') && ParseSourceName(state); return ParseOneCharToken(state, 'B') && ParseSourceName(state);
} }
// <operator-name> ::= nw, and other two letters cases // <operator-name> ::= nw, and other two letters cases
// ::= cv <type> # (cast) // ::= cv <type> # (cast)
// ::= v <digit> <source-name> # vendor extended operator // ::= v <digit> <source-name> # vendor extended operator
bool ParseOperatorName(State* state) { static bool ParseOperatorName(State *state) {
if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) { if (!AtLeastNumCharsRemaining(state->mangled_cur, 2)) {
return false; return false;
} }
// First check with "cv" (cast) case. // First check with "cv" (cast) case.
State copy = *state; State copy = *state;
if (ParseTwoCharToken(state, "cv") && MaybeAppend(state, "operator ") && if (ParseTwoCharToken(state, "cv") &&
EnterNestedName(state) && ParseType(state) && MaybeAppend(state, "operator ") &&
EnterNestedName(state) &&
ParseType(state) &&
LeaveNestedName(state, copy.nest_level)) { LeaveNestedName(state, copy.nest_level)) {
return true; return true;
} }
@ -720,7 +730,8 @@ bool ParseOperatorName(State* state) {
// Other operator names should start with a lower alphabet followed // Other operator names should start with a lower alphabet followed
// by a lower/upper alphabet. // by a lower/upper alphabet.
if (!(IsLower(state->mangled_cur[0]) && IsAlpha(state->mangled_cur[1]))) { if (!(IsLower(state->mangled_cur[0]) &&
IsAlpha(state->mangled_cur[1]))) {
return false; return false;
} }
// We may want to perform a binary search if we really need speed. // We may want to perform a binary search if we really need speed.
@ -758,9 +769,10 @@ bool ParseOperatorName(State* state) {
// //
// Note: we don't care much about them since they don't appear in // Note: we don't care much about them since they don't appear in
// stack traces. The are special data. // stack traces. The are special data.
bool ParseSpecialName(State* state) { static bool ParseSpecialName(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'T') && ParseCharClass(state, "VTIS") && if (ParseOneCharToken(state, 'T') &&
ParseCharClass(state, "VTIS") &&
ParseType(state)) { ParseType(state)) {
return true; return true;
} }
@ -772,7 +784,8 @@ bool ParseSpecialName(State* state) {
} }
*state = copy; *state = copy;
if (ParseTwoCharToken(state, "GV") && ParseName(state)) { if (ParseTwoCharToken(state, "GV") &&
ParseName(state)) {
return true; return true;
} }
*state = copy; *state = copy;
@ -818,16 +831,16 @@ bool ParseSpecialName(State* state) {
// <call-offset> ::= h <nv-offset> _ // <call-offset> ::= h <nv-offset> _
// ::= v <v-offset> _ // ::= v <v-offset> _
bool ParseCallOffset(State* state) { static bool ParseCallOffset(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'h') && ParseNVOffset(state) && if (ParseOneCharToken(state, 'h') &&
ParseOneCharToken(state, '_')) { ParseNVOffset(state) && ParseOneCharToken(state, '_')) {
return true; return true;
} }
*state = copy; *state = copy;
if (ParseOneCharToken(state, 'v') && ParseVOffset(state) && if (ParseOneCharToken(state, 'v') &&
ParseOneCharToken(state, '_')) { ParseVOffset(state) && ParseOneCharToken(state, '_')) {
return true; return true;
} }
*state = copy; *state = copy;
@ -836,10 +849,10 @@ bool ParseCallOffset(State* state) {
} }
// <nv-offset> ::= <(offset) number> // <nv-offset> ::= <(offset) number>
bool ParseNVOffset(State* state) { return ParseNumber(state, nullptr); } static bool ParseNVOffset(State *state) { return ParseNumber(state, nullptr); }
// <v-offset> ::= <(offset) number> _ <(virtual offset) number> // <v-offset> ::= <(offset) number> _ <(virtual offset) number>
bool ParseVOffset(State* state) { static bool ParseVOffset(State *state) {
State copy = *state; State copy = *state;
if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') && if (ParseNumber(state, nullptr) && ParseOneCharToken(state, '_') &&
ParseNumber(state, nullptr)) { ParseNumber(state, nullptr)) {
@ -851,9 +864,10 @@ bool ParseVOffset(State* state) {
// <ctor-dtor-name> ::= C1 | C2 | C3 // <ctor-dtor-name> ::= C1 | C2 | C3
// ::= D0 | D1 | D2 // ::= D0 | D1 | D2
bool ParseCtorDtorName(State* state) { static bool ParseCtorDtorName(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'C') && ParseCharClass(state, "123")) { if (ParseOneCharToken(state, 'C') &&
ParseCharClass(state, "123")) {
const char * const prev_name = state->prev_name; const char * const prev_name = state->prev_name;
const ssize_t prev_name_length = state->prev_name_length; const ssize_t prev_name_length = state->prev_name_length;
MaybeAppendWithLength(state, prev_name, prev_name_length); MaybeAppendWithLength(state, prev_name, prev_name_length);
@ -861,7 +875,8 @@ bool ParseCtorDtorName(State* state) {
} }
*state = copy; *state = copy;
if (ParseOneCharToken(state, 'D') && ParseCharClass(state, "012")) { if (ParseOneCharToken(state, 'D') &&
ParseCharClass(state, "012")) {
const char * const prev_name = state->prev_name; const char * const prev_name = state->prev_name;
const ssize_t prev_name_length = state->prev_name_length; const ssize_t prev_name_length = state->prev_name_length;
MaybeAppend(state, "~"); MaybeAppend(state, "~");
@ -892,7 +907,7 @@ bool ParseCtorDtorName(State* state) {
// # member access (C++0x) // # member access (C++0x)
// ::= DT <expression> E # decltype of an expression (C++0x) // ::= DT <expression> E # decltype of an expression (C++0x)
// //
bool ParseType(State* state) { static bool ParseType(State *state) {
// We should check CV-qualifers, and PRGC things first. // We should check CV-qualifers, and PRGC things first.
State copy = *state; State copy = *state;
if (ParseCVQualifiers(state) && ParseType(state)) { if (ParseCVQualifiers(state) && ParseType(state)) {
@ -922,13 +937,17 @@ bool ParseType(State* state) {
} }
*state = copy; *state = copy;
if (ParseBuiltinType(state) || ParseFunctionType(state) || if (ParseBuiltinType(state) ||
ParseClassEnumType(state) || ParseArrayType(state) || ParseFunctionType(state) ||
ParsePointerToMemberType(state) || ParseSubstitution(state)) { ParseClassEnumType(state) ||
ParseArrayType(state) ||
ParsePointerToMemberType(state) ||
ParseSubstitution(state)) {
return true; return true;
} }
if (ParseTemplateTemplateParam(state) && ParseTemplateArgs(state)) { if (ParseTemplateTemplateParam(state) &&
ParseTemplateArgs(state)) {
return true; return true;
} }
*state = copy; *state = copy;
@ -944,7 +963,7 @@ bool ParseType(State* state) {
// <CV-qualifiers> ::= [r] [V] [K] // <CV-qualifiers> ::= [r] [V] [K]
// We don't allow empty <CV-qualifiers> to avoid infinite loop in // We don't allow empty <CV-qualifiers> to avoid infinite loop in
// ParseType(). // ParseType().
bool ParseCVQualifiers(State* state) { static bool ParseCVQualifiers(State *state) {
int num_cv_qualifiers = 0; int num_cv_qualifiers = 0;
num_cv_qualifiers += ParseOneCharToken(state, 'r'); num_cv_qualifiers += ParseOneCharToken(state, 'r');
num_cv_qualifiers += ParseOneCharToken(state, 'V'); num_cv_qualifiers += ParseOneCharToken(state, 'V');
@ -954,7 +973,7 @@ bool ParseCVQualifiers(State* state) {
// <builtin-type> ::= v, etc. // <builtin-type> ::= v, etc.
// ::= u <source-name> // ::= u <source-name>
bool ParseBuiltinType(State* state) { static bool ParseBuiltinType(State *state) {
const AbbrevPair *p; const AbbrevPair *p;
for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) { for (p = kBuiltinTypeList; p->abbrev != nullptr; ++p) {
if (state->mangled_cur[0] == p->abbrev[0]) { if (state->mangled_cur[0] == p->abbrev[0]) {
@ -973,11 +992,11 @@ bool ParseBuiltinType(State* state) {
} }
// <function-type> ::= F [Y] <bare-function-type> E // <function-type> ::= F [Y] <bare-function-type> E
bool ParseFunctionType(State* state) { static bool ParseFunctionType(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'F') && if (ParseOneCharToken(state, 'F') &&
Optional(ParseOneCharToken(state, 'Y')) && ParseBareFunctionType(state) && Optional(ParseOneCharToken(state, 'Y')) &&
ParseOneCharToken(state, 'E')) { ParseBareFunctionType(state) && ParseOneCharToken(state, 'E')) {
return true; return true;
} }
*state = copy; *state = copy;
@ -985,7 +1004,7 @@ bool ParseFunctionType(State* state) {
} }
// <bare-function-type> ::= <(signature) type>+ // <bare-function-type> ::= <(signature) type>+
bool ParseBareFunctionType(State* state) { static bool ParseBareFunctionType(State *state) {
State copy = *state; State copy = *state;
DisableAppend(state); DisableAppend(state);
if (OneOrMore(ParseType, state)) { if (OneOrMore(ParseType, state)) {
@ -998,11 +1017,13 @@ bool ParseBareFunctionType(State* state) {
} }
// <class-enum-type> ::= <name> // <class-enum-type> ::= <name>
bool ParseClassEnumType(State* state) { return ParseName(state); } static bool ParseClassEnumType(State *state) {
return ParseName(state);
}
// <array-type> ::= A <(positive dimension) number> _ <(element) type> // <array-type> ::= A <(positive dimension) number> _ <(element) type>
// ::= A [<(dimension) expression>] _ <(element) type> // ::= A [<(dimension) expression>] _ <(element) type>
bool ParseArrayType(State* state) { static bool ParseArrayType(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) && if (ParseOneCharToken(state, 'A') && ParseNumber(state, nullptr) &&
ParseOneCharToken(state, '_') && ParseType(state)) { ParseOneCharToken(state, '_') && ParseType(state)) {
@ -1019,9 +1040,10 @@ bool ParseArrayType(State* state) {
} }
// <pointer-to-member-type> ::= M <(class) type> <(member) type> // <pointer-to-member-type> ::= M <(class) type> <(member) type>
bool ParsePointerToMemberType(State* state) { static bool ParsePointerToMemberType(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'M') && ParseType(state) && ParseType(state)) { if (ParseOneCharToken(state, 'M') && ParseType(state) &&
ParseType(state)) {
return true; return true;
} }
*state = copy; *state = copy;
@ -1030,7 +1052,7 @@ bool ParsePointerToMemberType(State* state) {
// <template-param> ::= T_ // <template-param> ::= T_
// ::= T <parameter-2 non-negative number> _ // ::= T <parameter-2 non-negative number> _
bool ParseTemplateParam(State* state) { static bool ParseTemplateParam(State *state) {
if (ParseTwoCharToken(state, "T_")) { if (ParseTwoCharToken(state, "T_")) {
MaybeAppend(state, "?"); // We don't support template substitutions. MaybeAppend(state, "?"); // We don't support template substitutions.
return true; return true;
@ -1046,17 +1068,20 @@ bool ParseTemplateParam(State* state) {
return false; return false;
} }
// <template-template-param> ::= <template-param> // <template-template-param> ::= <template-param>
// ::= <substitution> // ::= <substitution>
bool ParseTemplateTemplateParam(State* state) { static bool ParseTemplateTemplateParam(State *state) {
return (ParseTemplateParam(state) || ParseSubstitution(state)); return (ParseTemplateParam(state) ||
ParseSubstitution(state));
} }
// <template-args> ::= I <template-arg>+ E // <template-args> ::= I <template-arg>+ E
bool ParseTemplateArgs(State* state) { static bool ParseTemplateArgs(State *state) {
State copy = *state; State copy = *state;
DisableAppend(state); DisableAppend(state);
if (ParseOneCharToken(state, 'I') && OneOrMore(ParseTemplateArg, state) && if (ParseOneCharToken(state, 'I') &&
OneOrMore(ParseTemplateArg, state) &&
ParseOneCharToken(state, 'E')) { ParseOneCharToken(state, 'E')) {
RestoreAppend(state, copy.append); RestoreAppend(state, copy.append);
MaybeAppend(state, "<>"); MaybeAppend(state, "<>");
@ -1071,9 +1096,9 @@ bool ParseTemplateArgs(State* state) {
// ::= I <template-arg>* E # argument pack // ::= I <template-arg>* E # argument pack
// ::= J <template-arg>* E # argument pack // ::= J <template-arg>* E # argument pack
// ::= X <expression> E // ::= X <expression> E
bool ParseTemplateArg(State* state) { static bool ParseTemplateArg(State *state) {
// Avoid recursion above max_levels // Avoid recursion above max_levels
constexpr uint32 max_levels = 6; constexpr uint32 max_levels = 5;
if (state->arg_level > max_levels) { if (state->arg_level > max_levels) {
return false; return false;
@ -1082,13 +1107,15 @@ bool ParseTemplateArg(State* state) {
State copy = *state; State copy = *state;
if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) && if ((ParseOneCharToken(state, 'I') || ParseOneCharToken(state, 'J')) &&
ZeroOrMore(ParseTemplateArg, state) && ParseOneCharToken(state, 'E')) { ZeroOrMore(ParseTemplateArg, state) &&
ParseOneCharToken(state, 'E')) {
--state->arg_level; --state->arg_level;
return true; return true;
} }
*state = copy; *state = copy;
if (ParseType(state) || ParseExprPrimary(state)) { if (ParseType(state) ||
ParseExprPrimary(state)) {
--state->arg_level; --state->arg_level;
return true; return true;
} }
@ -1112,7 +1139,7 @@ bool ParseTemplateArg(State* state) {
// ::= st <type> // ::= st <type>
// ::= sr <type> <unqualified-name> <template-args> // ::= sr <type> <unqualified-name> <template-args>
// ::= sr <type> <unqualified-name> // ::= sr <type> <unqualified-name>
bool ParseExpression(State* state) { static bool ParseExpression(State *state) {
if (ParseTemplateParam(state) || ParseExprPrimary(state)) { if (ParseTemplateParam(state) || ParseExprPrimary(state)) {
return true; return true;
} }
@ -1126,21 +1153,25 @@ bool ParseExpression(State* state) {
++state->expr_level; ++state->expr_level;
State copy = *state; State copy = *state;
if (ParseOperatorName(state) && ParseExpression(state) && if (ParseOperatorName(state) &&
ParseExpression(state) && ParseExpression(state)) { ParseExpression(state) &&
--state->expr_level; ParseExpression(state) &&
return true;
}
*state = copy;
if (ParseOperatorName(state) && ParseExpression(state) &&
ParseExpression(state)) { ParseExpression(state)) {
--state->expr_level; --state->expr_level;
return true; return true;
} }
*state = copy; *state = copy;
if (ParseOperatorName(state) && ParseExpression(state)) { if (ParseOperatorName(state) &&
ParseExpression(state) &&
ParseExpression(state)) {
--state->expr_level;
return true;
}
*state = copy;
if (ParseOperatorName(state) &&
ParseExpression(state)) {
--state->expr_level; --state->expr_level;
return true; return true;
} }
@ -1153,7 +1184,8 @@ bool ParseExpression(State* state) {
*state = copy; *state = copy;
if (ParseTwoCharToken(state, "sr") && ParseType(state) && if (ParseTwoCharToken(state, "sr") && ParseType(state) &&
ParseUnqualifiedName(state) && ParseTemplateArgs(state)) { ParseUnqualifiedName(state) &&
ParseTemplateArgs(state)) {
--state->expr_level; --state->expr_level;
return true; return true;
} }
@ -1165,14 +1197,6 @@ bool ParseExpression(State* state) {
return true; return true;
} }
*state = copy; *state = copy;
// Pack expansion
if (ParseTwoCharToken(state, "sp") && ParseType(state)) {
--state->expr_level;
return true;
}
*state = copy;
return false; return false;
} }
@ -1181,7 +1205,7 @@ bool ParseExpression(State* state) {
// ::= L <mangled-name> E // ::= L <mangled-name> E
// // A bug in g++'s C++ ABI version 2 (-fabi-version=2). // // A bug in g++'s C++ ABI version 2 (-fabi-version=2).
// ::= LZ <encoding> E // ::= LZ <encoding> E
bool ParseExprPrimary(State* state) { static bool ParseExprPrimary(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, 'L') && ParseType(state) && if (ParseOneCharToken(state, 'L') && ParseType(state) &&
ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) { ParseNumber(state, nullptr) && ParseOneCharToken(state, 'E')) {
@ -1190,7 +1214,8 @@ bool ParseExprPrimary(State* state) {
*state = copy; *state = copy;
if (ParseOneCharToken(state, 'L') && ParseType(state) && if (ParseOneCharToken(state, 'L') && ParseType(state) &&
ParseFloatNumber(state) && ParseOneCharToken(state, 'E')) { ParseFloatNumber(state) &&
ParseOneCharToken(state, 'E')) {
return true; return true;
} }
*state = copy; *state = copy;
@ -1213,7 +1238,7 @@ bool ParseExprPrimary(State* state) {
// <local-name> := Z <(function) encoding> E <(entity) name> // <local-name> := Z <(function) encoding> E <(entity) name>
// [<discriminator>] // [<discriminator>]
// := Z <(function) encoding> E s [<discriminator>] // := Z <(function) encoding> E s [<discriminator>]
bool ParseLocalName(State* state) { static bool ParseLocalName(State *state) {
// Avoid recursion above max_levels // Avoid recursion above max_levels
constexpr uint32 max_levels = 5; constexpr uint32 max_levels = 5;
if (state->local_level > max_levels) { if (state->local_level > max_levels) {
@ -1240,7 +1265,7 @@ bool ParseLocalName(State* state) {
} }
// <discriminator> := _ <(non-negative) number> // <discriminator> := _ <(non-negative) number>
bool ParseDiscriminator(State* state) { static bool ParseDiscriminator(State *state) {
State copy = *state; State copy = *state;
if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) { if (ParseOneCharToken(state, '_') && ParseNumber(state, nullptr)) {
return true; return true;
@ -1252,7 +1277,7 @@ bool ParseDiscriminator(State* state) {
// <substitution> ::= S_ // <substitution> ::= S_
// ::= S <seq-id> _ // ::= S <seq-id> _
// ::= St, etc. // ::= St, etc.
bool ParseSubstitution(State* state) { static bool ParseSubstitution(State *state) {
if (ParseTwoCharToken(state, "S_")) { if (ParseTwoCharToken(state, "S_")) {
MaybeAppend(state, "?"); // We don't support substitutions. MaybeAppend(state, "?"); // We don't support substitutions.
return true; return true;
@ -1287,7 +1312,7 @@ bool ParseSubstitution(State* state) {
// Parse <mangled-name>, optionally followed by either a function-clone suffix // Parse <mangled-name>, optionally followed by either a function-clone suffix
// or version suffix. Returns true only if all of "mangled_cur" was consumed. // or version suffix. Returns true only if all of "mangled_cur" was consumed.
bool ParseTopLevelMangledName(State* state) { static bool ParseTopLevelMangledName(State *state) {
if (ParseMangledName(state)) { if (ParseMangledName(state)) {
if (state->mangled_cur[0] != '\0') { if (state->mangled_cur[0] != '\0') {
// Drop trailing function clone suffix, if any. // Drop trailing function clone suffix, if any.
@ -1300,13 +1325,12 @@ bool ParseTopLevelMangledName(State* state) {
MaybeAppend(state, state->mangled_cur); MaybeAppend(state, state->mangled_cur);
return true; return true;
} }
return ParseName(state); return false; // Unconsumed suffix.
} }
return true; return true;
} }
return false; return false;
} }
} // namespace
#endif #endif
// The demangler entry point. // The demangler entry point.
@ -1340,18 +1364,6 @@ bool Demangle(const char* mangled, char* out, size_t out_size) {
(void)out_size; (void)out_size;
return false; return false;
#endif #endif
#elif defined(HAVE___CXA_DEMANGLE)
int status = -1;
std::size_t n = 0;
std::unique_ptr<char, decltype(&std::free)> unmangled{
abi::__cxa_demangle(mangled, nullptr, &n, &status), &std::free};
if (!unmangled) {
return false;
}
std::copy_n(unmangled.get(), std::min(n, out_size), out);
return status == 0;
#else #else
State state; State state;
InitState(&state, mangled, out, out_size); InitState(&state, mangled, out, out_size);
@ -1359,5 +1371,4 @@ bool Demangle(const char* mangled, char* out, size_t out_size) {
#endif #endif
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -67,28 +67,19 @@
// C++ ABI in the future. // C++ ABI in the future.
// //
#ifndef GLOG_INTERNAL_DEMANGLE_H #ifndef BASE_DEMANGLE_H_
#define GLOG_INTERNAL_DEMANGLE_H #define BASE_DEMANGLE_H_
#include <cstddef> #include "config.h"
#include "glog/logging.h"
#if defined(GLOG_USE_GLOG_EXPORT) _START_GOOGLE_NAMESPACE_
# include "glog/export.h"
#endif
#if !defined(GLOG_NO_EXPORT)
# error "demangle.h" was not included correctly.
#endif
namespace google {
inline namespace glog_internal_namespace_ {
// Demangle "mangled". On success, return true and write the // Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false. // demangled symbol name to "out". Otherwise, return false.
// "out" is modified even if demangling is unsuccessful. // "out" is modified even if demangling is unsuccessful.
bool GLOG_NO_EXPORT Demangle(const char* mangled, char* out, size_t out_size); bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size);
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#endif // GLOG_INTERNAL_DEMANGLE_H #endif // BASE_DEMANGLE_H_

View File

@ -42,7 +42,7 @@
#include "googletest.h" #include "googletest.h"
#include "utilities.h" #include "utilities.h"
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
@ -51,7 +51,7 @@ GLOG_DEFINE_bool(demangle_filter, false,
"Run demangle_unittest in filter mode"); "Run demangle_unittest in filter mode");
using namespace std; using namespace std;
using namespace google; using namespace GOOGLE_NAMESPACE;
// A wrapper function for Demangle() to make the unit test simple. // A wrapper function for Demangle() to make the unit test simple.
static const char *DemangleIt(const char * const mangled) { static const char *DemangleIt(const char * const mangled) {
@ -67,11 +67,14 @@ static const char* DemangleIt(const char* const mangled) {
#if defined(HAVE_DBGHELP) && !defined(NDEBUG) #if defined(HAVE_DBGHELP) && !defined(NDEBUG)
TEST(Demangle, Windows) { TEST(Demangle, Windows) {
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("?func@Foo@@SAXH@Z")); DemangleIt("?func@Foo@@SAXH@Z"));
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", EXPECT_STREQ(
"public: static void __cdecl Foo::func(int)",
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)")); DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
EXPECT_STREQ("int __cdecl foobarArray(int * const)", EXPECT_STREQ(
"int __cdecl foobarArray(int * const)",
DemangleIt("?foobarArray@@YAHQAH@Z")); DemangleIt("?foobarArray@@YAHQAH@Z"));
} }
#endif #endif
@ -145,10 +148,10 @@ TEST(Demangle, FromFile) {
#endif #endif
int main(int argc, char **argv) { int main(int argc, char **argv) {
InitGoogleTest(&argc, argv); #ifdef HAVE_LIB_GFLAGS
#ifdef GLOG_USE_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
InitGoogleTest(&argc, argv);
FLAGS_logtostderr = true; FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);

View File

@ -143,10 +143,3 @@ _Zrm1XS_ operator%()
# Template argument packs can start with I or J. # Template argument packs can start with I or J.
_Z3addIIiEEvDpT_ add<>() _Z3addIIiEEvDpT_ add<>()
_Z3addIJiEEvDpT_ add<>() _Z3addIJiEEvDpT_ add<>()
# Nested templates with pack expansion
_ZSt13__invoke_implIvPFvPiEJDnEET_St14__invoke_otherOT0_DpOT1_ std::__invoke_impl<>()
_ZSt8__invokeIPFvPiEJDnEENSt15__invoke_resultIT_JDpT0_EE4typeEOS4_DpOS5_ std::__invoke<>()
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE std::thread::_Invoker<>::_M_invoke<>()
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEEclEv std::thread::_Invoker<>::operator()()
_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvPiEDnEEEEE6_M_runEv std::thread::_State_impl<>::_M_run()

View File

@ -1,158 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#include "glog/flags.h"
#include <cstdlib>
#include <cstring>
#include "base/commandlineflags.h"
#include "glog/log_severity.h"
namespace {
// Compute the default value for --log_dir
static const char* DefaultLogDir() {
constexpr const char* const names[]{"GOOGLE_LOG_DIR", "TEST_TMPDIR"};
for (const char* const name : names) {
const char* const env = std::getenv(name);
if (env != nullptr && env[0] != '\0') {
return env;
}
}
return "";
}
bool BoolFromEnv(const char* varname, bool defval) {
const char* const valstr = getenv(varname);
if (!valstr) {
return defval;
}
return std::memchr("tTyY1\0", valstr[0], 6) != nullptr;
}
} // namespace
GLOG_DEFINE_bool(timestamp_in_logfile_name,
BoolFromEnv("GOOGLE_TIMESTAMP_IN_LOGFILE_NAME", true),
"put a timestamp at the end of the log file name");
GLOG_DEFINE_bool(logtostderr, BoolFromEnv("GOOGLE_LOGTOSTDERR", false),
"log messages go to stderr instead of logfiles");
GLOG_DEFINE_bool(alsologtostderr, BoolFromEnv("GOOGLE_ALSOLOGTOSTDERR", false),
"log messages go to stderr in addition to logfiles");
GLOG_DEFINE_bool(colorlogtostderr, false,
"color messages logged to stderr (if supported by terminal)");
GLOG_DEFINE_bool(colorlogtostdout, false,
"color messages logged to stdout (if supported by terminal)");
GLOG_DEFINE_bool(logtostdout, BoolFromEnv("GOOGLE_LOGTOSTDOUT", false),
"log messages go to stdout instead of logfiles");
#ifdef GLOG_OS_LINUX
GLOG_DEFINE_bool(
drop_log_memory, true,
"Drop in-memory buffers of log contents. "
"Logs can grow very quickly and they are rarely read before they "
"need to be evicted from memory. Instead, drop them from memory "
"as soon as they are flushed to disk.");
#endif
// By default, errors (including fatal errors) get logged to stderr as
// well as the file.
//
// The default is ERROR instead of FATAL so that users can see problems
// when they run a program without having to look in another file.
GLOG_DEFINE_int32(
stderrthreshold, google::GLOG_ERROR,
"log messages at or above this level are copied to stderr in "
"addition to logfiles. This flag obsoletes --alsologtostderr.");
GLOG_DEFINE_string(alsologtoemail, "",
"log messages go to these email addresses "
"in addition to logfiles");
GLOG_DEFINE_bool(log_file_header, true,
"Write the file header at the start of each log file");
GLOG_DEFINE_bool(log_prefix, true,
"Prepend the log prefix to the start of each log line");
GLOG_DEFINE_bool(log_year_in_prefix, true,
"Include the year in the log prefix");
GLOG_DEFINE_int32(minloglevel, 0,
"Messages logged at a lower level than this don't "
"actually get logged anywhere");
GLOG_DEFINE_int32(logbuflevel, 0,
"Buffer log messages logged at this level or lower"
" (-1 means don't buffer; 0 means buffer INFO only;"
" ...)");
GLOG_DEFINE_int32(logbufsecs, 30,
"Buffer log messages for at most this many seconds");
GLOG_DEFINE_int32(logcleansecs, 60 * 5, // every 5 minutes
"Clean overdue logs every this many seconds");
GLOG_DEFINE_int32(logemaillevel, 999,
"Email log messages logged at this level or higher"
" (0 means email all; 3 means email FATAL only;"
" ...)");
GLOG_DEFINE_string(logmailer, "", "Mailer used to send logging email");
GLOG_DEFINE_int32(logfile_mode, 0664, "Log file mode/permissions.");
GLOG_DEFINE_string(
log_dir, DefaultLogDir(),
"If specified, logfiles are written into this directory instead "
"of the default logging directory.");
GLOG_DEFINE_string(log_link, "",
"Put additional links to the log "
"files in this directory");
GLOG_DEFINE_uint32(max_log_size, 1800,
"approx. maximum log file size (in MB). A value of 0 will "
"be silently overridden to 1.");
GLOG_DEFINE_bool(stop_logging_if_full_disk, false,
"Stop attempting to log to disk if the disk is full.");
GLOG_DEFINE_string(log_backtrace_at, "",
"Emit a backtrace when logging at file:linenum.");
GLOG_DEFINE_bool(log_utc_time, false, "Use UTC time for logging.");
GLOG_DEFINE_int32(v, 0,
"Show all VLOG(m) messages for m <= this."
" Overridable by --vmodule.");
GLOG_DEFINE_string(
vmodule, "",
"per-module verbose level."
" Argument is a comma-separated list of <module name>=<log level>."
" <module name> is a glob pattern, matched against the filename base"
" (that is, name ignoring .cc/.h./-inl.h)."
" <log level> overrides any value given by --v.");
GLOG_DEFINE_bool(symbolize_stacktrace, true,
"Symbolize the stack trace in the tombstone");

View File

@ -1,191 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GLOG_FLAGS_H
#define GLOG_FLAGS_H
#include <string>
#if defined(GLOG_USE_GFLAGS)
# include <gflags/gflags.h>
#endif
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/flags.h> was not included correctly. See the documentation for how to consume the library.
#endif
#include "glog/platform.h"
#include "glog/types.h"
#pragma push_macro("DECLARE_VARIABLE")
#pragma push_macro("DECLARE_bool")
#pragma push_macro("DECLARE_string")
#pragma push_macro("DECLARE_int32")
#pragma push_macro("DECLARE_uint32")
#ifdef DECLARE_VARIABLE
# undef DECLARE_VARIABLE
#endif
#ifdef DECLARE_bool
# undef DECLARE_bool
#endif
#ifdef DECLARE_string
# undef DECLARE_string
#endif
#ifdef DECLARE_int32
# undef DECLARE_int32
#endif
#ifdef DECLARE_uint32
# undef DECLARE_uint32
#endif
#ifndef DECLARE_VARIABLE
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \
} \
using fL##shorttype::FLAGS_##name
// bool specialization
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
// int32 specialization
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
# if !defined(DECLARE_uint32)
// uint32 specialization
# define DECLARE_uint32(name) \
DECLARE_VARIABLE(google::uint32, U, name, uint32)
# endif // !defined(DECLARE_uint32) && !defined(GLOG_USE_GFLAGS)
// Special case for string, because we have to specify the namespace
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
# define DECLARE_string(name) \
namespace fLS { \
extern GLOG_EXPORT std::string& FLAGS_##name; \
} \
using fLS::FLAGS_##name
#endif
DECLARE_int32(logemaillevel);
DECLARE_int32(logcleansecs);
#ifdef GLOG_OS_LINUX
DECLARE_bool(drop_log_memory);
#endif
DECLARE_string(alsologtoemail);
DECLARE_string(log_backtrace_at);
// Set whether appending a timestamp to the log file name
DECLARE_bool(timestamp_in_logfile_name);
// Set whether log messages go to stdout instead of logfiles
DECLARE_bool(logtostdout);
// Set color messages logged to stdout (if supported by terminal).
DECLARE_bool(colorlogtostdout);
// Set whether log messages go to stderr instead of logfiles
DECLARE_bool(logtostderr);
// Set whether log messages go to stderr in addition to logfiles.
DECLARE_bool(alsologtostderr);
// Set color messages logged to stderr (if supported by terminal).
DECLARE_bool(colorlogtostderr);
// Log messages at a level >= this flag are automatically sent to
// stderr in addition to log files.
DECLARE_int32(stderrthreshold);
// Set whether the log file header should be written upon creating a file.
DECLARE_bool(log_file_header);
// Set whether the log prefix should be prepended to each line of output.
DECLARE_bool(log_prefix);
// Set whether the year should be included in the log prefix.
DECLARE_bool(log_year_in_prefix);
// Log messages at a level <= this flag are buffered.
// Log messages at a higher level are flushed immediately.
DECLARE_int32(logbuflevel);
// Sets the maximum number of seconds which logs may be buffered for.
DECLARE_int32(logbufsecs);
// Log suppression level: messages logged at a lower level than this
// are suppressed.
DECLARE_int32(minloglevel);
// If specified, logfiles are written into this directory instead of the
// default logging directory.
DECLARE_string(log_dir);
// Set the log file mode.
DECLARE_int32(logfile_mode);
// Sets the path of the directory into which to put additional links
// to the log files.
DECLARE_string(log_link);
DECLARE_int32(v); // in vlog_is_on.cc
DECLARE_string(vmodule); // also in vlog_is_on.cc
// Sets the maximum log file size (in MB).
DECLARE_uint32(max_log_size);
// Sets whether to avoid logging to the disk if the disk is full.
DECLARE_bool(stop_logging_if_full_disk);
// Use UTC time for logging
DECLARE_bool(log_utc_time);
// Mailer used to send logging email
DECLARE_string(logmailer);
DECLARE_bool(symbolize_stacktrace);
#pragma pop_macro("DECLARE_VARIABLE")
#pragma pop_macro("DECLARE_bool")
#pragma pop_macro("DECLARE_string")
#pragma pop_macro("DECLARE_int32")
#pragma pop_macro("DECLARE_uint32")
#endif // GLOG_FLAGS_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2023, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -30,16 +30,6 @@
#ifndef BASE_LOG_SEVERITY_H__ #ifndef BASE_LOG_SEVERITY_H__
#define BASE_LOG_SEVERITY_H__ #define BASE_LOG_SEVERITY_H__
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/log_severity.h> was not included correctly. See the documentation for how to consume the library.
#endif
namespace google {
// The recommended semantics of the log levels are as follows: // The recommended semantics of the log levels are as follows:
// //
// INFO: // INFO:
@ -58,35 +48,17 @@ namespace google {
// Variables of type LogSeverity are widely taken to lie in the range // Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if // [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// you ever need to change their values or add a new severity. // you ever need to change their values or add a new severity.
using LogSeverity = int;
enum LogSeverity { const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
GLOG_INFO = 0, NUM_SEVERITIES = 4;
GLOG_WARNING = 1,
GLOG_ERROR = 2,
GLOG_FATAL = 3,
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES #ifndef GLOG_NO_ABBREVIATED_SEVERITIES
# ifdef ERROR # ifdef ERROR
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail. # error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
# endif # endif
INFO = GLOG_INFO, const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
WARNING = GLOG_WARNING, ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
ERROR = GLOG_ERROR,
FATAL = GLOG_FATAL
#endif #endif
};
#if defined(__cpp_inline_variables)
# if (__cpp_inline_variables >= 201606L)
# define GLOG_INLINE_VARIABLE inline
# endif // (__cpp_inline_variables >= 201606L)
#endif // defined(__cpp_inline_variables)
#if !defined(GLOG_INLINE_VARIABLE)
# define GLOG_INLINE_VARIABLE
#endif // !defined(GLOG_INLINE_VARIABLE)
GLOG_INLINE_VARIABLE
constexpr int NUM_SEVERITIES = 4;
// DFATAL is FATAL in debug mode, ERROR in normal mode // DFATAL is FATAL in debug mode, ERROR in normal mode
#ifdef NDEBUG #ifdef NDEBUG
@ -95,6 +67,8 @@ constexpr int NUM_SEVERITIES = 4;
#define DFATAL_LEVEL FATAL #define DFATAL_LEVEL FATAL
#endif #endif
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK: // NDEBUG usage helpers related to (RAW_)DCHECK:
// //
// DEBUG_MODE is for small !NDEBUG uses like // DEBUG_MODE is for small !NDEBUG uses like
@ -121,6 +95,4 @@ enum { DEBUG_MODE = 1 };
#define IF_DEBUG_MODE(x) x #define IF_DEBUG_MODE(x) x
#endif #endif
} // namespace google
#endif // BASE_LOG_SEVERITY_H__ #endif // BASE_LOG_SEVERITY_H__

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -39,9 +39,8 @@
#elif defined(__CYGWIN__) || defined(__CYGWIN32__) #elif defined(__CYGWIN__) || defined(__CYGWIN32__)
#define GLOG_OS_CYGWIN #define GLOG_OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__) #elif defined(linux) || defined(__linux) || defined(__linux__)
#ifndef GLOG_OS_LINUX
#define GLOG_OS_LINUX #define GLOG_OS_LINUX
# if defined(__ANDROID__)
# define GLOG_OS_ANDROID
#endif #endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__) #elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
#define GLOG_OS_MACOSX #define GLOG_OS_MACOSX

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -36,18 +36,17 @@
#ifndef GLOG_RAW_LOGGING_H #ifndef GLOG_RAW_LOGGING_H
#define GLOG_RAW_LOGGING_H #define GLOG_RAW_LOGGING_H
#if defined(GLOG_USE_GLOG_EXPORT) #include <ctime>
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/raw_logging.h> was not included correctly. See the documentation for how to consume the library.
#endif
@ac_google_start_namespace@
#include "glog/log_severity.h" #include "glog/log_severity.h"
#include "glog/logging.h"
#include "glog/vlog_is_on.h" #include "glog/vlog_is_on.h"
namespace google { #if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wvariadic-macros"
#endif
// This is similar to LOG(severity) << format... and VLOG(level) << format.., // This is similar to LOG(severity) << format... and VLOG(level) << format..,
// but // but
@ -65,7 +64,7 @@ namespace google {
// I20200821 211317 file.cc:142] RAW: status is 20 // I20200821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \ #define RAW_LOG(severity, ...) \
do { \ do { \
switch (google::GLOG_##severity) { \ switch (@ac_google_namespace@::GLOG_ ## severity) { \
case 0: \ case 0: \
RAW_LOG_INFO(__VA_ARGS__); \ RAW_LOG_INFO(__VA_ARGS__); \
break; \ break; \
@ -97,33 +96,33 @@ namespace google {
#endif // STRIP_LOG == 0 #endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG == 0 #if !defined(STRIP_LOG) || STRIP_LOG == 0
# define RAW_LOG_INFO(...) \ #define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \
google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__) __FILE__, __LINE__, __VA_ARGS__)
#else #else
# define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__) #define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0 #endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG <= 1 #if !defined(STRIP_LOG) || STRIP_LOG <= 1
# define RAW_LOG_WARNING(...) \ #define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \
google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__) __FILE__, __LINE__, __VA_ARGS__)
#else #else
# define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__) #define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 1 #endif // STRIP_LOG <= 1
#if !defined(STRIP_LOG) || STRIP_LOG <= 2 #if !defined(STRIP_LOG) || STRIP_LOG <= 2
# define RAW_LOG_ERROR(...) \ #define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \
google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__) __FILE__, __LINE__, __VA_ARGS__)
#else #else
# define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__) #define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG <= 2 #endif // STRIP_LOG <= 2
#if !defined(STRIP_LOG) || STRIP_LOG <= 3 #if !defined(STRIP_LOG) || STRIP_LOG <= 3
# define RAW_LOG_FATAL(...) \ #define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \
google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__) __FILE__, __LINE__, __VA_ARGS__)
#else #else
#define RAW_LOG_FATAL(...) \ #define RAW_LOG_FATAL(...) \
do { \ do { \
google::RawLogStub__(0, __VA_ARGS__); \ @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} while (0) } while (0)
#endif // STRIP_LOG <= 3 #endif // STRIP_LOG <= 3
@ -149,15 +148,22 @@ namespace google {
#else // NDEBUG #else // NDEBUG
#define RAW_DLOG(severity, ...) \ #define RAW_DLOG(severity, ...) \
while (false) RAW_LOG(severity, __VA_ARGS__) while (false) \
RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) \ #define RAW_DCHECK(condition, message) \
while (false) RAW_CHECK(condition, message) while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG #endif // NDEBUG
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Stub log function used to work around for unused variable warnings when // Stub log function used to work around for unused variable warnings when
// building with STRIP_LOG > 0. // building with STRIP_LOG > 0.
static inline void RawLogStub__(int /* ignored */, ...) {} static inline void RawLogStub__(int /* ignored */, ...) {
}
// Helper function to implement RAW_LOG and RAW_VLOG // Helper function to implement RAW_LOG and RAW_VLOG
// Logs format... at "severity" level, reporting it // Logs format... at "severity" level, reporting it
@ -165,12 +171,8 @@ static inline void RawLogStub__(int /* ignored */, ...) {}
// This does not allocate memory or acquire locks. // This does not allocate memory or acquire locks.
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line, GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) const char* format, ...)
#if defined(__has_attribute) @ac_cv___attribute___printf_4_5@;
# if __has_attribute(used)
__attribute__((__format__(__printf__, 4, 5))) @ac_google_end_namespace@
# endif
#endif
;
} // namespace google
#endif // GLOG_RAW_LOGGING_H #endif // GLOG_RAW_LOGGING_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2023, Google Inc. // Copyright (c) 2003, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -35,9 +35,17 @@
// vector<int> v1, v2; // vector<int> v1, v2;
// CHECK_EQ(v1, v2); // CHECK_EQ(v1, v2);
// //
// If you want to use this header file with hash maps or slist, you
// need to define macros before including this file:
//
// - GLOG_STL_LOGGING_FOR_UNORDERED - <unordered_map> and <unordered_set>
// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - <tr1/unordered_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_HASH - <ext/hash_(map|set)>
// - GLOG_STL_LOGGING_FOR_EXT_SLIST - <ext/slist>
//
#ifndef GLOG_STL_LOGGING_H #ifndef UTIL_GTL_STL_LOGGING_INL_H_
#define GLOG_STL_LOGGING_H #define UTIL_GTL_STL_LOGGING_INL_H_
#include <deque> #include <deque>
#include <list> #include <list>
@ -55,35 +63,35 @@
template<class First, class Second> template<class First, class Second>
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p); std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
namespace google { @ac_google_start_namespace@
template<class Iter> template<class Iter>
void PrintSequence(std::ostream& out, Iter begin, Iter end); void PrintSequence(std::ostream& out, Iter begin, Iter end);
} @ac_google_end_namespace@
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \ #define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template<class T1, class T2> \ template<class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2>& seq) { \ const Sequence<T1, T2>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \ @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list) OUTPUT_TWO_ARG_CONTAINER(std::list)
#undef OUTPUT_TWO_ARG_CONTAINER #undef OUTPUT_TWO_ARG_CONTAINER
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \ #define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3> \ template<class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \ const Sequence<T1, T2, T3>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \ @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(
OUTPUT_THREE_ARG_CONTAINER(std::multiset) std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER #undef OUTPUT_THREE_ARG_CONTAINER
@ -91,37 +99,40 @@ OUTPUT_THREE_ARG_CONTAINER(std::multiset)
template<class T1, class T2, class T3, class T4> \ template<class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4>& seq) { \ const Sequence<T1, T2, T3, T4>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \ @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(
OUTPUT_FOUR_ARG_CONTAINER(std::multimap) std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)
#undef OUTPUT_FOUR_ARG_CONTAINER #undef OUTPUT_FOUR_ARG_CONTAINER
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \ #define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template<class T1, class T2, class T3, class T4, class T5> \ template<class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \ inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3, T4, T5>& seq) { \ const Sequence<T1, T2, T3, T4, T5>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \ @ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \ return out; \
} }
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map) OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap) OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
#endif
#undef OUTPUT_FIVE_ARG_CONTAINER #undef OUTPUT_FIVE_ARG_CONTAINER
template <class First, class Second> template <class First, class Second>
inline std::ostream& operator<<(std::ostream& out, inline std::ostream& operator<<(
std::ostream& out,
const std::pair<First, Second>& p) { const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')'; out << '(' << p.first << ", " << p.second << ')';
return out; return out;
} }
namespace google { @ac_google_start_namespace@
template<class Iter> template<class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) { inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
@ -135,7 +146,7 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
} }
} }
} // namespace google @ac_google_end_namespace@
// Note that this is technically undefined behavior! We are adding things into // Note that this is technically undefined behavior! We are adding things into
// the std namespace for a reason though -- we are providing new operations on // the std namespace for a reason though -- we are providing new operations on
@ -161,8 +172,6 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// move all of the *definitions* into namespace std, bet we need to ensure no // move all of the *definitions* into namespace std, bet we need to ensure no
// one references them first. This lets us take that step. We cannot define them // one references them first. This lets us take that step. We cannot define them
// in both because that would create ambiguous overloads when both are found. // in both because that would create ambiguous overloads when both are found.
namespace std { namespace std { using ::operator<<; }
using ::operator<<;
}
#endif // GLOG_STL_LOGGING_H #endif // UTIL_GTL_STL_LOGGING_INL_H_

View File

@ -1,81 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
#ifndef GLOG_TYPES_H
#define GLOG_TYPES_H
#include <cstddef>
#include <cstdint>
namespace google {
using int32 = std::int32_t;
using uint32 = std::uint32_t;
using int64 = std::int64_t;
using uint64 = std::uint64_t;
} // namespace google
#if defined(__has_feature)
# if __has_feature(thread_sanitizer)
# define GLOG_SANITIZE_THREAD 1
# endif
#endif
#if !defined(GLOG_SANITIZE_THREAD) && defined(__SANITIZE_THREAD__) && \
__SANITIZE_THREAD__
# define GLOG_SANITIZE_THREAD 1
#endif
#if defined(GLOG_SANITIZE_THREAD)
# define GLOG_IFDEF_THREAD_SANITIZER(X) X
#else
# define GLOG_IFDEF_THREAD_SANITIZER(X)
#endif
#if defined(_MSC_VER)
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n) \
__pragma(warning(push)) __pragma(warning(disable : n))
# define GLOG_MSVC_POP_WARNING() __pragma(warning(pop))
#else
# define GLOG_MSVC_PUSH_DISABLE_WARNING(n)
# define GLOG_MSVC_POP_WARNING()
#endif
#if defined(GLOG_SANITIZE_THREAD)
// We need to identify the static variables as "benign" races
// to avoid noisy reports from TSAN.
extern "C" void AnnotateBenignRaceSized(const char* file, int line,
const volatile void* mem, size_t size,
const char* description);
#endif // defined(GLOG_SANITIZE_THREAD)
#endif // GLOG_TYPES_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2023, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -58,21 +58,12 @@
// CAVEAT: --vmodule functionality is not available in non gcc compilers. // CAVEAT: --vmodule functionality is not available in non gcc compilers.
// //
#ifndef GLOG_VLOG_IS_ON_H #ifndef BASE_VLOG_IS_ON_H_
#define GLOG_VLOG_IS_ON_H #define BASE_VLOG_IS_ON_H_
#include <cstddef> #include <cstddef>
#if defined(GLOG_USE_GLOG_EXPORT) #include "glog/log_severity.h"
# include "glog/export.h"
#endif
#if !defined(GLOG_EXPORT)
# error <glog/vlog_is_on.h> was not included correctly. See the documentation for how to consume the library.
#endif
#include "glog/flags.h"
#include "glog/types.h"
#if defined(__GNUC__) #if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site. // We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
@ -82,15 +73,13 @@
// matching the current source file that represents results of // matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls. // parsing of --vmodule flag and/or SetVLOGLevel calls.
#define VLOG_IS_ON(verboselevel) \ #define VLOG_IS_ON(verboselevel) \
__extension__({ \ __extension__ \
static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \ ({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \
GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \ GLOG_IFDEF_THREAD_SANITIZER( \
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \ AnnotateBenignRaceSized(__FILE__, __LINE__, &vlocal__, sizeof(@ac_google_namespace@::SiteFlag), "")); \
google::int32 verbose_level__ = (verboselevel); \ @ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
(vlocal__.level == nullptr \ (vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \ __FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \
verbose_level__) \
: *vlocal__.level >= verbose_level__); \
}) })
#else #else
// GNU extensions not available, so we do not support --vmodule. // GNU extensions not available, so we do not support --vmodule.
@ -98,8 +87,6 @@
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel)) #define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif #endif
namespace google {
// Set VLOG(_IS_ON) level for module_pattern to log_level. // Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag. // This lets us dynamically control what is normally set by the --vmodule flag.
// Returns the level that previously applied to module_pattern. // Returns the level that previously applied to module_pattern.
@ -113,7 +100,7 @@ extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);
// Various declarations needed for VLOG_IS_ON above: ========================= // Various declarations needed for VLOG_IS_ON above: =========================
struct SiteFlag { struct SiteFlag {
int32* level; @ac_google_namespace@::int32* level;
const char* base_name; const char* base_name;
std::size_t base_len; std::size_t base_len;
SiteFlag* next; SiteFlag* next;
@ -127,10 +114,9 @@ struct SiteFlag {
// verbose_level is the argument to VLOG_IS_ON // verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON // We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately. // and if possible set *site_flag appropriately.
extern GLOG_EXPORT bool InitVLOG3__(SiteFlag* site_flag, extern GLOG_EXPORT bool InitVLOG3__(
int32* site_default, @ac_google_namespace@::SiteFlag* site_flag,
const char* fname, @ac_google_namespace@::int32* site_default, const char* fname,
int32 verbose_level); @ac_google_namespace@::int32 verbose_level);
} // namespace google
#endif // GLOG_VLOG_IS_ON_H #endif // BASE_VLOG_IS_ON_H_

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2009, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -51,16 +51,12 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "config.h" #include "utilities.h"
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
#if defined(GLOG_USE_WINDOWS_PORT)
# include "port.h"
#endif // defined(GLOG_USE_WINDOWS_PORT)
#include "base/commandlineflags.h" #include "base/commandlineflags.h"
#include "utilities.h"
#if __cplusplus < 201103L && !defined(_MSC_VER) #if __cplusplus < 201103L && !defined(_MSC_VER)
#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc) #define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc)
@ -72,19 +68,18 @@ using std::map;
using std::string; using std::string;
using std::vector; using std::vector;
namespace google { _START_GOOGLE_NAMESPACE_
extern void (*g_logging_fail_func)();
extern void GetExistingTempDirectories(std::vector<std::string>& list); extern GLOG_EXPORT void (*g_logging_fail_func)();
extern int posix_strerror_r(int err, char* buf, size_t len);
extern std::string StrError(int err); _END_GOOGLE_NAMESPACE_
} // namespace google
#undef GLOG_EXPORT #undef GLOG_EXPORT
#define GLOG_EXPORT #define GLOG_EXPORT
static inline string GetTempDir() { static inline string GetTempDir() {
vector<string> temp_directories_list; vector<string> temp_directories_list;
google::GetExistingTempDirectories(temp_directories_list); google::GetExistingTempDirectories(&temp_directories_list);
if (temp_directories_list.empty()) { if (temp_directories_list.empty()) {
fprintf(stderr, "No temporary directory found\n"); fprintf(stderr, "No temporary directory found\n");
@ -124,7 +119,7 @@ DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
using testing::InitGoogleTest; using testing::InitGoogleTest;
#else #else
namespace google { _START_GOOGLE_NAMESPACE_
void InitGoogleTest(int*, char**); void InitGoogleTest(int*, char**);
@ -135,8 +130,8 @@ void InitGoogleTest(int*, char**) {}
#define EXPECT_NEAR(val1, val2, abs_error) \ #define EXPECT_NEAR(val1, val2, abs_error) \
do { \ do { \
if (abs(val1 - val2) > abs_error) { \ if (abs(val1 - val2) > abs_error) { \
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \ fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
#abs_error, #val2); \ #val2); \
exit(EXIT_FAILURE); \ exit(EXIT_FAILURE); \
} \ } \
} while (0) } while (0)
@ -196,31 +191,18 @@ void InitGoogleTest(int*, char**) {}
} \ } \
} while (0) } while (0)
# define EXPECT_THROW(statement, exception) \
do { \
try { \
statement; \
} catch (const exception&) { \
printf("ok\n"); \
} catch (...) { \
fprintf(stderr, "%s\n", "Unexpected exception thrown"); \
exit(EXIT_FAILURE); \
} \
} while (0)
vector<void (*)()> g_testlist; // the tests to run vector<void (*)()> g_testlist; // the tests to run
#define TEST(a, b) \ #define TEST(a, b) \
struct Test_##a##_##b { \ struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \ Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run() { \ static void Run() { FlagSaver fs; RunTest(); } \
FlagSaver fs; \
RunTest(); \
} \
static void RunTest(); \ static void RunTest(); \
}; \ }; \
static Test_##a##_##b g_test_##a##_##b; \ static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::RunTest() void Test_##a##_##b::RunTest()
static inline int RUN_ALL_TESTS() { static inline int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it; vector<void (*)()>::const_iterator it;
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) { for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
@ -231,11 +213,11 @@ static inline int RUN_ALL_TESTS() {
return 0; return 0;
} }
} // namespace google _END_GOOGLE_NAMESPACE_
#endif // ! HAVE_LIB_GTEST #endif // ! HAVE_LIB_GTEST
namespace google { _START_GOOGLE_NAMESPACE_
static bool g_called_abort; static bool g_called_abort;
static jmp_buf g_jmp_buf; static jmp_buf g_jmp_buf;
@ -315,34 +297,43 @@ static inline void RunSpecifiedBenchmarks() {
class CapturedStream { class CapturedStream {
public: public:
CapturedStream(int fd, string filename) CapturedStream(int fd, string filename)
: fd_(fd), filename_(std::move(filename)) { : fd_(fd),
filename_(std::move(filename)) {
Capture(); Capture();
} }
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file // Start redirecting output to a file
void Capture() { void Capture() {
// Keep original stream for later // Keep original stream for later
CHECK(!uncaptured_fd_) << ", Stream " << fd_ << " already captured!"; CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_.reset(dup(fd_)); uncaptured_fd_ = dup(fd_);
CHECK(uncaptured_fd_); CHECK(uncaptured_fd_ != -1);
// Open file to save stream to // Open file to save stream to
FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY, int cap_fd = open(filename_.c_str(),
S_IRUSR | S_IWUSR)}; O_CREAT | O_TRUNC | O_WRONLY,
CHECK(cap_fd); S_IRUSR | S_IWUSR);
CHECK(cap_fd != -1);
// Send stdout/stderr to this file // Send stdout/stderr to this file
fflush(nullptr); fflush(nullptr);
CHECK(dup2(cap_fd.get(), fd_) != -1); CHECK(dup2(cap_fd, fd_) != -1);
CHECK(cap_fd.close() != -1); CHECK(close(cap_fd) != -1);
} }
// Remove output redirection // Remove output redirection
void StopCapture() { void StopCapture() {
// Restore original stream // Restore original stream
if (uncaptured_fd_) { if (uncaptured_fd_ != -1) {
fflush(nullptr); fflush(nullptr);
CHECK(dup2(uncaptured_fd_.get(), fd_) != -1); CHECK(dup2(uncaptured_fd_, fd_) != -1);
} }
} }
@ -350,24 +341,23 @@ class CapturedStream {
private: private:
int fd_; // file descriptor being captured int fd_; // file descriptor being captured
FileDescriptor int uncaptured_fd_{-1}; // where the stream was originally being sent to
uncaptured_fd_; // where the stream was originally being sent to
string filename_; // file where stream is being saved string filename_; // file where stream is being saved
}; };
static std::map<int, std::unique_ptr<CapturedStream>> s_captured_streams; static CapturedStream * s_captured_streams[STDERR_FILENO+1];
// Redirect a file descriptor to a file. // Redirect a file descriptor to a file.
// fd - Should be stdout or stderr // fd - Should be STDOUT_FILENO or STDERR_FILENO
// filename - File where output should be stored // filename - File where output should be stored
static inline void CaptureTestOutput(int fd, const string & filename) { static inline void CaptureTestOutput(int fd, const string & filename) {
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr))); CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
CHECK(s_captured_streams.find(fd) == s_captured_streams.end()); CHECK(s_captured_streams[fd] == nullptr);
s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename); s_captured_streams[fd] = new CapturedStream(fd, filename);
} }
static inline void CaptureTestStdout() { static inline void CaptureTestStdout() {
CaptureTestOutput(fileno(stdout), FLAGS_test_tmpdir + "/captured.out"); CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
} }
static inline void CaptureTestStderr() { static inline void CaptureTestStderr() {
CaptureTestOutput(fileno(stderr), FLAGS_test_tmpdir + "/captured.err"); CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
} }
// Return the size (in bytes) of a file // Return the size (in bytes) of a file
static inline size_t GetFileSize(FILE * file) { static inline size_t GetFileSize(FILE * file) {
@ -377,7 +367,7 @@ static inline size_t GetFileSize(FILE* file) {
// Read the entire content of a file as a string // Read the entire content of a file as a string
static inline string ReadEntireFile(FILE * file) { static inline string ReadEntireFile(FILE * file) {
const size_t file_size = GetFileSize(file); const size_t file_size = GetFileSize(file);
std::vector<char> content(file_size); char * const buffer = new char[file_size];
size_t bytes_last_read = 0; // # of bytes read in the last fread() size_t bytes_last_read = 0; // # of bytes read in the last fread()
size_t bytes_read = 0; // # of bytes read so far size_t bytes_read = 0; // # of bytes read so far
@ -387,33 +377,39 @@ static inline string ReadEntireFile(FILE* file) {
// Keep reading the file until we cannot read further or the // Keep reading the file until we cannot read further or the
// pre-determined file size is reached. // pre-determined file size is reached.
do { do {
bytes_last_read = bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
fread(content.data() + bytes_read, 1, file_size - bytes_read, file);
bytes_read += bytes_last_read; bytes_read += bytes_last_read;
} while (bytes_last_read > 0 && bytes_read < file_size); } while (bytes_last_read > 0 && bytes_read < file_size);
return std::string(content.data(), bytes_read); const string content = string(buffer, buffer+bytes_read);
delete[] buffer;
return content;
} }
// Get the captured stdout or stderr as a string // Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
// fd is STDERR_FILENO) as a string
static inline string GetCapturedTestOutput(int fd) { static inline string GetCapturedTestOutput(int fd) {
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr))); CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams.at(fd)); CapturedStream * const cap = s_captured_streams[fd];
s_captured_streams.erase(fd); CHECK(cap)
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?"; << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed. // Make sure everything is flushed.
cap->StopCapture(); cap->StopCapture();
// Read the captured file. // Read the captured file.
std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), "r")}; FILE * const file = fopen(cap->filename().c_str(), "r");
const string content = ReadEntireFile(file.get()); const string content = ReadEntireFile(file);
file.reset(); fclose(file);
delete cap;
s_captured_streams[fd] = nullptr;
return content; return content;
} }
// Get the captured stderr of a test as a string. // Get the captured stderr of a test as a string.
static inline string GetCapturedTestStderr() { static inline string GetCapturedTestStderr() {
return GetCapturedTestOutput(fileno(stderr)); return GetCapturedTestOutput(STDERR_FILENO);
} }
static const std::size_t kLoggingPrefixLength = 9; static const std::size_t kLoggingPrefixLength = 9;
@ -472,7 +468,8 @@ static inline string MungeLine(const string& line) {
MungeLine(rest)); MungeLine(rest));
} }
static inline void StringReplace(string* str, const string& oldsub, static inline void StringReplace(string* str,
const string& oldsub,
const string& newsub) { const string& newsub) {
size_t pos = str->find(oldsub); size_t pos = str->find(oldsub);
if (pos != string::npos) { if (pos != string::npos) {
@ -481,18 +478,17 @@ static inline void StringReplace(string* str, const string& oldsub,
} }
static inline string Munge(const string& filename) { static inline string Munge(const string& filename) {
std::unique_ptr<FILE> fp{fopen(filename.c_str(), "rb")}; FILE* fp = fopen(filename.c_str(), "rb");
CHECK(fp != nullptr) << filename << ": couldn't open"; CHECK(fp != nullptr) << filename << ": couldn't open";
char buf[4096]; char buf[4096];
string result; string result;
while (fgets(buf, 4095, fp.get())) { while (fgets(buf, 4095, fp)) {
string line = MungeLine(buf); string line = MungeLine(buf);
const size_t str_size = 256; const size_t str_size = 256;
char null_str[str_size]; char null_str[str_size];
char ptr_str[str_size]; char ptr_str[str_size];
std::snprintf(null_str, str_size, "%p", static_cast<void*>(nullptr)); snprintf(null_str, str_size, "%p", static_cast<void*>(nullptr));
std::snprintf(ptr_str, str_size, "%p", snprintf(ptr_str, str_size, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
reinterpret_cast<void*>(PTR_TEST_VALUE));
StringReplace(&line, "__NULLP__", null_str); StringReplace(&line, "__NULLP__", null_str);
StringReplace(&line, "__PTRTEST__", ptr_str); StringReplace(&line, "__PTRTEST__", ptr_str);
@ -504,19 +500,19 @@ static inline string Munge(const string& filename) {
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC)); StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
result += line + "\n"; result += line + "\n";
} }
fclose(fp);
return result; return result;
} }
static inline void WriteToFile(const string& body, const string& file) { static inline void WriteToFile(const string& body, const string& file) {
std::unique_ptr<FILE> fp{fopen(file.c_str(), "wb")}; FILE* fp = fopen(file.c_str(), "wb");
fwrite(body.data(), 1, body.size(), fp.get()); fwrite(body.data(), 1, body.size(), fp);
fclose(fp);
} }
static inline bool MungeAndDiffTest(const string& golden_filename, static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) { CapturedStream* cap) {
auto pos = s_captured_streams.find(fileno(stdout)); if (cap == s_captured_streams[STDOUT_FILENO]) {
if (pos != s_captured_streams.end() && cap == pos->second.get()) {
CHECK(cap) << ": did you forget CaptureTestStdout()?"; CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else { } else {
CHECK(cap) << ": did you forget CaptureTestStderr()?"; CHECK(cap) << ": did you forget CaptureTestStderr()?";
@ -551,17 +547,15 @@ static inline bool MungeAndDiffTest(const string& golden_filename,
} }
static inline bool MungeAndDiffTestStderr(const string& golden_filename) { static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
s_captured_streams.at(fileno(stderr)).get());
} }
static inline bool MungeAndDiffTestStdout(const string& golden_filename) { static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename, return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
s_captured_streams.at(fileno(stdout)).get());
} }
// Save flags used from logging_unittest.cc. // Save flags used from logging_unittest.cc.
#ifndef GLOG_USE_GFLAGS #ifndef HAVE_LIB_GFLAGS
struct FlagSaver { struct FlagSaver {
FlagSaver() FlagSaver()
: v_(FLAGS_v), : v_(FLAGS_v),
@ -584,15 +578,70 @@ struct FlagSaver {
}; };
#endif #endif
class Thread {
public:
virtual ~Thread() = default;
void SetJoinable(bool) {}
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
void Start() {
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
CHECK(handle_) << "CreateThread";
}
void Join() {
WaitForSingleObject(handle_, INFINITE);
}
#elif defined(HAVE_PTHREAD)
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
void Join() { pthread_join(th_, nullptr); }
#else
void Start() {}
void Join() {}
#endif
protected:
virtual void Run() = 0;
private:
static void* InvokeThread(void* self) {
(static_cast<Thread*>(self))->Run();
return nullptr;
}
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
static DWORD __stdcall InvokeThreadW(LPVOID self) {
InvokeThread(self);
return 0;
}
HANDLE handle_;
DWORD th_;
#elif defined(HAVE_PTHREAD)
pthread_t th_;
#endif
};
static inline void SleepForMilliseconds(unsigned t) {
#ifndef GLOG_OS_WINDOWS
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
const struct timespec req = {0, t * 1000 * 1000};
nanosleep(&req, nullptr);
# else
usleep(t * 1000);
# endif
#else
Sleep(t);
#endif
}
// Add hook for operator new to ensure there are no memory allocation. // Add hook for operator new to ensure there are no memory allocation.
void (*g_new_hook)() = nullptr; void (*g_new_hook)() = nullptr;
} // namespace google _END_GOOGLE_NAMESPACE_
void* operator new(size_t size, const std::nothrow_t&) noexcept { void* operator new(size_t size, const std::nothrow_t&) noexcept {
if (google::g_new_hook) { if (GOOGLE_NAMESPACE::g_new_hook) {
google::g_new_hook(); GOOGLE_NAMESPACE::g_new_hook();
} }
return malloc(size); return malloc(size);
} }

View File

@ -1,16 +0,0 @@
cmake_minimum_required (VERSION 3.16)
project (glog_includes LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_includes_logging glog_includes_logging.cc)
target_link_libraries (glog_includes_logging PRIVATE glog::glog)
add_executable (glog_includes_vlog_is_on glog_includes_vlog_is_on.cc)
target_link_libraries (glog_includes_vlog_is_on PRIVATE glog::glog)
add_executable (glog_includes_raw_logging glog_includes_raw_logging.cc)
target_link_libraries (glog_includes_raw_logging PRIVATE glog::glog)
add_executable (glog_includes_stl_logging glog_includes_stl_logging.cc)
target_link_libraries (glog_includes_stl_logging PRIVATE glog::glog)

View File

@ -1,39 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
LOG(INFO) << "info";
LOG(WARNING) << "warning";
LOG(ERROR) << "error";
LOG(FATAL) << "fatal";
}

View File

@ -1,39 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/raw_logging.h>
int main() {
RAW_LOG(INFO, "info");
RAW_LOG(WARNING, "warning");
RAW_LOG(ERROR, "error");
RAW_LOG(FATAL, "fatal");
}

View File

@ -1,10 +0,0 @@
cmake_minimum_required (VERSION 3.16)
project (glog_log_severity LANGUAGES CXX)
find_package (glog REQUIRED NO_MODULE)
add_executable (glog_log_severity_constants glog_log_severity_constants.cc)
target_link_libraries (glog_log_severity_constants PRIVATE glog::glog)
add_executable (glog_log_severity_conversion glog_log_severity_conversion.cc)
target_link_libraries (glog_log_severity_conversion PRIVATE glog::glog)

View File

@ -1,40 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
// Must not compile
LOG(0) << "type unsafe info";
LOG(1) << "type unsafe info";
LOG(2) << "type unsafe info";
LOG(3) << "type unsafe info";
}

View File

@ -1,42 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Sergiu Deitsch
#include <glog/logging.h>
int main() {
// Must not compile
google::LogMessage{__FILE__, __LINE__, -1};
// Cast to int to avoid implicit conversoin to nullptr
google::LogMessage{__FILE__, __LINE__, static_cast<int>(0)};
google::LogMessage{__FILE__, __LINE__, 1};
google::LogMessage{__FILE__, __LINE__, 2};
google::LogMessage{__FILE__, __LINE__, 3};
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
#! /bin/sh #! /bin/sh
# #
# Copyright (c) 2023, Google Inc. # Copyright (c) 2007, Google Inc.
# All rights reserved. # All rights reserved.
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -32,8 +32,8 @@
# Author: Sergey Ioffe # Author: Sergey Ioffe
get_strings () { get_strings () {
if test -e "$1"; then if test -e ".libs/$1"; then
binary="$1" binary=".libs/$1"
elif test -e "$1.exe"; then elif test -e "$1.exe"; then
binary="$1.exe" binary="$1.exe"
else else
@ -60,21 +60,20 @@ die () {
# Check that the string literals are appropriately stripped. This will # Check that the string literals are appropriately stripped. This will
# not be the case in debug mode. # not be the case in debug mode.
mode=`GLOG_check_mode=1 ./striplog0_unittest 2> /dev/null` mode=`GLOG_check_mode=1 ./logging_striptest0 2> /dev/null`
echo $mode
if [ "$mode" = "opt" ]; if [ "$mode" = "opt" ];
then then
echo "In OPT mode" echo "In OPT mode"
check_eq "`get_strings striplog0_unittest`" "COND ERROR FATAL INFO WARNING " check_eq "`get_strings logging_striptest0`" "COND ERROR FATAL INFO USAGE WARNING "
check_eq "`get_strings striplog2_unittest`" "COND ERROR FATAL " check_eq "`get_strings logging_striptest2`" "COND ERROR FATAL USAGE "
check_eq "`get_strings striplog10_unittest`" "" check_eq "`get_strings logging_striptest10`" ""
else else
echo "In DBG mode; not checking strings" echo "In DBG mode; not checking strings"
fi fi
# Check that LOG(FATAL) aborts even for large STRIP_LOG # Check that LOG(FATAL) aborts even for large STRIP_LOG
./striplog2_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=2" ./logging_striptest2 2>/dev/null && die "Did not abort for STRIP_LOG=2"
./striplog10_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=10" ./logging_striptest10 2>/dev/null && die "Did not abort for STRIP_LOG=10"
echo "PASS" echo "PASS"

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2007, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,8 +27,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// Author: Sergiu Deitsch // Author: Sergey Ioffe
#include <glog/vlog_is_on.h> #define GOOGLE_STRIP_LOG 10
int main() { VLOG_IS_ON(0); } // Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2007, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -27,8 +27,9 @@
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// Author: Sergiu Deitsch // Author: Sergey Ioffe
#include <glog/stl_logging.h> #define GOOGLE_STRIP_LOG 2
int main() {} // Include the actual test.
#include "logging_striptest_main.cc"

View File

@ -1,4 +1,4 @@
// Copyright (c) 2023, Google Inc. // Copyright (c) 2007, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,9 +31,7 @@
// The common part of the striplog tests. // The common part of the striplog tests.
#include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib>
#include <iosfwd> #include <iosfwd>
#include <string> #include <string>
@ -41,16 +39,16 @@
#include "config.h" #include "config.h"
#include "glog/logging.h" #include "glog/logging.h"
DECLARE_bool(logtostderr);
GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'"); GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'");
using std::string; using std::string;
using namespace google; using namespace GOOGLE_NAMESPACE;
int CheckNoReturn(bool b) { int CheckNoReturn(bool b) {
string s; string s;
if (b) { if (b) {
LOG(FATAL) << "Fatal"; LOG(FATAL) << "Fatal";
return 0; // Workaround for MSVC warning C4715
} else { } else {
return 0; return 0;
} }
@ -59,18 +57,7 @@ int CheckNoReturn(bool b) {
struct A { }; struct A { };
std::ostream &operator<<(std::ostream &str, const A&) {return str;} std::ostream &operator<<(std::ostream &str, const A&) {return str;}
namespace {
void handle_abort(int /*code*/) { std::exit(EXIT_FAILURE); }
} // namespace
int main(int, char* argv[]) { int main(int, char* argv[]) {
#if defined(_MSC_VER)
// Avoid presenting an interactive dialog that will cause the test to time
// out.
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
#endif // defined(_MSC_VER)
std::signal(SIGABRT, handle_abort);
FLAGS_logtostderr = true; FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);
if (FLAGS_check_mode) { if (FLAGS_check_mode) {
@ -78,8 +65,8 @@ int main(int, char* argv[]) {
return 0; return 0;
} }
LOG(INFO) << "TESTMESSAGE INFO"; LOG(INFO) << "TESTMESSAGE INFO";
LOG(WARNING) << 2 << "something" LOG(WARNING) << 2 << "something" << "TESTMESSAGE WARNING"
<< "TESTMESSAGE WARNING" << 1 << 'c' << A() << std::endl; << 1 << 'c' << A() << std::endl;
LOG(ERROR) << "TESTMESSAGE ERROR"; LOG(ERROR) << "TESTMESSAGE ERROR";
bool flag = true; bool flag = true;
(flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND"; (flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND";

File diff suppressed because it is too large Load Diff

View File

@ -35,7 +35,7 @@
#ifndef GLOG_SRC_MOCK_LOG_H_ #ifndef GLOG_SRC_MOCK_LOG_H_
#define GLOG_SRC_MOCK_LOG_H_ #define GLOG_SRC_MOCK_LOG_H_
// For google. This must go first so we get _XOPEN_SOURCE. // For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE.
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <string> #include <string>
@ -43,7 +43,7 @@
#include "glog/logging.h" #include "glog/logging.h"
#include "utilities.h" #include "utilities.h"
namespace google { _START_GOOGLE_NAMESPACE_
namespace glog_testing { namespace glog_testing {
// A ScopedMockLog object intercepts LOG() messages issued during its // A ScopedMockLog object intercepts LOG() messages issued during its
@ -64,7 +64,7 @@ namespace glog_testing {
// //
// Foo(); // Exercises the code under test. // Foo(); // Exercises the code under test.
// } // }
class ScopedMockLog : public google::LogSink { class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
public: public:
// When a ScopedMockLog object is constructed, it starts to // When a ScopedMockLog object is constructed, it starts to
// intercept logs. // intercept logs.
@ -86,8 +86,8 @@ class ScopedMockLog : public google::LogSink {
// for messages from different threads. In fact, if the same or multiple // for messages from different threads. In fact, if the same or multiple
// expectations are matched on two threads concurrently, their actions will // expectations are matched on two threads concurrently, their actions will
// be executed concurrently as well and may interleave. // be executed concurrently as well and may interleave.
MOCK_METHOD3(Log, MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity,
void(google::LogSeverity severity, const std::string& file_path, const std::string& file_path,
const std::string& message)); const std::string& message));
private: private:
@ -112,7 +112,7 @@ class ScopedMockLog : public google::LogSink {
// be running simultaneously, we ensure thread-safety of the exchange between // be running simultaneously, we ensure thread-safety of the exchange between
// send() and WaitTillSent(), and that for each message, LOG(), send(), // send() and WaitTillSent(), and that for each message, LOG(), send(),
// WaitTillSent() and Log() are executed in the same thread. // WaitTillSent() and Log() are executed in the same thread.
void send(google::LogSeverity severity, const char* full_filename, void send(GOOGLE_NAMESPACE::LogSeverity severity, const char* full_filename,
const char* /*base_filename*/, int /*line*/, const char* /*base_filename*/, int /*line*/,
const LogMessageTime& /*logmsgtime*/, const char* message, const LogMessageTime& /*logmsgtime*/, const char* message,
size_t message_len) override { size_t message_len) override {
@ -141,7 +141,7 @@ class ScopedMockLog : public google::LogSink {
// All relevant information about a logged message that needs to be passed // All relevant information about a logged message that needs to be passed
// from send() to WaitTillSent(). // from send() to WaitTillSent().
struct MessageInfo { struct MessageInfo {
google::LogSeverity severity; GOOGLE_NAMESPACE::LogSeverity severity;
std::string file_path; std::string file_path;
std::string message; std::string message;
}; };
@ -149,6 +149,6 @@ class ScopedMockLog : public google::LogSink {
}; };
} // namespace glog_testing } // namespace glog_testing
} // namespace google _END_GOOGLE_NAMESPACE_
#endif // GLOG_SRC_MOCK_LOG_H_ #endif // GLOG_SRC_MOCK_LOG_H_

View File

@ -33,17 +33,17 @@
#include "mock-log.h" #include "mock-log.h"
#include <string>
#include <gmock/gmock.h> #include <gmock/gmock.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string>
namespace { namespace {
using google::GLOG_ERROR; using GOOGLE_NAMESPACE::GLOG_ERROR;
using google::GLOG_INFO; using GOOGLE_NAMESPACE::GLOG_INFO;
using google::GLOG_WARNING; using GOOGLE_NAMESPACE::GLOG_WARNING;
using google::glog_testing::ScopedMockLog; using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using std::string; using std::string;
using testing::_; using testing::_;
using testing::EndsWith; using testing::EndsWith;
@ -57,7 +57,8 @@ TEST(ScopedMockLogTest, InterceptsLog) {
InSequence s; InSequence s;
EXPECT_CALL(log, EXPECT_CALL(log,
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy.")); Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")).Times(2); EXPECT_CALL(log, Log(GLOG_INFO, _, "Working..."))
.Times(2);
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!")); EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
LOG(WARNING) << "Fishy."; LOG(WARNING) << "Fishy.";
@ -66,9 +67,13 @@ TEST(ScopedMockLogTest, InterceptsLog) {
LOG(ERROR) << "Bad!!"; LOG(ERROR) << "Bad!!";
} }
void LogBranch() { LOG(INFO) << "Logging a branch..."; } void LogBranch() {
LOG(INFO) << "Logging a branch...";
}
void LogTree() { LOG(INFO) << "Logging the whole tree..."; } void LogTree() {
LOG(INFO) << "Logging the whole tree...";
}
void LogForest() { void LogForest() {
LOG(INFO) << "Logging the entire forest."; LOG(INFO) << "Logging the entire forest.";
@ -95,7 +100,7 @@ TEST(ScopedMockLogTest, LogDuringIntercept) {
} // namespace } // namespace
int main(int argc, char **argv) { int main(int argc, char **argv) {
google::InitGoogleLogging(argv[0]); GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]);
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv); testing::InitGoogleMock(&argc, argv);

View File

@ -1,3 +1,6 @@
#include "glog/logging.h" #include "glog/logging.h"
int main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); } int main(int /*argc*/, char** argv)
{
google::InitGoogleLogging(argv[0]);
}

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,20 +31,27 @@
// //
// logging_unittest.cc covers the functionality herein // logging_unittest.cc covers the functionality herein
#include <cerrno>
#include <cstdarg> #include <cstdarg>
#include <cstdio> #include <cstdio>
#include <cstring>
#include <iomanip>
#include <mutex>
#include <ostream>
#include <streambuf>
#include <thread>
#include "config.h"
#include "utilities.h"
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> // for close() and write() # include <unistd.h> // for close() and write()
#endif #endif
#include <fcntl.h> // for open()
#include <ctime>
#include "base/commandlineflags.h"
#include "config.h"
#include "glog/logging.h" // To pick up flag settings etc.
#include "glog/raw_logging.h"
#ifdef HAVE_STACKTRACE
# include "stacktrace.h"
#endif
#if defined(HAVE_SYSCALL_H) #if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall() #include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H) #elif defined(HAVE_SYS_SYSCALL_H)
@ -53,12 +60,6 @@
#ifdef HAVE_UNISTD_H #ifdef HAVE_UNISTD_H
# include <unistd.h> # include <unistd.h>
#endif #endif
#include <fcntl.h> // for open()
#include "glog/logging.h"
#include "glog/raw_logging.h"
#include "stacktrace.h"
#include "utilities.h"
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \ #if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \ (!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
@ -69,7 +70,7 @@
#define safe_write(fd, s, len) write(fd, s, len) #define safe_write(fd, s, len) write(fd, s, len)
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
#if defined(__GNUC__) #if defined(__GNUC__)
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \ #define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
@ -81,10 +82,10 @@ namespace google {
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) #define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#endif #endif
// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code // CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
// paths that invoke malloc() and getenv() that might acquire some locks. If // that invoke malloc() and getenv() that might acquire some locks.
// this becomes a problem we should reimplement a subset of std::vsnprintf that // If this becomes a problem we should reimplement a subset of vsnprintf
// does not need locks and malloc. // that does not need locks and malloc.
// Helper for RawLog__ below. // Helper for RawLog__ below.
// *DoRawLog writes to *buf of *size and move them past the written portion. // *DoRawLog writes to *buf of *size and move them past the written portion.
@ -93,7 +94,7 @@ GLOG_ATTRIBUTE_FORMAT(printf, 3, 4)
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) { static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
int n = std::vsnprintf(*buf, *size, format, ap); int n = vsnprintf(*buf, *size, format, ap);
va_end(ap); va_end(ap);
if (n < 0 || static_cast<size_t>(n) > *size) return false; if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n); *size -= static_cast<size_t>(n);
@ -102,13 +103,13 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
} }
// Helper for RawLog__ below. // Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, size_t* size, const char* format, inline static bool VADoRawLog(char** buf, size_t* size,
va_list ap) { const char* format, va_list ap) {
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral" #pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif #endif
int n = std::vsnprintf(*buf, *size, format, ap); int n = vsnprintf(*buf, *size, format, ap);
#if defined(__GNUC__) #if defined(__GNUC__)
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif #endif
@ -119,30 +120,10 @@ inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
} }
static const int kLogBufSize = 3000; static const int kLogBufSize = 3000;
static std::once_flag crashed; static bool crashed = false;
static logging::internal::CrashReason crash_reason; static CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0' static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
namespace {
template <std::size_t N>
class StaticStringBuf : public std::streambuf {
public:
StaticStringBuf() {
setp(std::begin(data_), std::end(data_));
setg(std::begin(data_), std::begin(data_), std::end(data_));
}
const char* data() noexcept {
if (pptr() != pbase() && pptr() != epptr() && *(pptr() - 1) != '\0') {
sputc('\0');
}
return data_;
}
private:
char data_[N];
};
} // namespace
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5) GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
void RawLog__(LogSeverity severity, const char* file, int line, void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...) { const char* format, ...) {
@ -151,24 +132,15 @@ void RawLog__(LogSeverity severity, const char* file, int line,
!IsGoogleLoggingInitialized())) { !IsGoogleLoggingInitialized())) {
return; // this stderr log message is suppressed return; // this stderr log message is suppressed
} }
// We do not have any any option other that string streams to obtain the
// thread identifier as the corresponding value is not convertible to an
// integer. Use a statically allocated buffer to avoid dynamic memory
// allocations.
StaticStringBuf<kLogBufSize> sbuf;
std::ostream oss(&sbuf);
oss << std::setw(5) << std::this_thread::get_id();
// can't call localtime_r here: it can allocate // can't call localtime_r here: it can allocate
char buffer[kLogBufSize]; char buffer[kLogBufSize];
char* buf = buffer; char* buf = buffer;
size_t size = sizeof(buffer); size_t size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h // NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %s %s:%d] RAW: ", DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
GetLogSeverityName(severity)[0], sbuf.data(), LogSeverityNames[severity][0],
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line); const_basename(const_cast<char *>(file)), line);
// Record the position and size of the buffer after the prefix // Record the position and size of the buffer after the prefix
@ -188,9 +160,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing // avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception). // libc (to side-step any libc interception).
// We write just once to avoid races with other invocations of RawLog__. // We write just once to avoid races with other invocations of RawLog__.
safe_write(fileno(stderr), buffer, strlen(buffer)); safe_write(STDERR_FILENO, buffer, strlen(buffer));
if (severity == GLOG_FATAL) { if (severity == GLOG_FATAL) {
std::call_once(crashed, [file, line, msg_start, msg_size] { if (!sync_val_compare_and_swap(&crashed, false, true)) {
crash_reason.filename = file; crash_reason.filename = file;
crash_reason.line_number = line; crash_reason.line_number = line;
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
@ -202,9 +174,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
crash_reason.depth = 0; crash_reason.depth = 0;
#endif #endif
SetCrashReason(&crash_reason); SetCrashReason(&crash_reason);
}); }
LogMessage::Fail(); // abort() LogMessage::Fail(); // abort()
} }
} }
} // namespace google _END_GOOGLE_NAMESPACE_

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -31,36 +31,22 @@
// //
// Implementation of InstallFailureSignalHandler(). // Implementation of InstallFailureSignalHandler().
#include <algorithm>
#include <csignal> #include <csignal>
#include <cstring>
#include <ctime> #include <ctime>
#include <mutex>
#include <sstream>
#include <thread>
#include "config.h"
#include "glog/logging.h" #include "glog/logging.h"
#include "glog/platform.h"
#include "stacktrace.h" #include "stacktrace.h"
#include "symbolize.h" #include "symbolize.h"
#include "utilities.h" #include "utilities.h"
#ifdef HAVE_UCONTEXT_H #ifdef HAVE_UCONTEXT_H
# include <ucontext.h> # include <ucontext.h>
#endif #endif
#ifdef HAVE_SYS_UCONTEXT_H #ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h> # include <sys/ucontext.h>
#endif #endif
#ifdef HAVE_UNISTD_H #include <algorithm>
# include <unistd.h>
#endif
#if defined(HAVE_SYS_SYSCALL_H) && defined(HAVE_SYS_TYPES_H)
# include <sys/syscall.h>
# include <sys/types.h>
#endif
namespace google { _START_GOOGLE_NAMESPACE_
namespace { namespace {
@ -73,8 +59,10 @@ const struct {
int number; int number;
const char *name; const char *name;
} kFailureSignals[] = { } kFailureSignals[] = {
{SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"}, { SIGSEGV, "SIGSEGV" },
{SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"}, { SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
{ SIGBUS, "SIGBUS" }, { SIGBUS, "SIGBUS" },
#endif #endif
@ -86,8 +74,7 @@ static bool kFailureSignalHandlerInstalled = false;
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
// Returns the program counter from signal context, nullptr if unknown. // Returns the program counter from signal context, nullptr if unknown.
void* GetPC(void* ucontext_in_void) { void* GetPC(void* ucontext_in_void) {
# if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \ #if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
defined(PC_FROM_UCONTEXT)
if (ucontext_in_void != nullptr) { if (ucontext_in_void != nullptr) {
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void); ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
return (void*)context->PC_FROM_UCONTEXT; return (void*)context->PC_FROM_UCONTEXT;
@ -104,12 +91,13 @@ void* GetPC(void* ucontext_in_void) {
class MinimalFormatter { class MinimalFormatter {
public: public:
MinimalFormatter(char *buffer, size_t size) MinimalFormatter(char *buffer, size_t size)
: buffer_(buffer), cursor_(buffer), end_(buffer + size) {} : buffer_(buffer),
cursor_(buffer),
end_(buffer + size) {
}
// Returns the number of bytes written in the buffer. // Returns the number of bytes written in the buffer.
std::size_t num_bytes_written() const { std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
return static_cast<std::size_t>(cursor_ - buffer_);
}
// Appends string from "str" and updates the internal cursor. // Appends string from "str" and updates the internal cursor.
void AppendString(const char* str) { void AppendString(const char* str) {
@ -162,7 +150,7 @@ class MinimalFormatter {
// Writes the given data with the size to the standard error. // Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, size_t size) { void WriteToStderr(const char* data, size_t size) {
if (write(fileno(stderr), data, size) < 0) { if (write(STDERR_FILENO, data, size) < 0) {
// Ignore errors. // Ignore errors.
} }
} }
@ -215,19 +203,15 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
formatter.AppendString(")"); formatter.AppendString(")");
formatter.AppendString(" received by PID "); formatter.AppendString(" received by PID ");
formatter.AppendUint64(static_cast<uint64>(getpid()), 10); formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
formatter.AppendString(" (TID "); formatter.AppendString(" (TID 0x");
// We assume pthread_t is an integral number or a pointer, rather
std::ostringstream oss; // than a complex struct. In some environments, pthread_self()
oss << std::showbase << std::hex << std::this_thread::get_id(); // returns an uint64 but in some other environments pthread_self()
formatter.AppendString(oss.str().c_str()); // returns a pointer.
# if defined(GLOG_OS_LINUX) && defined(HAVE_SYS_SYSCALL_H) && \ pthread_t id = pthread_self();
defined(HAVE_SYS_TYPES_H) formatter.AppendUint64(
pid_t tid = syscall(SYS_gettid); reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
formatter.AppendString(" LWP ");
formatter.AppendUint64(static_cast<uint64>(tid), 10);
# endif
formatter.AppendString(") "); formatter.AppendString(") ");
// Only linux has the PID of the signal sender in si_pid. // Only linux has the PID of the signal sender in si_pid.
#ifdef GLOG_OS_LINUX #ifdef GLOG_OS_LINUX
formatter.AppendString("from PID "); formatter.AppendString("from PID ");
@ -244,18 +228,13 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
void DumpStackFrameInfo(const char* prefix, void* pc) { void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name. // Get the symbol name.
const char *symbol = "(unknown)"; const char *symbol = "(unknown)";
#if defined(HAVE_SYMBOLIZE)
char symbolized[1024]; // Big enough for a sane symbol. char symbolized[1024]; // Big enough for a sane symbol.
// Symbolizes the previous address of pc because pc may be in the // Symbolizes the previous address of pc because pc may be in the
// next function. // next function.
if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized, if (Symbolize(reinterpret_cast<char *>(pc) - 1,
sizeof(symbolized))) { symbolized, sizeof(symbolized))) {
symbol = symbolized; symbol = symbolized;
} }
#else
# pragma message( \
"Symbolize functionality is not available for target platform: stack dump will contain empty frames.")
#endif // defined(HAVE_SYMBOLIZE)
char buf[1024]; // Big enough for stack frame info. char buf[1024]; // Big enough for stack frame info.
MinimalFormatter formatter(buf, sizeof(buf)); MinimalFormatter formatter(buf, sizeof(buf));
@ -285,19 +264,52 @@ void InvokeDefaultSignalHandler(int signal_number) {
#endif #endif
} }
// This variable is used for protecting FailureSignalHandler() from dumping // This variable is used for protecting FailureSignalHandler() from
// stuff while another thread is doing it. Our policy is to let the first // dumping stuff while another thread is doing it. Our policy is to let
// thread dump stuff and let other threads do nothing. // the first thread dump stuff and let other threads wait.
// See also comments in FailureSignalHandler(). // See also comments in FailureSignalHandler().
static std::once_flag signaled; static pthread_t* g_entered_thread_id_pointer = nullptr;
static void HandleSignal(int signal_number // Dumps signal and stack frame information, and invokes the default
#if !defined(GLOG_OS_WINDOWS) // signal handler once our job is done.
, #if defined(GLOG_OS_WINDOWS)
siginfo_t* signal_info, void* ucontext void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number,
siginfo_t *signal_info,
void *ucontext)
#endif #endif
) { {
// First check if we've already entered the function. We use an atomic
// compare and swap operation for platforms that support it. For other
// platforms, we use a naive method that could lead to a subtle race.
// We assume pthread_self() is async signal safe, though it's not
// officially guaranteed.
pthread_t my_thread_id = pthread_self();
// NOTE: We could simply use pthread_t rather than pthread_t* for this,
// if pthread_self() is guaranteed to return non-zero value for thread
// ids, but there is no such guarantee. We need to distinguish if the
// old value (value returned from __sync_val_compare_and_swap) is
// different from the original value (in this case nullptr).
pthread_t* old_thread_id_pointer =
glog_internal_namespace_::sync_val_compare_and_swap(
&g_entered_thread_id_pointer, static_cast<pthread_t*>(nullptr),
&my_thread_id);
if (old_thread_id_pointer != nullptr) {
// We've already entered the signal handler. What should we do?
if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
// It looks the current thread is reentering the signal handler.
// Something must be going wrong (maybe we are reentering by another
// type of signal?). Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number);
}
// Another thread is dumping stuff. Let's wait until that thread
// finishes the job and kills the process.
while (true) {
sleep(1);
}
}
// This is the first time we enter the signal handler. We are going to // This is the first time we enter the signal handler. We are going to
// do some interesting stuff from here. // do some interesting stuff from here.
// TODO(satorux): We might want to set timeout here using alarm(), but // TODO(satorux): We might want to set timeout here using alarm(), but
@ -341,31 +353,16 @@ static void HandleSignal(int signal_number
// Flush the logs before we do anything in case 'anything' // Flush the logs before we do anything in case 'anything'
// causes problems. // causes problems.
FlushLogFilesUnsafe(GLOG_INFO); FlushLogFilesUnsafe(0);
// Kill ourself by the default signal handler. // Kill ourself by the default signal handler.
InvokeDefaultSignalHandler(signal_number); InvokeDefaultSignalHandler(signal_number);
} }
// Dumps signal and stack frame information, and invokes the default
// signal handler once our job is done.
#if defined(GLOG_OS_WINDOWS)
void FailureSignalHandler(int signal_number)
#else
void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
void* ucontext)
#endif
{
std::call_once(signaled, &HandleSignal, signal_number
#if !defined(GLOG_OS_WINDOWS)
,
signal_info, ucontext
#endif
);
}
} // namespace } // namespace
namespace glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() { bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled? // TODO(andschwa): Return kFailureSignalHandlerInstalled?
@ -382,6 +379,8 @@ bool IsFailureSignalHandlerInstalled() {
return false; return false;
} }
} // namespace glog_internal_namespace_
void InstallFailureSignalHandler() { void InstallFailureSignalHandler() {
#ifdef HAVE_SIGACTION #ifdef HAVE_SIGACTION
// Build the sigaction struct. // Build the sigaction struct.
@ -397,7 +396,8 @@ void InstallFailureSignalHandler() {
kFailureSignalHandlerInstalled = true; kFailureSignalHandlerInstalled = true;
#elif defined(GLOG_OS_WINDOWS) #elif defined(GLOG_OS_WINDOWS)
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) { for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR); CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
SIG_ERR);
} }
kFailureSignalHandlerInstalled = true; kFailureSignalHandlerInstalled = true;
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
@ -409,4 +409,4 @@ void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
#endif // HAVE_SIGACTION #endif // HAVE_SIGACTION
} }
} // namespace google _END_GOOGLE_NAMESPACE_

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -32,42 +32,42 @@
// This is a helper binary for testing signalhandler.cc. The actual test // This is a helper binary for testing signalhandler.cc. The actual test
// is done in signalhandler_unittest.sh. // is done in signalhandler_unittest.sh.
#include "utilities.h"
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <csignal> #include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <sstream>
#include <string> #include <string>
#include <thread>
#include "config.h"
#include "glog/logging.h" #include "glog/logging.h"
#include "stacktrace.h"
#include "symbolize.h"
#if defined(HAVE_UNISTD_H) #ifdef HAVE_LIB_GFLAGS
# include <unistd.h>
#endif
#ifdef GLOG_USE_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
#if defined(_MSC_VER)
# include <io.h> // write
#endif
using namespace google; using namespace GOOGLE_NAMESPACE;
static void DieInThread(int* a) { static void* DieInThread(void*) {
std::ostringstream oss; // We assume pthread_t is an integral number or a pointer, rather
oss << std::showbase << std::hex << std::this_thread::get_id(); // than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
fprintf(stderr, "%s is dying\n", oss.str().c_str()); // returns a pointer.
int b = 1 / *a; fprintf(
stderr, "0x%px is dying\n",
static_cast<const void*>(reinterpret_cast<const char*>(pthread_self())));
// Use volatile to prevent from these to be optimized away.
volatile int a = 0;
volatile int b = 1 / a;
fprintf(stderr, "We should have died: b=%d\n", b); fprintf(stderr, "We should have died: b=%d\n", b);
return nullptr;
} }
static void WriteToStdout(const char* data, size_t size) { static void WriteToStdout(const char* data, size_t size) {
if (write(fileno(stdout), data, size) < 0) { if (write(STDOUT_FILENO, data, size) < 0) {
// Ignore errors. // Ignore errors.
} }
} }
@ -75,7 +75,7 @@ static void WriteToStdout(const char* data, size_t size) {
int main(int argc, char **argv) { int main(int argc, char **argv) {
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE) #if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);
# ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true); ParseCommandLineFlags(&argc, &argv, true);
#endif #endif
InstallFailureSignalHandler(); InstallFailureSignalHandler();
@ -89,11 +89,16 @@ int main(int argc, char** argv) {
*a = 0; *a = 0;
} else if (command == "loop") { } else if (command == "loop") {
fprintf(stderr, "looping\n"); fprintf(stderr, "looping\n");
while (true) while (true);
;
} else if (command == "die_in_thread") { } else if (command == "die_in_thread") {
std::thread t{&DieInThread, nullptr}; #if defined(HAVE_PTHREAD)
t.join(); pthread_t thread;
pthread_create(&thread, nullptr, &DieInThread, nullptr);
pthread_join(thread, nullptr);
#else
fprintf(stderr, "no pthread\n");
return 1;
#endif
} else if (command == "dump_to_stdout") { } else if (command == "dump_to_stdout") {
InstallFailureWriter(WriteToStdout); InstallFailureWriter(WriteToStdout);
abort(); abort();

View File

@ -1,38 +0,0 @@
// Copyright (c) 2024, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Routines to extract the current stack trace. These functions are
// thread-safe.
#include "stacktrace.h"
// Make an implementation of stacktrace compiled.
#if defined(STACKTRACE_H)
# include STACKTRACE_H
#endif

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2000 - 2007, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -30,46 +30,13 @@
// Routines to extract the current stack trace. These functions are // Routines to extract the current stack trace. These functions are
// thread-safe. // thread-safe.
#ifndef GLOG_INTERNAL_STACKTRACE_H #ifndef BASE_STACKTRACE_H_
#define GLOG_INTERNAL_STACKTRACE_H #define BASE_STACKTRACE_H_
#include "glog/platform.h"
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_NO_EXPORT)
# error "stacktrace.h" was not included correctly.
#endif
#include "config.h" #include "config.h"
#if defined(HAVE_LIBUNWIND) #include "glog/logging.h"
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif defined(HAVE_UNWIND)
# define STACKTRACE_H "stacktrace_unwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_x86-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# elif defined(GLOG_OS_WINDOWS)
# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif
#endif
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE) _START_GOOGLE_NAMESPACE_
# define STACKTRACE_H "stacktrace_generic-inl.h"
#endif
#if defined(STACKTRACE_H)
# define HAVE_STACKTRACE
#endif
namespace google {
inline namespace glog_internal_namespace_ {
#if defined(HAVE_STACKTRACE)
// This is similar to the GetStackFrames routine, except that it returns // This is similar to the GetStackFrames routine, except that it returns
// the stack trace only, and not the stack frame sizes as well. // the stack trace only, and not the stack frame sizes as well.
@ -87,11 +54,8 @@ inline namespace glog_internal_namespace_ {
// .... ... // .... ...
// //
// "result" must not be nullptr. // "result" must not be nullptr.
GLOG_NO_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count); GLOG_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
#endif // defined(HAVE_STACKTRACE) _END_GOOGLE_NAMESPACE_
} // namespace glog_internal_namespace_ #endif // BASE_STACKTRACE_H_
} // namespace google
#endif // GLOG_INTERNAL_STACKTRACE_H

View File

@ -37,8 +37,7 @@
#include "stacktrace.h" #include "stacktrace.h"
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// If you change this function, also change GetStackFrames below. // If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
@ -62,5 +61,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return result_count; return result_count;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -40,8 +40,7 @@ extern "C" {
#include "glog/raw_logging.h" #include "glog/raw_logging.h"
#include "stacktrace.h" #include "stacktrace.h"
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// Sometimes, we can try to get a stack trace from within a stack // Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap (maybe indirectly via an // trace, because libunwind can call mmap (maybe indirectly via an
@ -91,5 +90,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n; return n;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -40,8 +40,7 @@
#include "stacktrace.h" #include "stacktrace.h"
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// Given a pointer to a stack frame, locate and return the calling // Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity // stackframe, or return nullptr if no stackframe can be found. Perform sanity
@ -115,8 +114,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
result[n++] = *(sp+2); result[n++] = *(sp+2);
#elif defined(_CALL_SYSV) #elif defined(_CALL_SYSV)
result[n++] = *(sp+1); result[n++] = *(sp+1);
#elif defined(__APPLE__) || \ #elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
// This check is in case the compiler doesn't define _CALL_AIX/etc. // This check is in case the compiler doesn't define _CALL_AIX/etc.
result[n++] = *(sp+2); result[n++] = *(sp+2);
#elif defined(__linux) || defined(__OpenBSD__) #elif defined(__linux) || defined(__OpenBSD__)
@ -132,5 +130,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n; return n;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -41,6 +41,8 @@
# include <execinfo.h> # include <execinfo.h>
#endif #endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the // Obtain a backtrace, verify that the expected callers are present in the
@ -73,10 +75,7 @@ AddressRange expected_range[BACKTRACE_STEPS];
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before // (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
// the recursive call. // the recursive call.
#define DECLARE_ADDRESS_LABEL(a_label) \ #define DECLARE_ADDRESS_LABEL(a_label) \
a_label: \ a_label: do { __asm__ __volatile__(""); } while (0)
do { \
__asm__ __volatile__(""); \
} while (0)
// Gcc 4.4.0 may split function into multiple chunks, and the chunk // Gcc 4.4.0 may split function into multiple chunks, and the chunk
// performing recursive call may end up later in the code then the return // performing recursive call may end up later in the code then the return
// instruction (this actually happens with FDO). // instruction (this actually happens with FDO).
@ -86,8 +85,9 @@ AddressRange expected_range[BACKTRACE_STEPS];
void *ra = __builtin_return_address(0); \ void *ra = __builtin_return_address(0); \
CHECK_LT((prange)->start, ra); \ CHECK_LT((prange)->start, ra); \
if (ra > (prange)->end) { \ if (ra > (prange)->end) { \
printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \ printf("Adjusting range from %p..%p to %p..%p\n", \
(prange)->end, (prange)->start, ra); \ (prange)->start, (prange)->end, \
(prange)->start, ra); \
(prange)->end = ra; \ (prange)->end = ra; \
} \ } \
} while (0) } while (0)
@ -98,18 +98,14 @@ AddressRange expected_range[BACKTRACE_STEPS];
(prange)->start = reinterpret_cast<const void *>(&fn); \ (prange)->start = reinterpret_cast<const void *>(&fn); \
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \ (prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
} while (0) } while (0)
# define DECLARE_ADDRESS_LABEL(a_label) \ #define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
do { \ #define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
} while (0)
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \
} while (0)
#endif // __GNUC__ #endif // __GNUC__
//-----------------------------------------------------------------------// //-----------------------------------------------------------------------//
static void CheckRetAddrIsInFunction(void* ret_addr, static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
const AddressRange& range) { {
CHECK_GE(ret_addr, range.start); CHECK_GE(ret_addr, range.start);
CHECK_LE(ret_addr, range.end); CHECK_LE(ret_addr, range.end);
} }
@ -130,7 +126,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]); ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]); INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
DECLARE_ADDRESS_LABEL(start); DECLARE_ADDRESS_LABEL(start);
size = google::GetStackTrace(stack, STACK_LEN, 0); size = GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size); printf("Obtained %d stack frames.\n", size);
CHECK_GE(size, 1); CHECK_GE(size, 1);
CHECK_LE(size, STACK_LEN); CHECK_LE(size, STACK_LEN);
@ -153,8 +149,8 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
#endif #endif
} }
for (int i = 0; i < BACKTRACE_STEPS; i++) { for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ", i, printf("Backtrace %d: expected: %p..%p actual: %p ... ",
expected_range[i].start, expected_range[i].end, stack[i]); i, expected_range[i].start, expected_range[i].end, stack[i]);
fflush(stdout); fflush(stdout);
CheckRetAddrIsInFunction(stack[i], expected_range[i]); CheckRetAddrIsInFunction(stack[i], expected_range[i]);
printf("OK\n"); printf("OK\n");
@ -211,8 +207,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
// See https://github.com/google/glog/issues/421 for the detail. // See https://github.com/google/glog/issues/421 for the detail.
static static
#endif #endif
void ATTRIBUTE_NOINLINE void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
CheckStackTrace(int i) {
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]); INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
DECLARE_ADDRESS_LABEL(start); DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) { for (int j = i; j >= 0; j--) {
@ -229,7 +224,7 @@ static
int main(int, char ** argv) { int main(int, char ** argv) {
FLAGS_logtostderr = true; FLAGS_logtostderr = true;
google::InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);
CheckStackTrace(0); CheckStackTrace(0);

View File

@ -1,4 +1,4 @@
// Copyright (c) 2023, Google Inc. // Copyright (c) 2005 - 2007, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -33,10 +33,11 @@
#include <unwind.h> // ABI defined unwinder #include <unwind.h> // ABI defined unwinder
#include <cstdlib> // for nullptr
#include "stacktrace.h" #include "stacktrace.h"
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
struct trace_arg_t { struct trace_arg_t {
void **result; void **result;
@ -46,11 +47,11 @@ struct trace_arg_t {
}; };
// Workaround for the malloc() in _Unwind_Backtrace() issue. // Workaround for the malloc() in _Unwind_Backtrace() issue.
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context* /*uc*/, static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context */*uc*/, void */*opq*/) {
void* /*opq*/) {
return _URC_NO_REASON; return _URC_NO_REASON;
} }
// This code is not considered ready to run until // This code is not considered ready to run until
// static initializers run so that we are guaranteed // static initializers run so that we are guaranteed
// that any malloc-related initialization is done. // that any malloc-related initialization is done.
@ -102,5 +103,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return targ.count; return targ.count;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -31,13 +31,12 @@
// //
// Windows implementation - just use CaptureStackBackTrace // Windows implementation - just use CaptureStackBackTrace
// clang-format off #include "config.h"
#include <windows.h> // Must come before <dbghelp.h> #include "port.h"
#include "stacktrace.h"
#include <dbghelp.h> #include <dbghelp.h>
// clang-format on
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
int GetStackTrace(void** result, int max_depth, int skip_count) { int GetStackTrace(void** result, int max_depth, int skip_count) {
if (max_depth > 64) { if (max_depth > 64) {
@ -49,5 +48,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
static_cast<DWORD>(max_depth), result, nullptr); static_cast<DWORD>(max_depth), result, nullptr);
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google

View File

@ -34,16 +34,15 @@
#include "utilities.h" // for OS_* macros #include "utilities.h" // for OS_* macros
#if !defined(GLOG_OS_WINDOWS) #if !defined(GLOG_OS_WINDOWS)
# include <sys/mman.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h>
#endif #endif
#include <cstdio> // for nullptr #include <cstdio> // for nullptr
#include "stacktrace.h" #include "stacktrace.h"
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// Given a pointer to a stack frame, locate and return the calling // Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity // stackframe, or return nullptr if no stackframe can be found. Perform sanity
@ -156,5 +155,5 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
} }
return n; return n;
} }
} // namespace glog_internal_namespace_
} // namespace google _END_GOOGLE_NAMESPACE_

View File

@ -82,7 +82,7 @@ static void TestSTLLogging() {
if (i > 0) expected += ' '; if (i > 0) expected += ' ';
const size_t buf_size = 256; const size_t buf_size = 256;
char buf[buf_size]; char buf[buf_size];
std::snprintf(buf, buf_size, "%d", i); snprintf(buf, buf_size, "%d", i);
expected += buf; expected += buf;
} }
v.push_back(100); v.push_back(100);

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -52,68 +52,72 @@
#include GLOG_BUILD_CONFIG_INCLUDE #include GLOG_BUILD_CONFIG_INCLUDE
#endif // GLOG_BUILD_CONFIG_INCLUDE #endif // GLOG_BUILD_CONFIG_INCLUDE
#include "symbolize.h"
#include "utilities.h" #include "utilities.h"
#if defined(HAVE_SYMBOLIZE) #if defined(HAVE_SYMBOLIZE)
# include <algorithm>
# include <cstdlib>
#include <cstring> #include <cstring>
#include <algorithm>
#include <limits> #include <limits>
#include "symbolize.h"
#include "demangle.h" #include "demangle.h"
_START_GOOGLE_NAMESPACE_
// We don't use assert() since it's not guaranteed to be // We don't use assert() since it's not guaranteed to be
// async-signal-safe. Instead we define a minimal assertion // async-signal-safe. Instead we define a minimal assertion
// macro. So far, we don't need pretty printing for __FILE__, etc. // macro. So far, we don't need pretty printing for __FILE__, etc.
# define GLOG_SAFE_ASSERT(expr) ((expr) ? 0 : (std::abort(), 0))
namespace google { // A wrapper for abort() to make it callable in ? :.
inline namespace glog_internal_namespace_ { static int AssertFail() {
abort();
namespace { return 0; // Should not reach.
SymbolizeCallback g_symbolize_callback = nullptr;
SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback = nullptr;
// This function wraps the Demangle function to provide an interface
// where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
ATTRIBUTE_NOINLINE
void DemangleInplace(char* out, size_t out_size) {
char demangled[256]; // Big enough for sane demangled symbols.
if (Demangle(out, demangled, sizeof(demangled))) {
// Demangling succeeded. Copy to out if the space allows.
size_t len = strlen(demangled);
if (len + 1 <= out_size) { // +1 for '\0'.
GLOG_SAFE_ASSERT(len < sizeof(demangled));
memmove(out, demangled, len + 1);
}
}
} }
} // namespace #define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
static SymbolizeCallback g_symbolize_callback = nullptr;
void InstallSymbolizeCallback(SymbolizeCallback callback) { void InstallSymbolizeCallback(SymbolizeCallback callback) {
g_symbolize_callback = callback; g_symbolize_callback = callback;
} }
static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
nullptr;
void InstallSymbolizeOpenObjectFileCallback( void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback) { SymbolizeOpenObjectFileCallback callback) {
g_symbolize_open_object_file_callback = callback; g_symbolize_open_object_file_callback = callback;
} }
} // namespace glog_internal_namespace_ // This function wraps the Demangle function to provide an interface
} // namespace google // where the input symbol is demangled in-place.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size) {
char demangled[256]; // Big enough for sane demangled symbols.
if (Demangle(out, demangled, sizeof(demangled))) {
// Demangling succeeded. Copy to out if the space allows.
size_t len = strlen(demangled);
if (len + 1 <= out_size) { // +1 for '\0'.
SAFE_ASSERT(len < sizeof(demangled));
memmove(out, demangled, len + 1);
}
}
}
# if defined(HAVE_LINK_H) _END_GOOGLE_NAMESPACE_
#if defined(__ELF__)
#if defined(HAVE_DLFCN_H) #if defined(HAVE_DLFCN_H)
#include <dlfcn.h> #include <dlfcn.h>
#endif #endif
#if defined(GLOG_OS_OPENBSD)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif
#include <fcntl.h> #include <fcntl.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
@ -131,24 +135,10 @@ void InstallSymbolizeOpenObjectFileCallback(
#include "glog/raw_logging.h" #include "glog/raw_logging.h"
#include "symbolize.h" #include "symbolize.h"
namespace google { // Re-runs fn until it doesn't cause EINTR.
inline namespace glog_internal_namespace_ { #define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
namespace { _START_GOOGLE_NAMESPACE_
// Re-runs run until it doesn't cause EINTR.
// Similar to the TEMP_FAILURE_RETRY macro from GNU C.
template <class Functor>
auto FailureRetry(Functor run, int error = EINTR) noexcept(noexcept(run())) {
decltype(run()) result;
while ((result = run()) == -1 && errno == error) {
}
return result;
}
} // namespace
// Read up to "count" bytes from "offset" in the file pointed by file // Read up to "count" bytes from "offset" in the file pointed by file
// descriptor "fd" into the buffer starting at "buf" while handling short reads // descriptor "fd" into the buffer starting at "buf" while handling short reads
@ -156,16 +146,14 @@ auto FailureRetry(Functor run, int error = EINTR) noexcept(noexcept(run())) {
// -1. // -1.
static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count, static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
const size_t offset) { const size_t offset) {
GLOG_SAFE_ASSERT(fd >= 0); SAFE_ASSERT(fd >= 0);
GLOG_SAFE_ASSERT(count <= SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
char *buf0 = reinterpret_cast<char *>(buf); char *buf0 = reinterpret_cast<char *>(buf);
size_t num_bytes = 0; size_t num_bytes = 0;
while (num_bytes < count) { while (num_bytes < count) {
ssize_t len = FailureRetry([fd, p = buf0 + num_bytes, n = count - num_bytes, ssize_t len;
m = static_cast<off_t>(offset + num_bytes)] { NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes,
return pread(fd, p, n, m); static_cast<off_t>(offset + num_bytes)));
});
if (len < 0) { // There was an error other than EINTR. if (len < 0) { // There was an error other than EINTR.
return -1; return -1;
} }
@ -174,7 +162,7 @@ static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
} }
num_bytes += static_cast<size_t>(len); num_bytes += static_cast<size_t>(len);
} }
GLOG_SAFE_ASSERT(num_bytes <= count); SAFE_ASSERT(num_bytes <= count);
return static_cast<ssize_t>(num_bytes); return static_cast<ssize_t>(num_bytes);
} }
@ -182,8 +170,8 @@ static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
// pointed by "fd" into the buffer starting at "buf" while handling // pointed by "fd" into the buffer starting at "buf" while handling
// short reads and EINTR. On success, return true. Otherwise, return // short reads and EINTR. On success, return true. Otherwise, return
// false. // false.
static bool ReadFromOffsetExact(const int fd, void* buf, const size_t count, static bool ReadFromOffsetExact(const int fd, void *buf,
const size_t offset) { const size_t count, const size_t offset) {
ssize_t len = ReadFromOffset(fd, buf, count, offset); ssize_t len = ReadFromOffset(fd, buf, count, offset);
return static_cast<size_t>(len) == count; return static_cast<size_t>(len) == count;
} }
@ -205,11 +193,9 @@ static int FileGetElfType(const int fd) {
// and return true. Otherwise, return false. // and return true. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get // To keep stack consumption low, we would like this function to not get
// inlined. // inlined.
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd, static ATTRIBUTE_NOINLINE bool
ElfW(Half) sh_num, GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
const size_t sh_offset, ElfW(Word) type, ElfW(Shdr) *out) {
ElfW(Word) type,
ElfW(Shdr) * out) {
// Read at most 16 section headers at a time to save read calls. // Read at most 16 section headers at a time to save read calls.
ElfW(Shdr) buf[16]; ElfW(Shdr) buf[16];
for (size_t i = 0; i < sh_num;) { for (size_t i = 0; i < sh_num;) {
@ -221,9 +207,9 @@ static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
if (len == -1) { if (len == -1) {
return false; return false;
} }
GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0); SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]); const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
GLOG_SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0])); SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
for (size_t j = 0; j < num_headers_in_buf; ++j) { for (size_t j = 0; j < num_headers_in_buf; ++j) {
if (buf[j].sh_type == type) { if (buf[j].sh_type == type) {
*out = buf[j]; *out = buf[j];
@ -256,17 +242,15 @@ bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
} }
for (size_t i = 0; i < elf_header.e_shnum; ++i) { for (size_t i = 0; i < elf_header.e_shnum; ++i) {
size_t section_header_offset = size_t section_header_offset = (elf_header.e_shoff +
(elf_header.e_shoff + elf_header.e_shentsize * i); elf_header.e_shentsize * i);
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) { if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
return false; return false;
} }
char header_name[kMaxSectionNameLen]; char header_name[kMaxSectionNameLen];
if (sizeof(header_name) < name_len) { if (sizeof(header_name) < name_len) {
RAW_LOG(WARNING, RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
"Section name '%s' is too long (%zu); " "section will not be found (even if present).", name, name_len);
"section will not be found (even if present).",
name, name_len);
// No point in even trying. // No point in even trying.
return false; return false;
} }
@ -291,10 +275,9 @@ bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
// to out. Otherwise, return false. // to out. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get // To keep stack consumption low, we would like this function to not get
// inlined. // inlined.
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out, static ATTRIBUTE_NOINLINE bool
size_t out_size, FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
uint64_t symbol_offset, uint64_t symbol_offset, const ElfW(Shdr) *strtab,
const ElfW(Shdr) * strtab,
const ElfW(Shdr) *symtab) { const ElfW(Shdr) *symtab) {
if (symtab == nullptr) { if (symtab == nullptr) {
return false; return false;
@ -317,9 +300,9 @@ static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i); size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
const ssize_t len = const ssize_t len =
ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset); ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0); SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]); const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
GLOG_SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read); SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
for (unsigned j = 0; j < num_symbols_in_buf; ++j) { for (unsigned j = 0; j < num_symbols_in_buf; ++j) {
const ElfW(Sym)& symbol = buf[j]; const ElfW(Sym)& symbol = buf[j];
uint64_t start_address = symbol.st_value; uint64_t start_address = symbol.st_value;
@ -346,8 +329,11 @@ static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
// both regular and dynamic symbol tables if necessary. On success, // both regular and dynamic symbol tables if necessary. On success,
// write the symbol name to "out" and return true. Otherwise, return // write the symbol name to "out" and return true. Otherwise, return
// false. // false.
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out, static bool GetSymbolFromObjectFile(const int fd,
size_t out_size, uint64_t base_address) { uint64_t pc,
char* out,
size_t out_size,
uint64_t base_address) {
// Read the ELF header. // Read the ELF header.
ElfW(Ehdr) elf_header; ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) { if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
@ -359,9 +345,8 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
// Consult a regular symbol table first. // Consult a regular symbol table first.
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff, if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_SYMTAB, &symtab)) { SHT_SYMTAB, &symtab)) {
if (!ReadFromOffsetExact( if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
fd, &strtab, sizeof(strtab), symtab.sh_link * sizeof(symtab))) {
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
return false; return false;
} }
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
@ -372,9 +357,8 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
// If the symbol is not found, then consult a dynamic symbol table. // If the symbol is not found, then consult a dynamic symbol table.
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff, if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_DYNSYM, &symtab)) { SHT_DYNSYM, &symtab)) {
if (!ReadFromOffsetExact( if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
fd, &strtab, sizeof(strtab), symtab.sh_link * sizeof(symtab))) {
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
return false; return false;
} }
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) { if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
@ -386,12 +370,28 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
} }
namespace { namespace {
// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
struct FileDescriptor {
const int fd_;
explicit FileDescriptor(int fd) : fd_(fd) {}
~FileDescriptor() {
if (fd_ >= 0) {
close(fd_);
}
}
int get() { return fd_; }
private:
FileDescriptor(const FileDescriptor &) = delete;
void operator=(const FileDescriptor &) = delete;
};
// Helper class for reading lines from file. // Helper class for reading lines from file.
// //
// Note: we don't use ProcMapsIterator since the object is big (it has // Note: we don't use ProcMapsIterator since the object is big (it has
// a 5k array member) and uses async-unsafe functions such as sscanf() // a 5k array member) and uses async-unsafe functions such as sscanf()
// and std::snprintf(). // and snprintf().
class LineReader { class LineReader {
public: public:
explicit LineReader(int fd, char *buf, size_t buf_len, size_t offset) explicit LineReader(int fd, char *buf, size_t buf_len, size_t offset)
@ -419,7 +419,7 @@ class LineReader {
bol_ = buf_; bol_ = buf_;
} else { } else {
bol_ = eol_ + 1; // Advance to the next line in the buffer. bol_ = eol_ + 1; // Advance to the next line in the buffer.
GLOG_SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_". SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
if (!HasCompleteLine()) { if (!HasCompleteLine()) {
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_); const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
// Move the trailing incomplete line to the beginning. // Move the trailing incomplete line to the beginning.
@ -449,21 +449,26 @@ class LineReader {
} }
// Beginning of line. // Beginning of line.
const char* bol() { return bol_; } const char *bol() {
return bol_;
}
// End of line. // End of line.
const char* eol() { return eol_; } const char *eol() {
return eol_;
}
private: private:
LineReader(const LineReader &) = delete; LineReader(const LineReader &) = delete;
void operator=(const LineReader &) = delete; void operator=(const LineReader &) = delete;
char *FindLineFeed() { char *FindLineFeed() {
return reinterpret_cast<char*>( return reinterpret_cast<char *>(memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
} }
bool BufferIsEmpty() { return buf_ == eod_; } bool BufferIsEmpty() {
return buf_ == eod_;
}
bool HasCompleteLine() { bool HasCompleteLine() {
return !BufferIsEmpty() && FindLineFeed() != nullptr; return !BufferIsEmpty() && FindLineFeed() != nullptr;
@ -486,15 +491,14 @@ static char* GetHex(const char* start, const char* end, uint64_t* hex) {
const char *p; const char *p;
for (p = start; p < end; ++p) { for (p = start; p < end; ++p) {
int ch = *p; int ch = *p;
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || if ((ch >= '0' && ch <= '9') ||
(ch >= 'a' && ch <= 'f')) { (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
*hex = (*hex << 4U) | *hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
(ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
} else { // Encountered the first non-hex character. } else { // Encountered the first non-hex character.
break; break;
} }
} }
GLOG_SAFE_ASSERT(p <= end); SAFE_ASSERT(p <= end);
return const_cast<char *>(p); return const_cast<char *>(p);
} }
@ -506,33 +510,37 @@ static char* GetHex(const char* start, const char* end, uint64_t* hex) {
// file is opened successfully, returns the file descriptor. Otherwise, // file is opened successfully, returns the file descriptor. Otherwise,
// returns -1. |out_file_name_size| is the size of the file name buffer // returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator). // (including the null-terminator).
static ATTRIBUTE_NOINLINE FileDescriptor static ATTRIBUTE_NOINLINE int
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc, OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t &start_address, uint64_t &start_address,
uint64_t &base_address, uint64_t &base_address,
char *out_file_name, char *out_file_name,
size_t out_file_name_size) { size_t out_file_name_size) {
FileDescriptor maps_fd{ int object_fd;
FailureRetry([] { return open("/proc/self/maps", O_RDONLY); })};
if (!maps_fd) { int maps_fd;
return nullptr; NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
FileDescriptor wrapped_maps_fd(maps_fd);
if (wrapped_maps_fd.get() < 0) {
return -1;
} }
FileDescriptor mem_fd{ int mem_fd;
FailureRetry([] { return open("/proc/self/mem", O_RDONLY); })}; NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
if (!mem_fd) { FileDescriptor wrapped_mem_fd(mem_fd);
return nullptr; if (wrapped_mem_fd.get() < 0) {
return -1;
} }
// Iterate over maps and look for the map containing the pc. Then // Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside. // look into the symbol tables inside.
char buf[1024]; // Big enough for line of sane /proc/self/maps char buf[1024]; // Big enough for line of sane /proc/self/maps
LineReader reader(maps_fd.get(), buf, sizeof(buf), 0); LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
while (true) { while (true) {
const char *cursor; const char *cursor;
const char *eol; const char *eol;
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line. if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
return nullptr; return -1;
} }
// Start parsing line in /proc/self/maps. Here is an example: // Start parsing line in /proc/self/maps. Here is an example:
@ -545,7 +553,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// Read start address. // Read start address.
cursor = GetHex(cursor, eol, &start_address); cursor = GetHex(cursor, eol, &start_address);
if (cursor == eol || *cursor != '-') { if (cursor == eol || *cursor != '-') {
return nullptr; // Malformed line. return -1; // Malformed line.
} }
++cursor; // Skip '-'. ++cursor; // Skip '-'.
@ -553,7 +561,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t end_address; uint64_t end_address;
cursor = GetHex(cursor, eol, &end_address); cursor = GetHex(cursor, eol, &end_address);
if (cursor == eol || *cursor != ' ') { if (cursor == eol || *cursor != ' ') {
return nullptr; // Malformed line. return -1; // Malformed line.
} }
++cursor; // Skip ' '. ++cursor; // Skip ' '.
@ -564,15 +572,14 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
} }
// We expect at least four letters for flags (ex. "r-xp"). // We expect at least four letters for flags (ex. "r-xp").
if (cursor == eol || cursor < flags_start + 4) { if (cursor == eol || cursor < flags_start + 4) {
return nullptr; // Malformed line. return -1; // Malformed line.
} }
// Determine the base address by reading ELF headers in process memory. // Determine the base address by reading ELF headers in process memory.
ElfW(Ehdr) ehdr; ElfW(Ehdr) ehdr;
// Skip non-readable maps. // Skip non-readable maps.
if (flags_start[0] == 'r' && if (flags_start[0] == 'r' &&
ReadFromOffsetExact(mem_fd.get(), &ehdr, sizeof(ElfW(Ehdr)), ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
start_address) &&
memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) { memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
switch (ehdr.e_type) { switch (ehdr.e_type) {
case ET_EXEC: case ET_EXEC:
@ -591,7 +598,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
for (unsigned i = 0; i != ehdr.e_phnum; ++i) { for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
ElfW(Phdr) phdr; ElfW(Phdr) phdr;
if (ReadFromOffsetExact( if (ReadFromOffsetExact(
mem_fd.get(), &phdr, sizeof(phdr), mem_fd, &phdr, sizeof(phdr),
start_address + ehdr.e_phoff + i * sizeof(phdr)) && start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
phdr.p_type == PT_LOAD && phdr.p_offset == 0) { phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
base_address = start_address - phdr.p_vaddr; base_address = start_address - phdr.p_vaddr;
@ -607,7 +614,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
} }
// Check start and end addresses. // Check start and end addresses.
if (start_address > pc || pc >= end_address) { if (!(start_address <= pc && pc < end_address)) {
continue; // We skip this map. PC isn't in this map. continue; // We skip this map. PC isn't in this map.
} }
@ -621,7 +628,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t file_offset; uint64_t file_offset;
cursor = GetHex(cursor, eol, &file_offset); cursor = GetHex(cursor, eol, &file_offset);
if (cursor == eol || *cursor != ' ') { if (cursor == eol || *cursor != ' ') {
return nullptr; // Malformed line. return -1; // Malformed line.
} }
++cursor; // Skip ' '. ++cursor; // Skip ' '.
@ -639,16 +646,20 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
++cursor; ++cursor;
} }
if (cursor == eol) { if (cursor == eol) {
return nullptr; // Malformed line. return -1; // Malformed line.
} }
// Finally, "cursor" now points to file name of our interest.
NO_INTR(object_fd = open(cursor, O_RDONLY));
if (object_fd < 0) {
// Failed to open object file. Copy the object file name to
// |out_file_name|.
strncpy(out_file_name, cursor, out_file_name_size); strncpy(out_file_name, cursor, out_file_name_size);
// Making sure |out_file_name| is always null-terminated. // Making sure |out_file_name| is always null-terminated.
out_file_name[out_file_name_size - 1] = '\0'; out_file_name[out_file_name_size - 1] = '\0';
return -1;
// Finally, "cursor" now points to file name of our interest. }
return FileDescriptor{ return object_fd;
FailureRetry([cursor] { return open(cursor, O_RDONLY); })};
} }
} }
@ -659,8 +670,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// "sz" bytes. Output will be truncated as needed, and a NUL character is always // "sz" bytes. Output will be truncated as needed, and a NUL character is always
// appended. // appended.
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc. // NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base, static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
size_t padding) {
// Make sure we can write at least one NUL byte. // Make sure we can write at least one NUL byte.
size_t n = 1; size_t n = 1;
if (n > sz) { if (n > sz) {
@ -712,7 +722,7 @@ static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
// buffer size |dest_size| and guarantees that |dest| is null-terminated. // buffer size |dest_size| and guarantees that |dest| is null-terminated.
static void SafeAppendString(const char* source, char* dest, size_t dest_size) { static void SafeAppendString(const char* source, char* dest, size_t dest_size) {
size_t dest_string_length = strlen(dest); size_t dest_string_length = strlen(dest);
GLOG_SAFE_ASSERT(dest_string_length < dest_size); SAFE_ASSERT(dest_string_length < dest_size);
dest += dest_string_length; dest += dest_string_length;
dest_size -= dest_string_length; dest_size -= dest_string_length;
strncpy(dest, source, dest_size); strncpy(dest, source, dest_size);
@ -737,12 +747,12 @@ static void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {
// and "out" is used as its output. // and "out" is used as its output.
// To keep stack consumption low, we would like this function to not // To keep stack consumption low, we would like this function to not
// get inlined. // get inlined.
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle( static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) { size_t out_size) {
auto pc0 = reinterpret_cast<uintptr_t>(pc); auto pc0 = reinterpret_cast<uintptr_t>(pc);
uint64_t start_address = 0; uint64_t start_address = 0;
uint64_t base_address = 0; uint64_t base_address = 0;
FileDescriptor object_fd; int object_fd = -1;
if (out_size < 1) { if (out_size < 1) {
return false; return false;
@ -751,18 +761,23 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
SafeAppendString("(", out, out_size); SafeAppendString("(", out, out_size);
if (g_symbolize_open_object_file_callback) { if (g_symbolize_open_object_file_callback) {
object_fd.reset(g_symbolize_open_object_file_callback( object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
pc0, start_address, base_address, out + 1, out_size - 1)); base_address, out + 1,
out_size - 1);
} else { } else {
object_fd = OpenObjectFileContainingPcAndGetStartAddress( object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
pc0, start_address, base_address, out + 1, out_size - 1); base_address,
out + 1,
out_size - 1);
} }
FileDescriptor wrapped_object_fd(object_fd);
#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES) #if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
{ {
#else #else
// Check whether a file name was returned. // Check whether a file name was returned.
if (!object_fd) { if (object_fd < 0) {
#endif #endif
if (out[1]) { if (out[1]) {
// The object file containing PC was determined successfully however the // The object file containing PC was determined successfully however the
@ -778,7 +793,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
// Failed to determine the object file containing PC. Bail out. // Failed to determine the object file containing PC. Bail out.
return false; return false;
} }
int elf_type = FileGetElfType(object_fd.get()); int elf_type = FileGetElfType(wrapped_object_fd.get());
if (elf_type == -1) { if (elf_type == -1) {
return false; return false;
} }
@ -787,15 +802,16 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
// Note: relocation (and much of the rest of this code) will be // Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables. // wrong for prelinked shared libraries and PIE executables.
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0; uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written = int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
g_symbolize_callback(object_fd.get(), pc, out, out_size, relocation); pc, out, out_size,
relocation);
if (num_bytes_written > 0) { if (num_bytes_written > 0) {
out += static_cast<size_t>(num_bytes_written); out += static_cast<size_t>(num_bytes_written);
out_size -= static_cast<size_t>(num_bytes_written); out_size -= static_cast<size_t>(num_bytes_written);
} }
} }
if (!GetSymbolFromObjectFile(object_fd.get(), pc0, out, out_size, if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
base_address)) { out, out_size, base_address)) {
if (out[1] && !g_symbolize_callback) { if (out[1] && !g_symbolize_callback) {
// The object file containing PC was opened successfully however the // The object file containing PC was opened successfully however the
// symbol was not found. The object may have been stripped. This is still // symbol was not found. The object may have been stripped. This is still
@ -815,20 +831,17 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
return true; return true;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR) #elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
#include <dlfcn.h> #include <dlfcn.h>
#include <cstring> #include <cstring>
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle( static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) { size_t out_size) {
Dl_info info; Dl_info info;
if (dladdr(pc, &info)) { if (dladdr(pc, &info)) {
if (info.dli_sname) { if (info.dli_sname) {
@ -843,30 +856,31 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
return false; return false;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN) #elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
# include <dbghelp.h>
#include <windows.h> #include <windows.h>
#include <dbghelp.h>
namespace google { #ifdef _MSC_VER
inline namespace glog_internal_namespace_ { #pragma comment(lib, "dbghelp")
#endif
namespace { _START_GOOGLE_NAMESPACE_
class SymInitializer final { class SymInitializer {
public: public:
HANDLE process; HANDLE process;
bool ready; bool ready;
SymInitializer() : process(GetCurrentProcess()), ready(false) { SymInitializer() : process(nullptr), ready(false) {
// Initialize the symbol handler. // Initialize the symbol handler.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx // https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
process = GetCurrentProcess();
// Defer symbol loading. // Defer symbol loading.
// We do not request undecorated symbols with SYMOPT_UNDNAME // We do not request undecorated symbols with SYMOPT_UNDNAME
// because the mangling library calls UnDecorateSymbolName. // because the mangling library calls UnDecorateSymbolName.
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES); SymSetOptions(SYMOPT_DEFERRED_LOADS);
if (SymInitialize(process, nullptr, true)) { if (SymInitialize(process, nullptr, true)) {
ready = true; ready = true;
} }
@ -875,18 +889,13 @@ class SymInitializer final {
SymCleanup(process); SymCleanup(process);
// We do not need to close `HANDLE process` because it's a "pseudo handle." // We do not need to close `HANDLE process` because it's a "pseudo handle."
} }
private:
SymInitializer(const SymInitializer&) = delete; SymInitializer(const SymInitializer&);
SymInitializer& operator=(const SymInitializer&) = delete; SymInitializer& operator=(const SymInitializer&);
SymInitializer(SymInitializer&&) = delete;
SymInitializer& operator=(SymInitializer&&) = delete;
}; };
} // namespace
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out, static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size, size_t out_size) {
SymbolizeOptions options) {
const static SymInitializer symInitializer; const static SymInitializer symInitializer;
if (!symInitializer.ready) { if (!symInitializer.ready) {
return false; return false;
@ -899,65 +908,47 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
symbol->MaxNameLen = MAX_SYM_NAME; symbol->MaxNameLen = MAX_SYM_NAME;
// We use the ANSI version to ensure the string type is always `char *`. // We use the ANSI version to ensure the string type is always `char *`.
// This could break if a symbol has Unicode in it. // This could break if a symbol has Unicode in it.
BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc), BOOL ret = SymFromAddr(symInitializer.process,
0, symbol); reinterpret_cast<DWORD64>(pc), 0, symbol);
std::size_t namelen = static_cast<size_t>(symbol->NameLen); if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
if (ret && namelen < out_size) { // `NameLen` does not include the null terminating character.
std::strncpy(out, symbol->Name, namelen); strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
out[namelen] = '\0'; out[static_cast<size_t>(symbol->NameLen)] = '\0';
DWORD displacement;
IMAGEHLP_LINE64 line{sizeof(IMAGEHLP_LINE64)};
BOOL found = FALSE;
if ((options & SymbolizeOptions::kNoLineNumbers) !=
SymbolizeOptions::kNoLineNumbers) {
found = SymGetLineFromAddr64(symInitializer.process,
reinterpret_cast<DWORD64>(pc), &displacement,
&line);
}
// Symbolization succeeded. Now we try to demangle the symbol. // Symbolization succeeded. Now we try to demangle the symbol.
DemangleInplace(out, out_size); DemangleInplace(out, out_size);
out_size -= std::strlen(out);
if (found) {
std::size_t fnlen = std::strlen(line.FileName);
// Determine the number of digits (base 10) necessary to represent the
// line number
std::size_t digits = 1; // At least one digit required
for (DWORD value = line.LineNumber; (value /= 10) != 0; ++digits) {
}
constexpr std::size_t extralen = 4; // space + parens () + :
const std::size_t suffixlen = fnlen + extralen + fnlen + digits;
if (suffixlen < out_size) {
out_size -= std::snprintf(out + namelen, out_size, " (%s:%lu)",
line.FileName, line.LineNumber);
}
}
return true; return true;
} }
return false; return false;
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#else #else
# error BUG: HAVE_SYMBOLIZE was wrongly set # error BUG: HAVE_SYMBOLIZE was wrongly set
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
bool Symbolize(void* pc, char* out, size_t out_size, SymbolizeOptions options) { bool Symbolize(void *pc, char *out, size_t out_size) {
return SymbolizeAndDemangle(pc, out, out_size, options); return SymbolizeAndDemangle(pc, out, out_size);
} }
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#else /* HAVE_SYMBOLIZE */
#include <cassert>
#include "config.h"
_START_GOOGLE_NAMESPACE_
// TODO: Support other environments.
bool Symbolize(void* /*pc*/, char* /*out*/, size_t /*out_size*/) {
assert(0);
return false;
}
_END_GOOGLE_NAMESPACE_
#endif #endif

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -51,58 +51,35 @@
// malloc() and other unsafe operations. It should be both // malloc() and other unsafe operations. It should be both
// thread-safe and async-signal-safe. // thread-safe and async-signal-safe.
#ifndef GLOG_INTERNAL_SYMBOLIZE_H #ifndef BASE_SYMBOLIZE_H_
#define GLOG_INTERNAL_SYMBOLIZE_H #define BASE_SYMBOLIZE_H_
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include "config.h" #include "config.h"
#include "glog/platform.h" #include "glog/logging.h"
#include "utilities.h"
#if defined(HAVE_LINK_H)
# include <link.h> // For ElfW() macro.
#elif defined(HAVE_ELF_H)
# include <elf.h>
#elif defined(HAVE_SYS_EXEC_ELF_H)
# include <sys/exec_elf.h>
#endif
#if defined(GLOG_USE_GLOG_EXPORT)
# include "glog/export.h"
#endif
#if !defined(GLOG_NO_EXPORT)
# error "symbolize.h" was not included correctly.
#endif
// We prefer to let the build system detect the availability of certain features
// such as symbolization support. HAVE_SYMBOLIZE should therefore be defined by
// the build system in general unless there is a good reason to perform the
// detection using the preprocessor.
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
# ifndef HAVE_SYMBOLIZE
// defined by gcc
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
# define HAVE_SYMBOLIZE
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
# elif defined(GLOG_OS_WINDOWS)
// Use DbgHelp to symbolize
# define HAVE_SYMBOLIZE
# endif
# endif // !defined(HAVE_SYMBOLIZE)
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
#ifdef HAVE_SYMBOLIZE #ifdef HAVE_SYMBOLIZE
# if !defined(SIZEOF_VOID_P) && defined(__SIZEOF_POINTER__) #if defined(__ELF__) // defined by gcc
# define SIZEOF_VOID_P __SIZEOF_POINTER__ #if defined(__OpenBSD__)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif #endif
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) #if !defined(ANDROID)
#include <link.h> // For ElfW() macro.
#endif
// For systems where SIZEOF_VOID_P is not defined, determine it
// based on __LP64__ (defined by gcc on 64-bit systems)
#if !defined(SIZEOF_VOID_P)
# if defined(__LP64__)
# define SIZEOF_VOID_P 8
# else
# define SIZEOF_VOID_P 4
# endif
#endif
// If there is no ElfW macro, let's define it by ourself. // If there is no ElfW macro, let's define it by ourself.
#ifndef ElfW #ifndef ElfW
@ -115,22 +92,18 @@
# endif # endif
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// Gets the section header for the given name, if it exists. Returns true on // Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false. // success. Otherwise, returns false.
GLOG_NO_EXPORT
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len, bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out); ElfW(Shdr) *out);
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
# endif #endif /* __ELF__ */
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
// Restrictions on the callbacks that follow: // Restrictions on the callbacks that follow:
// - The callbacks must not use heaps but only use stacks. // - The callbacks must not use heaps but only use stacks.
@ -144,7 +117,7 @@ inline namespace glog_internal_namespace_ {
// and return the size of the output written. On error, the callback // and return the size of the output written. On error, the callback
// function should return -1. // function should return -1.
using SymbolizeCallback = int (*)(int, void *, char *, size_t, uint64_t); using SymbolizeCallback = int (*)(int, void *, char *, size_t, uint64_t);
GLOG_NO_EXPORT GLOG_EXPORT
void InstallSymbolizeCallback(SymbolizeCallback callback); void InstallSymbolizeCallback(SymbolizeCallback callback);
// Installs a callback function, which will be called instead of // Installs a callback function, which will be called instead of
@ -157,54 +130,23 @@ void InstallSymbolizeCallback(SymbolizeCallback callback);
// file is opened successfully, returns the file descriptor. Otherwise, // file is opened successfully, returns the file descriptor. Otherwise,
// returns -1. |out_file_name_size| is the size of the file name buffer // returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator). // (including the null-terminator).
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&, using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t &,
char*, size_t); uint64_t &, char *, size_t);
GLOG_NO_EXPORT
void InstallSymbolizeOpenObjectFileCallback( void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback); SymbolizeOpenObjectFileCallback callback);
} // namespace glog_internal_namespace_ _END_GOOGLE_NAMESPACE_
} // namespace google
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ {
#if defined(HAVE_SYMBOLIZE)
enum class SymbolizeOptions {
// No additional options.
kNone = 0,
// Do not display source and line numbers in the symbolized output.
kNoLineNumbers = 1
};
constexpr SymbolizeOptions operator&(SymbolizeOptions lhs,
SymbolizeOptions rhs) noexcept {
return static_cast<SymbolizeOptions>(
static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) &
static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));
}
constexpr SymbolizeOptions operator|(SymbolizeOptions lhs,
SymbolizeOptions rhs) noexcept {
return static_cast<SymbolizeOptions>(
static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) |
static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));
}
// Symbolizes a program counter. On success, returns true and write the // Symbolizes a program counter. On success, returns true and write the
// symbol name to "out". The symbol name is demangled if possible // symbol name to "out". The symbol name is demangled if possible
// (supports symbols generated by GCC 3.x or newer). Otherwise, // (supports symbols generated by GCC 3.x or newer). Otherwise,
// returns false. // returns false.
GLOG_NO_EXPORT bool Symbolize( GLOG_EXPORT bool Symbolize(void* pc, char* out, size_t out_size);
void* pc, char* out, size_t out_size,
SymbolizeOptions options = SymbolizeOptions::kNone);
#endif // defined(HAVE_SYMBOLIZE) _END_GOOGLE_NAMESPACE_
} // namespace glog_internal_namespace_ #endif // BASE_SYMBOLIZE_H_
} // namespace google
#endif // GLOG_INTERNAL_SYMBOLIZE_H

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2006, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -40,15 +40,14 @@
#include "glog/logging.h" #include "glog/logging.h"
#include "googletest.h" #include "googletest.h"
#include "utilities.h" #include "utilities.h"
#include "stacktrace.h"
#ifdef GLOG_USE_GFLAGS #ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h> #include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE; using namespace GFLAGS_NAMESPACE;
#endif #endif
using namespace std; using namespace std;
using namespace google; using namespace GOOGLE_NAMESPACE;
// Avoid compile error due to "cast between pointer-to-function and // Avoid compile error due to "cast between pointer-to-function and
// pointer-to-object is an extension" warnings. // pointer-to-object is an extension" warnings.
@ -61,13 +60,11 @@ using namespace google;
#define always_inline #define always_inline
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) || \ #if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
// A wrapper function for Symbolize() to make the unit test simple. // A wrapper function for Symbolize() to make the unit test simple.
static const char* TrySymbolize(void* pc, google::SymbolizeOptions options = static const char *TrySymbolize(void *pc) {
google::SymbolizeOptions::kNone) {
static char symbol[4096]; static char symbol[4096];
if (Symbolize(pc, symbol, sizeof(symbol), options)) { if (Symbolize(pc, symbol, sizeof(symbol))) {
return symbol; return symbol;
} else { } else {
return nullptr; return nullptr;
@ -75,21 +72,23 @@ static const char* TrySymbolize(void* pc, google::SymbolizeOptions options =
} }
#endif #endif
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) # if defined(__ELF__)
// This unit tests make sense only with GCC. // This unit tests make sense only with GCC.
// Uses lots of GCC specific features. // Uses lots of GCC specific features.
#if defined(__GNUC__) && !defined(__OPENCC__) #if defined(__GNUC__) && !defined(__OPENCC__)
# if __GNUC__ >= 4 # if __GNUC__ >= 4
# define TEST_WITH_MODERN_GCC # define TEST_WITH_MODERN_GCC
# if defined(__i386__) && __i386__ // always_inline isn't supported for # if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
// x86_64 with GCC 4.1.0.
# undef always_inline # undef always_inline
# define always_inline __attribute__((always_inline)) # define always_inline __attribute__((always_inline))
# define HAVE_ALWAYS_INLINE # define HAVE_ALWAYS_INLINE
# endif // __i386__ # endif // __i386__
# else # else
# endif // __GNUC__ >= 4 # endif // __GNUC__ >= 4
# define TEST_WITH_LABEL_ADDRESSES # if defined(__i386__) || defined(__x86_64__)
# define TEST_X86_32_AND_64 1
# endif // defined(__i386__) || defined(__x86_64__)
#endif #endif
// Make them C linkage to avoid mangled names. // Make them C linkage to avoid mangled names.
@ -148,12 +147,8 @@ void ATTRIBUTE_NOINLINE Foo::func(int x) {
TEST(Symbolize, SymbolizeWithDemangling) { TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100); Foo::func(100);
#if !defined(_MSC_VER) || !defined(NDEBUG) #if !defined(_MSC_VER) || !defined(NDEBUG)
# if defined(HAVE___CXA_DEMANGLE)
EXPECT_STREQ("Foo::func(int)", TrySymbolize((void*)(&Foo::func)));
# else
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func))); EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
#endif #endif
# endif
} }
#endif #endif
@ -221,6 +216,7 @@ static int GetStackConsumption(const char* alt_stack) {
// Call Symbolize and figure out the stack footprint of this call. // Call Symbolize and figure out the stack footprint of this call.
static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) { static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
g_pc_to_symbolize = pc; g_pc_to_symbolize = pc;
// The alt-signal-stack cannot be heap allocated because there is a // The alt-signal-stack cannot be heap allocated because there is a
@ -288,14 +284,12 @@ static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
return g_symbolize_result; return g_symbolize_result;
} }
# if !defined(HAVE___CXA_DEMANGLE)
#ifdef __ppc64__ #ifdef __ppc64__
// Symbolize stack consumption should be within 4kB. // Symbolize stack consumption should be within 4kB.
constexpr int kStackConsumptionUpperLimit = 4096; const int kStackConsumptionUpperLimit = 4096;
#else #else
// Symbolize stack consumption should be within 2kB. // Symbolize stack consumption should be within 2kB.
constexpr int kStackConsumptionUpperLimit = 2048; const int kStackConsumptionUpperLimit = 2048;
# endif
#endif #endif
TEST(Symbolize, SymbolizeStackConsumption) { TEST(Symbolize, SymbolizeStackConsumption) {
@ -306,9 +300,7 @@ TEST(Symbolize, SymbolizeStackConsumption) {
&stack_consumed); &stack_consumed);
EXPECT_STREQ("nonstatic_func", symbol); EXPECT_STREQ("nonstatic_func", symbol);
EXPECT_GT(stack_consumed, 0); EXPECT_GT(stack_consumed, 0);
# if !defined(HAVE___CXA_DEMANGLE)
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
# endif
// The name of an internal linkage symbol is not specified; allow either a // The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here. // mangled or an unmangled name here.
@ -318,12 +310,10 @@ TEST(Symbolize, SymbolizeStackConsumption) {
EXPECT_TRUE(strcmp("static_func", symbol) == 0 || EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
strcmp("static_func()", symbol) == 0); strcmp("static_func()", symbol) == 0);
EXPECT_GT(stack_consumed, 0); EXPECT_GT(stack_consumed, 0);
# if !defined(HAVE___CXA_DEMANGLE)
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
# endif
} }
# if defined(TEST_WITH_MODERN_GCC) && !defined(HAVE___CXA_DEMANGLE) #ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) { TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
Foo::func(100); Foo::func(100);
int stack_consumed; int stack_consumed;
@ -332,11 +322,7 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func), symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func),
&stack_consumed); &stack_consumed);
# if defined(HAVE___CXA_DEMANGLE)
EXPECT_STREQ("Foo::func(int)", symbol);
# else
EXPECT_STREQ("Foo::func()", symbol); EXPECT_STREQ("Foo::func()", symbol);
# endif
EXPECT_GT(stack_consumed, 0); EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit); EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
} }
@ -348,9 +334,8 @@ TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
extern "C" { extern "C" {
inline void* always_inline inline_func() { inline void* always_inline inline_func() {
void *pc = nullptr; void *pc = nullptr;
# ifdef TEST_WITH_LABEL_ADDRESSES #ifdef TEST_X86_32_AND_64
pc = &&curr_pc; __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
curr_pc:
#endif #endif
return pc; return pc;
} }
@ -358,15 +343,14 @@ curr_pc:
void* ATTRIBUTE_NOINLINE non_inline_func(); void* ATTRIBUTE_NOINLINE non_inline_func();
void* ATTRIBUTE_NOINLINE non_inline_func() { void* ATTRIBUTE_NOINLINE non_inline_func() {
void *pc = nullptr; void *pc = nullptr;
# ifdef TEST_WITH_LABEL_ADDRESSES #ifdef TEST_X86_32_AND_64
pc = &&curr_pc; __asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
curr_pc:
#endif #endif
return pc; return pc;
} }
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() { static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE) #if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
void *pc = non_inline_func(); void *pc = non_inline_func();
const char *symbol = TrySymbolize(pc); const char *symbol = TrySymbolize(pc);
@ -379,7 +363,7 @@ static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
} }
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() { static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE) #if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
void *pc = inline_func(); // Must be inlined. void *pc = inline_func(); // Must be inlined.
const char *symbol = TrySymbolize(pc); const char *symbol = TrySymbolize(pc);
@ -396,8 +380,7 @@ static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() { static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
#if defined(HAVE_ATTRIBUTE_NOINLINE) #if defined(HAVE_ATTRIBUTE_NOINLINE)
void *return_address = __builtin_return_address(0); void *return_address = __builtin_return_address(0);
const char* symbol = const char *symbol = TrySymbolize(return_address);
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
#if !defined(_MSC_VER) || !defined(NDEBUG) #if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr); CHECK(symbol != nullptr);
@ -442,15 +425,14 @@ __declspec(noinline) void TestWithReturnAddress() {
_ReturnAddress() _ReturnAddress()
#endif #endif
; ;
const char* symbol = const char *symbol = TrySymbolize(return_address);
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
#if !defined(_MSC_VER) || !defined(NDEBUG) #if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr); CHECK(symbol != nullptr);
CHECK_STREQ(symbol, "main"); CHECK_STREQ(symbol, "main");
#endif #endif
cout << "Test case TestWithReturnAddress passed." << endl; cout << "Test case TestWithReturnAddress passed." << endl;
} }
# endif # endif // __ELF__
#endif // HAVE_STACKTRACE #endif // HAVE_STACKTRACE
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -458,7 +440,7 @@ int main(int argc, char** argv) {
InitGoogleLogging(argv[0]); InitGoogleLogging(argv[0]);
InitGoogleTest(&argc, argv); InitGoogleTest(&argc, argv);
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE) #if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) # if defined(__ELF__)
// We don't want to get affected by the callback interface, that may be // We don't want to get affected by the callback interface, that may be
// used to install some callback function at InitGoogle() time. // used to install some callback function at InitGoogle() time.
InstallSymbolizeCallback(nullptr); InstallSymbolizeCallback(nullptr);
@ -473,7 +455,7 @@ int main(int argc, char** argv) {
# else // GLOG_OS_WINDOWS # else // GLOG_OS_WINDOWS
printf("PASS (no symbolize_unittest support)\n"); printf("PASS (no symbolize_unittest support)\n");
return 0; return 0;
# endif // defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) # endif // __ELF__
#else #else
printf("PASS (no symbolize support)\n"); printf("PASS (no symbolize support)\n");
return 0; return 0;

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -29,29 +29,17 @@
// //
// Author: Shinichiro Hamaji // Author: Shinichiro Hamaji
#define _GNU_SOURCE 1 #include "config.h"
#include "utilities.h" #include "utilities.h"
#include <atomic>
#include <cerrno>
#include <csignal>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include "base/googleinit.h" #include <csignal>
#include "config.h"
#include "glog/flags.h"
#include "glog/logging.h"
#include "stacktrace.h"
#include "symbolize.h"
#ifdef GLOG_OS_ANDROID
# include <android/log.h>
#endif
#ifdef HAVE_SYS_TIME_H #ifdef HAVE_SYS_TIME_H
# include <sys/time.h> # include <sys/time.h>
#endif #endif
#include <ctime>
#if defined(HAVE_SYSCALL_H) #if defined(HAVE_SYSCALL_H)
#include <syscall.h> // for syscall() #include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H) #elif defined(HAVE_SYS_SYSCALL_H)
@ -66,14 +54,15 @@
#ifdef HAVE_PWD_H #ifdef HAVE_PWD_H
# include <pwd.h> # include <pwd.h>
#endif #endif
#ifdef __ANDROID__
#if defined(HAVE___PROGNAME) #include <android/log.h>
extern char* __progname;
#endif #endif
#include "base/googleinit.h"
using std::string; using std::string;
namespace google { _START_GOOGLE_NAMESPACE_
static const char* g_program_invocation_short_name = nullptr; static const char* g_program_invocation_short_name = nullptr;
@ -81,45 +70,19 @@ bool IsGoogleLoggingInitialized() {
return g_program_invocation_short_name != nullptr; return g_program_invocation_short_name != nullptr;
} }
inline namespace glog_internal_namespace_ { _END_GOOGLE_NAMESPACE_
constexpr int FileDescriptor::InvalidHandle;
void AlsoErrorWrite(LogSeverity severity, const char* tag,
const char* message) noexcept {
#if defined(GLOG_OS_WINDOWS)
(void)severity;
(void)tag;
// On Windows, also output to the debugger
::OutputDebugStringA(message);
#elif defined(GLOG_OS_ANDROID)
constexpr int android_log_levels[] = {
ANDROID_LOG_INFO,
ANDROID_LOG_WARN,
ANDROID_LOG_ERROR,
ANDROID_LOG_FATAL,
};
__android_log_write(android_log_levels[severity], tag, message);
#else
(void)severity;
(void)tag;
(void)message;
#endif
}
} // namespace glog_internal_namespace_
} // namespace google
// The following APIs are all internal. // The following APIs are all internal.
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
# include "base/commandlineflags.h"
#include "stacktrace.h" #include "stacktrace.h"
#include "symbolize.h" #include "symbolize.h"
#include "base/commandlineflags.h"
namespace google { GLOG_DEFINE_bool(symbolize_stacktrace, true,
"Symbolize the stack trace in the tombstone");
_START_GOOGLE_NAMESPACE_
using DebugWriter = void(const char*, void*); using DebugWriter = void(const char*, void*);
@ -129,11 +92,15 @@ static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
static void DebugWriteToStderr(const char* data, void *) { static void DebugWriteToStderr(const char* data, void *) {
// This one is signal-safe. // This one is signal-safe.
if (write(fileno(stderr), data, strlen(data)) < 0) { if (write(STDERR_FILENO, data, strlen(data)) < 0) {
// Ignore errors. // Ignore errors.
} }
AlsoErrorWrite(GLOG_FATAL, #if defined(__ANDROID__)
glog_internal_namespace_::ProgramInvocationShortName(), data); // ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
__android_log_write(ANDROID_LOG_FATAL,
glog_internal_namespace_::ProgramInvocationShortName(),
data);
#endif
} }
static void DebugWriteToString(const char* data, void *arg) { static void DebugWriteToString(const char* data, void *arg) {
@ -153,8 +120,8 @@ static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
symbol = tmp; symbol = tmp;
} }
char buf[1024]; char buf[1024];
std::snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix, snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
kPrintfPointerFieldWidth, pc, symbol); prefix, kPrintfPointerFieldWidth, pc, symbol);
writerfn(buf, arg); writerfn(buf, arg);
} }
#endif #endif
@ -162,8 +129,8 @@ static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc, static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) { const char * const prefix) {
char buf[100]; char buf[100];
std::snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth, snprintf(buf, sizeof(buf), "%s@ %*p\n",
pc); prefix, kPrintfPointerFieldWidth, pc);
writerfn(buf, arg); writerfn(buf, arg);
} }
@ -210,41 +177,74 @@ DumpStackTraceAndExit() {
abort(); abort();
} }
} // namespace google _END_GOOGLE_NAMESPACE_
#endif // HAVE_STACKTRACE #endif // HAVE_STACKTRACE
namespace google { _START_GOOGLE_NAMESPACE_
inline namespace glog_internal_namespace_ { namespace glog_internal_namespace_ {
const char* const_basename(const char* filepath) {
const char* base = strrchr(filepath, '/');
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
if (!base) base = strrchr(filepath, '\\');
#endif
return base ? (base + 1) : filepath;
}
const char* ProgramInvocationShortName() { const char* ProgramInvocationShortName() {
if (g_program_invocation_short_name != nullptr) { if (g_program_invocation_short_name != nullptr) {
return g_program_invocation_short_name; return g_program_invocation_short_name;
} } else {
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME) // TODO(hamaji): Use /proc/self/cmdline and so?
return program_invocation_short_name;
#elif defined(HAVE_GETPROGNAME)
return getprogname();
#elif defined(HAVE___PROGNAME)
return __progname;
#elif defined(HAVE___ARGV)
return const_basename(__argv[0]);
#else
return "UNKNOWN"; return "UNKNOWN";
}
}
#ifdef GLOG_OS_WINDOWS
struct timeval {
long tv_sec, tv_usec;
};
// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
// See COPYING for copyright information.
static int gettimeofday(struct timeval *tv, void* /*tz*/) {
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wlong-long"
#endif #endif
#define EPOCHFILETIME (116444736000000000ULL)
FILETIME ft;
ULARGE_INTEGER li;
uint64 tt;
GetSystemTimeAsFileTime(&ft);
li.LowPart = ft.dwLowDateTime;
li.HighPart = ft.dwHighDateTime;
tt = (li.QuadPart - EPOCHFILETIME) / 10;
tv->tv_sec = tt / 1000000;
tv->tv_usec = tt % 1000000;
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
return 0;
}
#endif
int64 CycleClock_Now() {
// TODO(hamaji): temporary impementation - it might be too slow.
struct timeval tv;
gettimeofday(&tv, nullptr);
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
}
int64 UsecToCycles(int64 usec) {
return usec;
}
WallTime WallTime_Now() {
// Now, cycle clock is retuning microseconds since the epoch.
return CycleClock_Now() * 0.000001;
} }
static int32 g_main_thread_pid = getpid(); static int32 g_main_thread_pid = getpid();
int32 GetMainThreadPid() { return g_main_thread_pid; } int32 GetMainThreadPid() {
return g_main_thread_pid;
}
bool PidHasChanged() { bool PidHasChanged() {
int32 pid = getpid(); int32 pid = getpid();
@ -255,8 +255,66 @@ bool PidHasChanged() {
return true; return true;
} }
pid_t GetTID() {
// On Linux and MacOSX, we try to use gettid().
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
#ifndef __NR_gettid
#ifdef GLOG_OS_MACOSX
#define __NR_gettid SYS_gettid
#elif ! defined __i386__
#error "Must define __NR_gettid for non-x86 platforms"
#else
#define __NR_gettid 224
#endif
#endif
static bool lacks_gettid = false;
if (!lacks_gettid) {
#if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
uint64_t tid64;
const int error = pthread_threadid_np(nullptr, &tid64);
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
#else
auto tid = static_cast<pid_t>(syscall(__NR_gettid));
#endif
if (tid != -1) {
return tid;
}
// Technically, this variable has to be volatile, but there is a small
// performance penalty in accessing volatile variables and there should
// not be any serious adverse effect if a thread does not immediately see
// the value change to "true".
lacks_gettid = true;
}
#endif // GLOG_OS_LINUX || GLOG_OS_MACOSX
// If gettid() could not be used, we use one of the following.
#if defined GLOG_OS_LINUX
return getpid(); // Linux: getpid returns thread ID when gettid is absent
#elif defined GLOG_OS_WINDOWS && !defined GLOG_OS_CYGWIN
return static_cast<pid_t>(GetCurrentThreadId());
#elif defined GLOG_OS_OPENBSD
return getthrid();
#elif defined(HAVE_PTHREAD)
// If none of the techniques above worked, we use pthread_self().
return (pid_t)(uintptr_t)pthread_self();
#else
return -1;
#endif
}
const char* const_basename(const char* filepath) {
const char* base = strrchr(filepath, '/');
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
if (!base)
base = strrchr(filepath, '\\');
#endif
return base ? (base+1) : filepath;
}
static string g_my_user_name; static string g_my_user_name;
const string& MyUserName() { return g_my_user_name; } const string& MyUserName() {
return g_my_user_name;
}
static void MyUserNameInitializer() { static void MyUserNameInitializer() {
// TODO(hamaji): Probably this is not portable. // TODO(hamaji): Probably this is not portable.
#if defined(GLOG_OS_WINDOWS) #if defined(GLOG_OS_WINDOWS)
@ -276,7 +334,7 @@ static void MyUserNameInitializer() {
if (pwuid_res == 0 && result) { if (pwuid_res == 0 && result) {
g_my_user_name = pwd.pw_name; g_my_user_name = pwd.pw_name;
} else { } else {
std::snprintf(buffer, sizeof(buffer), "uid%d", uid); snprintf(buffer, sizeof(buffer), "uid%d", uid);
g_my_user_name = buffer; g_my_user_name = buffer;
} }
#endif #endif
@ -287,19 +345,30 @@ static void MyUserNameInitializer() {
} }
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer()) REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())
#ifdef HAVE_STACKTRACE
void DumpStackTraceToString(string* stacktrace) {
DumpStackTrace(1, DebugWriteToString, stacktrace);
}
#endif
// We use an atomic operation to prevent problems with calling CrashReason // We use an atomic operation to prevent problems with calling CrashReason
// from inside the Mutex implementation (potentially through RAW_CHECK). // from inside the Mutex implementation (potentially through RAW_CHECK).
static std::atomic<const logging::internal::CrashReason*> g_reason{nullptr}; static const CrashReason* g_reason = nullptr;
void SetCrashReason(const logging::internal::CrashReason* r) { void SetCrashReason(const CrashReason* r) {
const logging::internal::CrashReason* expected = nullptr; sync_val_compare_and_swap(&g_reason,
g_reason.compare_exchange_strong(expected, r); reinterpret_cast<const CrashReason*>(0),
r);
} }
void InitGoogleLoggingUtilities(const char* argv0) { void InitGoogleLoggingUtilities(const char* argv0) {
CHECK(!IsGoogleLoggingInitialized()) CHECK(!IsGoogleLoggingInitialized())
<< "You called InitGoogleLogging() twice!"; << "You called InitGoogleLogging() twice!";
g_program_invocation_short_name = const_basename(argv0); const char* slash = strrchr(argv0, '/');
#ifdef GLOG_OS_WINDOWS
if (!slash) slash = strrchr(argv0, '\\');
#endif
g_program_invocation_short_name = slash ? slash + 1 : argv0;
#ifdef HAVE_STACKTRACE #ifdef HAVE_STACKTRACE
InstallFailureFunction(&DumpStackTraceAndExit); InstallFailureFunction(&DumpStackTraceAndExit);
@ -308,8 +377,7 @@ void InitGoogleLoggingUtilities(const char* argv0) {
void ShutdownGoogleLoggingUtilities() { void ShutdownGoogleLoggingUtilities() {
CHECK(IsGoogleLoggingInitialized()) CHECK(IsGoogleLoggingInitialized())
<< "You called ShutdownGoogleLogging() without calling " << "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
"InitGoogleLogging() first!";
g_program_invocation_short_name = nullptr; g_program_invocation_short_name = nullptr;
#ifdef HAVE_SYSLOG_H #ifdef HAVE_SYSLOG_H
closelog(); closelog();
@ -318,12 +386,17 @@ void ShutdownGoogleLoggingUtilities() {
} // namespace glog_internal_namespace_ } // namespace glog_internal_namespace_
#ifdef HAVE_STACKTRACE _END_GOOGLE_NAMESPACE_
std::string GetStackTrace() {
std::string stacktrace;
DumpStackTrace(1, DebugWriteToString, &stacktrace);
return stacktrace;
}
#endif
} // namespace google // Make an implementation of stacktrace compiled.
#ifdef STACKTRACE_H
# include STACKTRACE_H
# if 0
// For include scanners which can't handle macro expansions.
# include "stacktrace_libunwind-inl.h"
# include "stacktrace_x86-inl.h"
# include "stacktrace_x86_64-inl.h"
# include "stacktrace_powerpc-inl.h"
# include "stacktrace_generic-inl.h"
# endif
#endif

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc. // Copyright (c) 2008, Google Inc.
// All rights reserved. // All rights reserved.
// //
// Redistribution and use in source and binary forms, with or without // Redistribution and use in source and binary forms, with or without
@ -28,19 +28,11 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// //
// Author: Shinichiro Hamaji // Author: Shinichiro Hamaji
// Sergiu Deitsch
// //
// Define utilities for glog internal usage. // Define utilities for glog internal usage.
#ifndef GLOG_INTERNAL_UTILITIES_H #ifndef UTILITIES_H__
#define GLOG_INTERNAL_UTILITIES_H #define UTILITIES_H__
#include <cstddef>
#include <cstdio>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
// printf macros for size_t, in the style of inttypes.h // printf macros for size_t, in the style of inttypes.h
#ifdef _LP64 #ifdef _LP64
@ -60,25 +52,16 @@
#define PRIXS __PRIS_PREFIX "X" #define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o" #define PRIoS __PRIS_PREFIX "o"
#include "config.h" #include <string>
#include "glog/platform.h"
#if defined(GLOG_USE_WINDOWS_PORT) #include "base/mutex.h" // This must go first so we get _XOPEN_SOURCE
#include "glog/logging.h"
#if defined(GLOG_OS_WINDOWS)
# include "port.h" # include "port.h"
#endif #endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#if !defined(HAVE_SSIZE_T)
# if defined(GLOG_OS_WINDOWS)
# include <basetsd.h>
using ssize_t = SSIZE_T;
# else
using ssize_t = std::ptrdiff_t;
# endif
#endif
#include "glog/log_severity.h" #include "config.h"
#include "glog/types.h"
// There are three different ways we can try to get the stack trace: // There are three different ways we can try to get the stack trace:
// //
@ -102,15 +85,109 @@ using ssize_t = std::ptrdiff_t;
// correctly when GetStackTrace() is called with max_depth == 0. // correctly when GetStackTrace() is called with max_depth == 0.
// Some code may do that. // Some code may do that.
#if defined(HAVE_LIB_UNWIND)
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
#elif defined(HAVE__UNWIND_BACKTRACE) && defined(HAVE__UNWIND_GETIP)
# define STACKTRACE_H "stacktrace_unwind-inl.h"
#elif !defined(NO_FRAME_POINTER)
# if defined(__i386__) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_x86-inl.h"
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
# elif defined(GLOG_OS_WINDOWS)
# define STACKTRACE_H "stacktrace_windows-inl.h"
# endif
#endif
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
# define STACKTRACE_H "stacktrace_generic-inl.h"
#endif
#if defined(STACKTRACE_H)
# define HAVE_STACKTRACE
#endif
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
#ifndef HAVE_SYMBOLIZE
// defined by gcc
#if defined(__ELF__) && defined(GLOG_OS_LINUX)
# define HAVE_SYMBOLIZE
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
// Use dladdr to symbolize.
# define HAVE_SYMBOLIZE
#elif defined(GLOG_OS_WINDOWS)
// Use DbgHelp to symbolize
# define HAVE_SYMBOLIZE
#endif
#endif // !defined(HAVE_SYMBOLIZE)
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
#ifndef ARRAYSIZE #ifndef ARRAYSIZE
// There is a better way, but this is good enough for our purpose. // There is a better way, but this is good enough for our purpose.
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a))) # define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
#endif #endif
namespace google { _START_GOOGLE_NAMESPACE_
namespace logging { namespace glog_internal_namespace_ {
namespace internal {
#ifdef HAVE___ATTRIBUTE__
# define ATTRIBUTE_NOINLINE __attribute__ ((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
#elif defined(GLOG_OS_WINDOWS)
# define ATTRIBUTE_NOINLINE __declspec(noinline)
# define HAVE_ATTRIBUTE_NOINLINE
#else
# define ATTRIBUTE_NOINLINE
#endif
const char* ProgramInvocationShortName();
int64 CycleClock_Now();
int64 UsecToCycles(int64 usec);
WallTime WallTime_Now();
int32 GetMainThreadPid();
bool PidHasChanged();
pid_t GetTID();
const std::string& MyUserName();
// Get the part of filepath after the last path separator.
// (Doesn't modify filepath, contrary to basename() in libgen.h.)
const char* const_basename(const char* filepath);
// Wrapper of __sync_val_compare_and_swap. If the GCC extension isn't
// defined, we try the CPU specific logics (we only support x86 and
// x86_64 for now) first, then use a naive implementation, which has a
// race condition.
template<typename T>
inline T sync_val_compare_and_swap(T* ptr, T oldval, T newval) {
#if defined(HAVE___SYNC_VAL_COMPARE_AND_SWAP)
return __sync_val_compare_and_swap(ptr, oldval, newval);
#elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
T ret;
__asm__ __volatile__("lock; cmpxchg %1, (%2);"
:"=a"(ret)
// GCC may produces %sil or %dil for
// constraint "r", but some of apple's gas
// doesn't know the 8 bit registers.
// We use "q" to avoid these registers.
:"q"(newval), "q"(ptr), "a"(oldval)
:"memory", "cc");
return ret;
#else
T ret = *ptr;
if (ret == oldval) {
*ptr = newval;
}
return ret;
#endif
}
void DumpStackTraceToString(std::string* stacktrace);
struct CrashReason { struct CrashReason {
CrashReason() = default; CrashReason() = default;
@ -125,159 +202,15 @@ struct CrashReason {
int depth{0}; int depth{0};
}; };
} // namespace internal void SetCrashReason(const CrashReason* r);
} // namespace logging
inline namespace glog_internal_namespace_ {
#if defined(__has_attribute)
# if __has_attribute(noinline)
# define ATTRIBUTE_NOINLINE __attribute__((noinline))
# define HAVE_ATTRIBUTE_NOINLINE
# endif
#endif
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
# if defined(GLOG_OS_WINDOWS)
# define ATTRIBUTE_NOINLINE __declspec(noinline)
# define HAVE_ATTRIBUTE_NOINLINE
# endif
#endif
#if !defined(HAVE_ATTRIBUTE_NOINLINE)
# define ATTRIBUTE_NOINLINE
#endif
void AlsoErrorWrite(LogSeverity severity, const char* tag,
const char* message) noexcept;
const char* ProgramInvocationShortName();
int32 GetMainThreadPid();
bool PidHasChanged();
const std::string& MyUserName();
// Get the part of filepath after the last path separator.
// (Doesn't modify filepath, contrary to basename() in libgen.h.)
const char* const_basename(const char* filepath);
void SetCrashReason(const logging::internal::CrashReason* r);
void InitGoogleLoggingUtilities(const char* argv0); void InitGoogleLoggingUtilities(const char* argv0);
void ShutdownGoogleLoggingUtilities(); void ShutdownGoogleLoggingUtilities();
template <class Functor>
class ScopedExit final {
public:
template <class F, std::enable_if_t<
std::is_constructible<Functor, F&&>::value>* = nullptr>
constexpr explicit ScopedExit(F&& functor) noexcept(
std::is_nothrow_constructible<Functor, F&&>::value)
: functor_{std::forward<F>(functor)} {}
~ScopedExit() noexcept(noexcept(std::declval<Functor&>()())) { functor_(); }
ScopedExit(const ScopedExit& other) = delete;
ScopedExit& operator=(const ScopedExit& other) = delete;
ScopedExit(ScopedExit&& other) noexcept = delete;
ScopedExit& operator=(ScopedExit&& other) noexcept = delete;
private:
Functor functor_;
};
// Thin wrapper around a file descriptor so that the file descriptor
// gets closed for sure.
class GLOG_NO_EXPORT FileDescriptor final {
static constexpr int InvalidHandle = -1;
public:
constexpr FileDescriptor() noexcept : FileDescriptor{nullptr} {}
constexpr explicit FileDescriptor(int fd) noexcept : fd_{fd} {}
// NOLINTNEXTLINE(google-explicit-constructor)
constexpr FileDescriptor(std::nullptr_t) noexcept : fd_{InvalidHandle} {}
FileDescriptor(const FileDescriptor& other) = delete;
FileDescriptor& operator=(const FileDescriptor& other) = delete;
FileDescriptor(FileDescriptor&& other) noexcept : fd_{other.release()} {}
FileDescriptor& operator=(FileDescriptor&& other) noexcept {
// Close the file descriptor being held and assign a new file descriptor
// previously held by 'other' without closing it.
reset(other.release());
return *this;
}
constexpr explicit operator bool() const noexcept {
return fd_ != InvalidHandle;
}
constexpr int get() const noexcept { return fd_; }
int release() noexcept { return std::exchange(fd_, InvalidHandle); }
void reset(std::nullptr_t) noexcept { safe_close(); }
void reset() noexcept { reset(nullptr); }
void reset(int fd) noexcept {
reset();
fd_ = fd;
}
int close() noexcept { return unsafe_close(); }
~FileDescriptor() { safe_close(); }
private:
int unsafe_close() noexcept { return ::close(release()); }
void safe_close() noexcept {
if (*this) {
unsafe_close();
}
}
int fd_;
};
// Provide variants of (in)equality comparison operators to avoid constructing
// temporaries.
constexpr bool operator==(const FileDescriptor& lhs, int rhs) noexcept {
return lhs.get() == rhs;
}
constexpr bool operator==(int lhs, const FileDescriptor& rhs) noexcept {
return rhs == lhs;
}
constexpr bool operator!=(const FileDescriptor& lhs, int rhs) noexcept {
return !(lhs == rhs);
}
constexpr bool operator!=(int lhs, const FileDescriptor& rhs) noexcept {
return !(lhs == rhs);
}
constexpr bool operator==(const FileDescriptor& lhs, std::nullptr_t) noexcept {
return !lhs;
}
constexpr bool operator==(std::nullptr_t, const FileDescriptor& rhs) noexcept {
return !rhs;
}
constexpr bool operator!=(const FileDescriptor& lhs, std::nullptr_t) noexcept {
return static_cast<bool>(lhs);
}
constexpr bool operator!=(std::nullptr_t, const FileDescriptor& rhs) noexcept {
return static_cast<bool>(rhs);
}
} // namespace glog_internal_namespace_ } // namespace glog_internal_namespace_
} // namespace google _END_GOOGLE_NAMESPACE_
template <> using namespace GOOGLE_NAMESPACE::glog_internal_namespace_;
struct std::default_delete<std::FILE> {
void operator()(FILE* p) const noexcept { fclose(p); }
};
#endif // GLOG_INTERNAL_UTILITIES_H #endif // UTILITIES_H__

Some files were not shown because too many files have changed in this diff Show More