Compare commits

..

1 Commits

Author SHA1 Message Date
Sergiu Deitsch
ad92df3fbb simple packaging support 2023-12-28 02:57:12 +01:00
104 changed files with 6371 additions and 7034 deletions

View File

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

View File

@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DerivePointerAlignment: true
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
IncludeIsMainSourceRegex: ''
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: AfterHash
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
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-*'
WarningsAsErrors: ''
HeaderFilterRegex: ''
AnalyzeTemporaryDtors: false
FormatStyle: file
CheckOptions:
- key: cert-dcl16-c.NewSuffixes

View File

@ -40,11 +40,18 @@ jobs:
env:
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}
run: |
emcmake cmake -S . -B build_${{matrix.build_type}} \
cmake -S . -B build_${{matrix.build_type}} \
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
-DCMAKE_AR=$(which emar) \
-DCMAKE_CXX_COMPILER=$(which em++) \
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
-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_RANLIB=$(which emranlib) \
-G Ninja \
-Werror

View File

@ -31,20 +31,42 @@ jobs:
- name: Setup Dependencies
run: |
sudo apt-get update
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-suggests --no-install-recommends \
g++ \
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
build-essential \
cmake \
gcovr \
libgflags-dev \
libgmock-dev \
libgtest-dev \
libunwind-dev \
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
if: matrix.build_type == 'Debug'
run: |
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
echo 'GTest_ROOT=${{github.workspace}}/gtest' >> $GITHUB_ENV
- name: Configure
env:
@ -106,10 +128,17 @@ jobs:
run: |
cd build_${{matrix.build_type}}
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
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml

View File

@ -63,12 +63,18 @@ jobs:
if: matrix.build_type == 'Debug'
run: |
cd build_${{matrix.build_type}}
rm -r Tests/
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
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml

View File

@ -42,21 +42,21 @@ jobs:
- name: Cache GTest
id: cache-gtest
uses: actions/cache@v4
uses: actions/cache@v3
with:
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
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
(New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip", "v1.14.0.zip")
Expand-Archive 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 release-1.11.0.zip .
- name: Build GTest
if: steps.cache-gtest.outputs.cache-hit != 'true'
run: |
cmake -S googletest-1.14.0 -B build-googletest `
cmake -S googletest-release-1.11.0 -B build-googletest `
-A ${{matrix.arch}} `
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
-Dgtest_force_shared_crt=ON `
@ -67,7 +67,7 @@ jobs:
- name: Cache gflags
id: cache-gflags
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: gflags/
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
@ -188,7 +188,7 @@ jobs:
- name: Setup Coverage Dependencies
if: matrix.build_type == 'Debug'
run: |
pip install 'gcovr==7.0'
pip install 'gcovr==6.0'
- name: Setup Environment
if: matrix.build_type == 'Debug'
@ -231,10 +231,17 @@ jobs:
run: |
cd build_${{matrix.build_type}}
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
if: matrix.build_type == 'Debug'
uses: codecov/codecov-action@v5
uses: codecov/codecov-action@v3
with:
token: ${{ secrets.CODECOV_TOKEN }}
files: build_${{matrix.build_type}}/coverage.xml

3
.gitignore vendored
View File

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

View File

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

View File

@ -1,30 +1,23 @@
cmake_minimum_required (VERSION 3.22)
cmake_minimum_required (VERSION 3.21)
project (glog
VERSION 0.8.0
VERSION 0.7.0
DESCRIPTION "C++ implementation of the Google logging module"
HOMEPAGE_URL https://github.com/google/glog
LANGUAGES CXX
)
set (CPACK_PACKAGE_NAME glog)
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library")
set (CPACK_PACKAGE_VERSION_MAJOR ${glog_VERSION_MAJOR})
set (CPACK_PACKAGE_VERSION_MINOR ${glog_VERSION_MINOR})
set (CPACK_PACKAGE_VERSION_PATCH ${glog_VERSION_PATCH})
set (CPACK_PACKAGE_VERSION ${glog_VERSION})
list (APPEND CMAKE_MODULE_PATH ${glog_SOURCE_DIR}/cmake)
include (CheckCXXSourceCompiles)
include (CheckCXXSourceRuns)
include (CheckCXXSymbolExists)
include (CheckFunctionExists)
include (CheckIncludeFileCXX)
include (CheckStructHasMember)
include (CheckTypeSize)
include (CMakeDependentOption)
include (CMakePackageConfigHelpers)
include (CMakePushCheckState)
include (CPack)
include (CTest)
include (DetermineGflagsNamespace)
include (GenerateExportHeader)
@ -32,39 +25,42 @@ include (GetCacheVariables)
include (GNUInstallDirs)
option (BUILD_SHARED_LIBS "Build shared libraries" ON)
option (BUILD_EXAMPLES "Build examples" ON)
option (PRINT_UNSYMBOLIZED_STACK_TRACES
"Print file offsets in traces instead of symbolizing" OFF)
option (WITH_GFLAGS "Use gflags" 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_TLS "Enable Thread Local Storage (TLS) support" ON)
set (WITH_UNWIND libunwind CACHE STRING "unwind driver")
set_property (CACHE WITH_UNWIND PROPERTY STRINGS none unwind libunwind)
option (WITH_THREADS "Enable multithreading support" ON)
option (WITH_UNWIND "Enable libunwind support" ON)
cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF)
cmake_dependent_option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON WITH_THREADS OFF)
set (WITH_FUZZING none CACHE STRING "Fuzzing engine")
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)
endif (WITH_UNWIND STREQUAL none)
endif (NOT WITH_UNWIND)
if (NOT WITH_GTEST)
set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)
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_CXX_VISIBILITY_PRESET hidden)
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
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)
set (HAVE_LIB_GTEST 1)
@ -83,54 +79,25 @@ if (WITH_GFLAGS)
endif (gflags_FOUND)
endif (WITH_GFLAGS)
find_package (Threads REQUIRED)
find_package (Threads)
find_package (Unwind)
if (Unwind_FOUND)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES unwind::unwind)
set (HAVE_LIB_UNWIND 1)
else (Unwind_FOUND)
# Check whether linking actually succeeds. ARM toolchains of LLVM unwind
# implementation do not necessarily provide the _Unwind_Backtrace function
# 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_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)
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 (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 (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/time.h HAVE_SYS_TIME_H)
check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)
@ -144,38 +111,79 @@ check_include_file_cxx (unistd.h HAVE_UNISTD_H)
check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)
check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)
check_cxx_symbol_exists (dladdr dlfcn.h HAVE_DLADDR)
check_cxx_symbol_exists (fcntl fcntl.h HAVE_FCNTL)
check_cxx_symbol_exists (posix_fadvise fcntl.h HAVE_POSIX_FADVISE)
check_cxx_symbol_exists (pread unistd.h HAVE_PREAD)
check_cxx_symbol_exists (pwrite unistd.h HAVE_PWRITE)
check_cxx_symbol_exists (sigaction csignal HAVE_SIGACTION)
check_cxx_symbol_exists (sigaltstack csignal HAVE_SIGALTSTACK)
check_function_exists (dladdr HAVE_DLADDR)
check_function_exists (fcntl HAVE_FCNTL)
check_function_exists (pread HAVE_PREAD)
check_function_exists (pwrite HAVE_PWRITE)
check_function_exists (sigaction HAVE_SIGACTION)
check_function_exists (sigaltstack HAVE_SIGALTSTACK)
check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
check_cxx_symbol_exists (backtrace_symbols execinfo.h
HAVE_EXECINFO_BACKTRACE_SYMBOLS)
check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_DEFINITIONS -D_XOPEN_SOURCE=500)
if (Threads_FOUND)
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
endif (Threads_FOUND)
check_cxx_symbol_exists (pthread_rwlock_destroy pthread.h HAVE_RWLOCK_DESTROY)
check_cxx_symbol_exists (pthread_rwlock_init pthread.h HAVE_RWLOCK_INIT)
check_cxx_symbol_exists (pthread_rwlock_rdlock pthread.h HAVE_RWLOCK_RDLOCK)
check_cxx_symbol_exists (pthread_rwlock_unlock pthread.h HAVE_RWLOCK_UNLOCK)
check_cxx_symbol_exists (pthread_rwlock_wrlock pthread.h HAVE_RWLOCK_WRLOCK)
check_cxx_symbol_exists (pthread_threadid_np pthread.h HAVE_PTHREAD_THREADID_NP)
cmake_pop_check_state ()
if (HAVE_RWLOCK_INIT AND HAVE_RWLOCK_RDLOCK AND HAVE_RWLOCK_WRLOCK AND
HAVE_RWLOCK_UNLOCK AND HAVE_RWLOCK_DESTROY)
set (HAVE_RWLOCK TRUE)
endif (HAVE_RWLOCK_INIT AND HAVE_RWLOCK_RDLOCK AND HAVE_RWLOCK_WRLOCK AND
HAVE_RWLOCK_UNLOCK AND HAVE_RWLOCK_DESTROY)
cmake_push_check_state (RESET)
set (CMAKE_REQUIRED_LIBRARIES dbghelp)
check_cxx_symbol_exists (UnDecorateSymbolName "windows.h;dbghelp.h" HAVE_DBGHELP)
cmake_pop_check_state ()
if (WITH_FUZZING STREQUAL none)
# Disable compiler demangler if fuzzing is active; we only want to use the
# glog demangler then.
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_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>
extern char* __progname;
int main() { return __progname != nullptr ? EXIT_SUCCESS : EXIT_FAILURE; }
]=] HAVE___PROGNAME)
static void foo(void) __attribute__ ((unused));
int main(void) { return 0; }
" 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)
check_cxx_source_compiles ("
__declspec(selectany) int a;
int main(void) { return 0; }
" HAVE___DECLSPEC)
if (WITH_TLS)
set (GLOG_THREAD_LOCAL_STORAGE 1)
@ -238,6 +246,58 @@ if (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
cmake_pop_check_state ()
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)
set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
@ -278,12 +338,12 @@ if (WITH_SYMBOLIZE)
if (HAVE_SYMBOLIZE)
set (HAVE_STACKTRACE 1)
endif (HAVE_SYMBOLIZE)
elseif (UNIX)
cmake_push_check_state (RESET)
check_cxx_symbol_exists (__ELF__ "" HAVE_SYMBOLIZE)
cmake_pop_check_state ()
elseif (APPLE AND HAVE_DLADDR)
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 (WITH_SYMBOLIZE)
@ -291,11 +351,18 @@ endif (WITH_SYMBOLIZE)
# building the library.
add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)
check_cxx_symbol_exists (gmtime_r "cstdlib;ctime" HAVE_GMTIME_R)
check_cxx_symbol_exists (localtime_r "cstdlib;ctime" HAVE_LOCALTIME_R)
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/....
# therefore we translate TEST_SRC_DIR to windows-path.
if (CYGWIN)
@ -308,6 +375,10 @@ else (CYGWIN)
endif (CYGWIN)
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)
set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})
set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
@ -349,28 +420,24 @@ endif (_glog_CMake_MODULES)
set (GLOG_PUBLIC_H
${glog_BINARY_DIR}/glog/export.h
${glog_BINARY_DIR}/glog/logging.h
${glog_BINARY_DIR}/glog/raw_logging.h
${glog_BINARY_DIR}/glog/stl_logging.h
${glog_BINARY_DIR}/glog/vlog_is_on.h
src/glog/log_severity.h
src/glog/logging.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
${GLOG_PUBLIC_H}
src/base/commandlineflags.h
src/base/googleinit.h
src/base/mutex.h
src/demangle.cc
src/demangle.h
src/flags.cc
src/logging.cc
src/raw_logging.cc
src/signalhandler.cc
src/stacktrace.cc
src/stacktrace.h
src/symbolize.cc
src/symbolize.h
src/utilities.cc
@ -378,14 +445,12 @@ set (GLOG_SRCS
src/vlog_is_on.cc
)
# NOTE MSYS2 defines both WIN32 and UNIX. Do not use windows port in this case.
if ((CYGWIN OR WIN32) AND NOT UNIX)
if (CYGWIN OR WIN32)
list (APPEND GLOG_SRCS
src/windows/port.cc
src/windows/port.h
)
set (_glog_USE_WINDOWS_PORT TRUE)
endif ((CYGWIN OR WIN32) AND NOT UNIX)
endif (CYGWIN OR WIN32)
add_library (glog_internal OBJECT
${_glog_BINARY_CMake_MODULES}
@ -413,26 +478,6 @@ add_library (glog::glog ALIAS glog)
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)
target_link_libraries (glog PRIVATE unwind::unwind)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind")
@ -444,11 +489,15 @@ if (HAVE_DBGHELP)
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp")
endif (HAVE_DBGHELP)
target_link_libraries (glog PRIVATE Threads::Threads)
if (HAVE_PTHREAD)
target_link_libraries (glog PRIVATE Threads::Threads)
if (CMAKE_THREAD_LIBS_INIT)
set (Threads_DEPENDENCY "find_dependency (Threads)")
if (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)
# Prefer the gflags target that uses double colon convention
@ -467,7 +516,7 @@ if (ANDROID)
endif (ANDROID)
set_target_properties (glog PROPERTIES VERSION ${glog_VERSION})
set_target_properties (glog PROPERTIES SOVERSION 3)
set_target_properties (glog PROPERTIES SOVERSION 1)
if (CYGWIN OR WIN32)
target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)
@ -584,13 +633,6 @@ if (BUILD_TESTING)
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)
add_executable (stacktrace_unittest
src/stacktrace_unittest.cc
@ -613,6 +655,7 @@ if (BUILD_TESTING)
target_link_libraries (signalhandler_unittest PRIVATE glog_test)
endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
add_test (NAME demangle COMMAND demangle_unittest)
add_test (NAME logging COMMAND logging_unittest)
set_tests_properties (logging PROPERTIES TIMEOUT 30)
@ -795,188 +838,21 @@ if (BUILD_TESTING)
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)
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
EXPORT glog-targets
RUNTIME DESTINATION ${_glog_CMake_BINDIR}
PUBLIC_HEADER DESTINATION ${_glog_CMake_INCLUDE_DIR}/glog
LIBRARY DESTINATION ${_glog_CMake_LIBDIR}
ARCHIVE DESTINATION ${_glog_CMake_LIBDIR})
RUNTIME DESTINATION ${_glog_CMake_BINDIR} COMPONENT Runtime
PUBLIC_HEADER DESTINATION ${_glog_CMake_INCLUDE_DIR}/glog COMPONENT Development
LIBRARY DESTINATION ${_glog_CMake_LIBDIR} COMPONENT Runtime
ARCHIVE DESTINATION ${_glog_CMake_LIBDIR} COMPONENT Development
)
if (WITH_PKGCONFIG)
install (
FILES "${glog_BINARY_DIR}/libglog.pc"
DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig"
COMPONENT Development
)
endif (WITH_PKGCONFIG)
@ -1046,7 +922,9 @@ file (INSTALL
install (FILES
${glog_BINARY_DIR}/glog-config.cmake
${glog_BINARY_DIR}/glog-config-version.cmake
DESTINATION ${_glog_CMake_INSTALLDIR})
DESTINATION ${_glog_CMake_INSTALLDIR}
COMPONENT Development
)
# Find modules in share/glog/cmake
install (DIRECTORY ${_glog_BINARY_CMake_DATADIR}
@ -1055,5 +933,20 @@ install (DIRECTORY ${_glog_BINARY_CMake_DATADIR}
FILES_MATCHING PATTERN "*.cmake"
)
install (EXPORT glog-targets NAMESPACE glog:: DESTINATION
${_glog_CMake_INSTALLDIR})
install (EXPORT glog-targets NAMESPACE glog::
DESTINATION ${_glog_CMake_INSTALLDIR}
COMPONENT Development
)
set (CPACK_DEB_COMPONENT_INSTALL ON)
set (CPACK_DEBIAN_DEVELOPMENT_PACKAGE_NAME libgoogle-glog-dev)
set (CPACK_DEBIAN_ENABLE_COMPONENT_DEPENDS ON)
set (CPACK_DEBIAN_FILE_NAME DEB-DEFAULT)
set (CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set (CPACK_DEBIAN_RUNTIME_PACKAGE_NAME libgoogle-glog)
set (CPACK_PACKAGE_NAME google-glog)
include (CPack)
cpack_add_component (Runtime)
cpack_add_component (Development DEPENDS Runtime)

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>
* 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,879 @@ 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.
.. role:: cmake(code)
:language: cmake
.. role:: cmd(code)
:language: bash
.. role:: cpp(code)
:language: cpp
.. role:: bazel(code)
:language: starlark
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";
DLOG_FIRST_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
DLOG_EVERY_T(INFO, 0.01) << "Got a 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

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"],
deps = [
"//: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() != "@":
repo_name = native.repository_name()[1:] # Strip the first leading @
gendir = "$(GENDIR)/external/" + repo_name
@ -48,8 +54,12 @@ def glog_library(with_gflags = 1, **kwargs):
common_copts = [
"-std=c++14",
"-DGLOG_BAZEL_BUILD",
# Inject a C++ namespace.
"-DGOOGLE_NAMESPACE='%s'" % namespace,
"-DHAVE_STRING_H",
"-I%s/glog_internal" % gendir,
] + (["-DGLOG_USE_GFLAGS"] if with_gflags else [])
] + (["-DHAVE_LIB_GFLAGS"] if with_gflags else [])
wasm_copts = [
# Disable warnings that exists in glog.
@ -57,32 +67,27 @@ def glog_library(with_gflags = 1, **kwargs):
"-Wno-unused-function",
"-Wno-unused-local-typedefs",
"-Wno-unused-variable",
# Allows src/base/mutex.h to include pthread.h.
"-DHAVE_PTHREAD",
# Allows src/logging.cc to determine the host name.
"-DHAVE_SYS_UTSNAME_H",
# For src/utilities.cc.
"-DHAVE_SYS_TIME_H",
# NOTE: users could optionally patch -DHAVE_UNWIND off if
# stacktrace dumping is not needed
"-DHAVE_UNWIND",
"-DHAVE__UNWIND_BACKTRACE",
"-DHAVE__UNWIND_GETIP",
# Enable dumping stacktrace upon sigaction.
"-DHAVE_SIGACTION",
# For logging.cc.
"-DHAVE_PREAD",
# -DHAVE_MODE_T prevent repeated typedef mode_t leading
# to emcc compilation failure
"-DHAVE_MODE_T",
"-DHAVE_UNISTD_H",
"-DHAVE___ATTRIBUTE__",
]
linux_or_darwin_copts = wasm_copts + [
"-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.
"-DHAVE_SYS_SYSCALL_H",
# For src/logging.cc to create symlinks.
"-DHAVE_UNISTD_H",
"-fvisibility-inlines-hidden",
"-fvisibility=hidden",
]
@ -90,30 +95,25 @@ def glog_library(with_gflags = 1, **kwargs):
freebsd_only_copts = [
# Enable declaration of _Unwind_Backtrace
"-D_GNU_SOURCE",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
]
linux_only_copts = [
# For utilities.h.
"-DHAVE_EXECINFO_H",
"-DHAVE_LINK_H",
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
]
darwin_only_copts = [
# For stacktrace.
"-DHAVE_DLADDR",
# Avoid deprecated syscall().
"-DHAVE_PTHREAD_THREADID_NP",
]
windows_only_copts = [
# Override -DGLOG_EXPORT= from the cc_library's defines.
"-DGLOG_EXPORT=__declspec(dllexport)",
"-DGLOG_NO_ABBREVIATED_SEVERITIES",
"-DGLOG_NO_EXPORT=",
"-DGLOG_USE_WINDOWS_PORT",
"-DHAVE__CHSIZE_S",
"-DHAVE_DBGHELP",
"-I" + src_windows,
]
@ -123,26 +123,25 @@ def glog_library(with_gflags = 1, **kwargs):
]
windows_only_srcs = [
"src/glog/log_severity.h",
"src/windows/dirent.h",
"src/windows/port.cc",
"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({
# GLOG_EXPORT is normally set by export.h, but that's not
# generated for Bazel.
"@bazel_tools//src/conditions:windows": [
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_EXPORT=",
"GLOG_DEPRECATED=__declspec(deprecated)",
"GLOG_NO_ABBREVIATED_SEVERITIES",
"GLOG_NO_EXPORT=",
],
"//conditions:default": [
"GLOG_DEPRECATED=__attribute__((deprecated))",
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
"GLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
],
})
@ -162,6 +161,7 @@ def glog_library(with_gflags = 1, **kwargs):
name = "shared_headers",
srcs = [
"src/base/commandlineflags.h",
"src/base/mutex.h",
"src/stacktrace.h",
"src/utilities.h",
]
@ -176,12 +176,9 @@ def glog_library(with_gflags = 1, **kwargs):
"src/base/googleinit.h",
"src/demangle.cc",
"src/demangle.h",
"src/flags.cc",
"src/logging.cc",
"src/raw_logging.cc",
"src/signalhandler.cc",
"src/stacktrace.cc",
"src/stacktrace.h",
"src/stacktrace_generic-inl.h",
"src/stacktrace_libunwind-inl.h",
"src/stacktrace_powerpc-inl.h",
@ -191,21 +188,18 @@ def glog_library(with_gflags = 1, **kwargs):
"src/symbolize.cc",
"src/symbolize.h",
"src/utilities.cc",
"src/utilities.h",
"src/vlog_is_on.cc",
] + select({
"@bazel_tools//src/conditions:windows": windows_only_srcs,
"//conditions:default": [],
}),
hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h",
"src/glog/logging.h",
"src/glog/platform.h",
"src/glog/raw_logging.h",
"src/glog/stl_logging.h",
"src/glog/types.h",
"src/glog/vlog_is_on.h",
":logging_h",
":raw_logging_h",
":stl_logging_h",
":vlog_is_on_h",
],
# https://github.com/google/glog/issues/837: Replacing
# `strip_include_prefix` with `includes` would avoid spamming
@ -222,10 +216,6 @@ def glog_library(with_gflags = 1, **kwargs):
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
"//conditions:default": [],
}),
linkopts = select({
"@bazel_tools//src/conditions:windows": ["dbghelp.lib"],
"//conditions:default": [],
}),
**kwargs
)
@ -261,7 +251,7 @@ def glog_library(with_gflags = 1, **kwargs):
copts = final_lib_copts + test_only_copts,
deps = gflags_deps + [
":glog",
"@googletest//:gtest",
"@com_github_google_googletest//:gtest",
],
**kwargs
)
@ -271,14 +261,11 @@ def glog_library(with_gflags = 1, **kwargs):
native.cc_library(
name = "strip_include_prefix_hack",
hdrs = [
"src/glog/flags.h",
"src/glog/log_severity.h",
"src/glog/logging.h",
"src/glog/platform.h",
"src/glog/raw_logging.h",
"src/glog/stl_logging.h",
"src/glog/types.h",
"src/glog/vlog_is_on.h",
":logging_h",
":raw_logging_h",
":stl_logging_h",
":vlog_is_on_h",
],
)
@ -288,3 +275,51 @@ def glog_library(with_gflags = 1, **kwargs):
out = "glog_internal/config.h",
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)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
list (LENGTH LOG_FILES NUM_FILES)
if (WIN32)
# On Windows open files cannot be removed and will result in a permission
# denied error while unlinking such file. Therefore, the last file will be
# 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)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@ -7,20 +7,16 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
list (LENGTH LOG_FILES NUM_FILES)
if (WIN32)
# On Windows open files cannot be removed and will result in a permission
# denied error while unlinking such file. Therefore, the last file will be
# 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)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)

View File

@ -10,23 +10,19 @@ foreach (iter RANGE 1 ${RUNS})
if (NOT _RESULT EQUAL 0)
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
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)
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
list (LENGTH LOG_FILES NUM_FILES)
if (WIN32)
# On Windows open files cannot be removed and will result in a permission
# denied error while unlinking such file. Therefore, the last file will be
# 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)
if (NOT NUM_FILES EQUAL 1)
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
endif (NOT NUM_FILES EQUAL 1)
# Remove the subdirectory required by this unit test.
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:
- "**/*_unittest.cc"
- "src/*_unittest/**"
- "src/googletest.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/googletest\.h
exclude = src/mock-log\.h
exclude-directories = Tests/
exclude-throw-branches = yes
exclude-unreachable-branches = yes
filter = .*/glog/.*\.h

View File

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

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,26 +48,25 @@
#ifndef BASE_COMMANDLINEFLAGS_H__
#define BASE_COMMANDLINEFLAGS_H__
#include "config.h"
#include <cstdlib> // for getenv
#include <cstring> // for memchr
#include <string>
#include "config.h"
#ifdef HAVE_LIB_GFLAGS
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#include <gflags/gflags.h>
#else
# include "glog/logging.h"
#include "glog/logging.h"
# define DECLARE_VARIABLE(type, shorttype, name, tn) \
#define DECLARE_VARIABLE(type, shorttype, name, tn) \
namespace fL##shorttype { \
extern GLOG_EXPORT type FLAGS_##name; \
} \
using fL##shorttype::FLAGS_##name
# define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
#define DEFINE_VARIABLE(type, shorttype, name, value, meaning, tn) \
namespace fL##shorttype { \
GLOG_EXPORT type FLAGS_##name(value); \
char FLAGS_no##name; \
@ -75,31 +74,33 @@
using fL##shorttype::FLAGS_##name
// bool specialization
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
# define DEFINE_bool(name, value, meaning) \
#define DECLARE_bool(name) \
DECLARE_VARIABLE(bool, B, name, bool)
#define DEFINE_bool(name, value, meaning) \
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
// int32 specialization
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
# define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)
#define DECLARE_int32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
#define DEFINE_int32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
// uint32 specialization
# ifndef DECLARE_uint32
# define DECLARE_uint32(name) \
DECLARE_VARIABLE(google::uint32, U, name, uint32)
# endif // DECLARE_uint64
# define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
#ifndef DECLARE_uint32
#define DECLARE_uint32(name) \
DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32)
#endif // DECLARE_uint64
#define DEFINE_uint32(name, value, meaning) \
DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32)
// 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) \
#define DECLARE_string(name) \
namespace fLS { \
extern GLOG_EXPORT std::string& FLAGS_##name; \
} \
using fLS::FLAGS_##name
# define DEFINE_string(name, value, meaning) \
#define DEFINE_string(name, value, meaning) \
namespace fLS { \
std::string FLAGS_##name##_buf(value); \
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
@ -107,7 +108,7 @@
} \
using fLS::FLAGS_##name
#endif // GLOG_USE_GFLAGS
#endif // HAVE_LIB_GFLAGS
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
// 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
// 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) \
(!getenv(envname) ? (dflt) \

View File

@ -36,14 +36,16 @@
class GoogleInitializer {
public:
using void_function = void (*)();
GoogleInitializer(const char*, void_function f) { f(); }
GoogleInitializer(const char*, void_function f) {
f();
}
};
#define REGISTER_MODULE_INITIALIZER(name, body) \
namespace { \
static void google_init_module_##name() { body; } \
GoogleInitializer google_initializer_module_##name( \
#name, google_init_module_##name); \
static void google_init_module_##name () { body; } \
GoogleInitializer google_initializer_module_##name(#name, \
google_init_module_##name); \
}
#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.
//
// Redistribution and use in source and binary forms, with or without
@ -32,17 +32,17 @@
#include "glog/raw_logging.h"
#include "googletest.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
# include <gmock/gmock.h>
#include <gmock/gmock.h>
# include "mock-log.h"
#include "mock-log.h"
// Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
@ -52,12 +52,11 @@ using testing::StrictMock;
using testing::StrNe;
#endif
using namespace google;
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediately, logging) {
using namespace std::chrono_literals;
google::SetLogFilenameExtension(".foobar");
google::EnableLogCleaner(0h);
google::EnableLogCleaner(0);
for (unsigned i = 0; i < 1000; ++i) {
LOG(INFO) << "cleanup test";
@ -66,10 +65,10 @@ TEST(CleanImmediately, logging) {
google::DisableLogCleaner();
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// 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.
//
// Redistribution and use in source and binary forms, with or without
@ -32,17 +32,17 @@
#include "glog/raw_logging.h"
#include "googletest.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
# include <gmock/gmock.h>
#include <gmock/gmock.h>
# include "mock-log.h"
#include "mock-log.h"
// Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
@ -52,11 +52,10 @@ using testing::StrictMock;
using testing::StrNe;
#endif
using namespace google;
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
using namespace std::chrono_literals;
google::EnableLogCleaner(0h);
google::EnableLogCleaner(0);
google::SetLogFilenameExtension(".barfoo");
google::SetLogDestination(GLOG_INFO, "test_cleanup_");
@ -71,10 +70,10 @@ TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
google::DisableLogCleaner();
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// 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.
//
// Redistribution and use in source and binary forms, with or without
@ -32,17 +32,17 @@
#include "glog/raw_logging.h"
#include "googletest.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#ifdef HAVE_LIB_GMOCK
# include <gmock/gmock.h>
#include <gmock/gmock.h>
# include "mock-log.h"
#include "mock-log.h"
// Introduce several symbols from gmock.
using google::glog_testing::ScopedMockLog;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using testing::_;
using testing::AllOf;
using testing::AnyNumber;
@ -52,11 +52,10 @@ using testing::StrictMock;
using testing::StrNe;
#endif
using namespace google;
using namespace GOOGLE_NAMESPACE;
TEST(CleanImmediatelyWithRelativePrefix, logging) {
using namespace std::chrono_literals;
google::EnableLogCleaner(0h);
google::EnableLogCleaner(0);
google::SetLogFilenameExtension(".relativefoo");
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
@ -67,10 +66,10 @@ TEST(CleanImmediatelyWithRelativePrefix, logging) {
google::DisableLogCleaner();
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
FLAGS_colorlogtostderr = false;
FLAGS_timestamp_in_logfile_name = true;
#ifdef GLOG_USE_GFLAGS
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
// Make sure stderr is not buffered as stderr seems to be buffered

View File

@ -1,6 +1,9 @@
#ifndef GLOG_CONFIG_H
#define GLOG_CONFIG_H
/* Namespace for Google classes */
#cmakedefine GOOGLE_NAMESPACE ${GOOGLE_NAMESPACE}
/* Define if you have the `dladdr' function */
#cmakedefine HAVE_DLADDR
@ -19,6 +22,12 @@
/* Define to 1 if you have the <glob.h> header file. */
#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 */
#cmakedefine HAVE_LIB_GMOCK
@ -28,11 +37,20 @@
/* define if you have dbghelp library */
#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 */
#cmakedefine HAVE_PREAD
/* Define if you have the 'posix_fadvise' function in <fcntl.h> */
#cmakedefine HAVE_POSIX_FADVISE
/* Define if you have POSIX threads libraries and header files. */
#cmakedefine HAVE_PTHREAD
/* Define to 1 if you have the <pwd.h> header file. */
#cmakedefine HAVE_PWD_H
@ -40,26 +58,26 @@
/* Define if you have the 'pwrite' function */
#cmakedefine HAVE_PWRITE
/* define if the compiler implements pthread_rwlock_* */
#cmakedefine HAVE_RWLOCK
/* Define if you have the 'sigaction' function */
#cmakedefine HAVE_SIGACTION
/* Define if you have the `sigaltstack' function */
#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. */
#cmakedefine HAVE_SYSCALL_H
/* Define to 1 if you have the <syslog.h> header file. */
#cmakedefine HAVE_SYSLOG_H
/* Define to 1 if you have the <elf.h> header file. */
#cmakedefine HAVE_ELF_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/stat.h> header file. */
#cmakedefine HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/syscall.h> header file. */
#cmakedefine HAVE_SYS_SYSCALL_H
@ -68,7 +86,7 @@
#cmakedefine HAVE_SYS_TIME_H
/* 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. */
#cmakedefine HAVE_SYS_UCONTEXT_H
@ -85,11 +103,20 @@
/* Define to 1 if you have the <unistd.h> header file. */
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
/* define if you have unwind */
#cmakedefine HAVE_UNWIND
/* Define if you linking to _Unwind_Backtrace is possible. */
#cmakedefine HAVE__UNWIND_BACKTRACE
/* define if you have libunwind */
#cmakedefine HAVE_LIBUNWIND
/* Define if you linking to _Unwind_GetIP is possible. */
#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 */
#cmakedefine HAVE_SYMBOLIZE
@ -103,11 +130,9 @@
/* define if _chsize_s is available in io.h */
#cmakedefine HAVE__CHSIZE_S
/* define if ssize_t is defined */
#cmakedefine HAVE_SSIZE_T
/* define if mode_t is defined */
#cmakedefine HAVE_MODE_T
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#cmakedefine LT_OBJDIR
/* How to access the PC from a struct ucontext */
#cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}
@ -115,6 +140,10 @@
/* define if we should print file offsets in traces instead of symbolizing. */
#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. */
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
@ -124,19 +153,25 @@
/* Define if thread-local storage is enabled. */
#cmakedefine GLOG_THREAD_LOCAL_STORAGE
/* define if abi::__cxa_demangle is available in cxxabi.h */
#cmakedefine HAVE___CXA_DEMANGLE
#ifdef GLOG_BAZEL_BUILD
/* define if __argv is available in cstdlib */
#cmakedefine HAVE___ARGV
/* TODO(rodrigoq): remove this workaround once bazel#3979 is resolved:
* https://github.com/bazelbuild/bazel/issues/3979 */
#define _START_GOOGLE_NAMESPACE_ namespace GOOGLE_NAMESPACE {
/* define if __progname is available */
#cmakedefine HAVE___PROGNAME
#define _END_GOOGLE_NAMESPACE_ }
/* define if getprogname is available in cstdlib */
#cmakedefine HAVE_GETPROGNAME
#else
/* define if program_invocation_short_name is available in cerrno */
#cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME
/* Stops putting the code inside the Google namespace */
#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

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";
}

File diff suppressed because it is too large Load Diff

View File

@ -67,28 +67,19 @@
// C++ ABI in the future.
//
#ifndef GLOG_INTERNAL_DEMANGLE_H
#define GLOG_INTERNAL_DEMANGLE_H
#ifndef BASE_DEMANGLE_H_
#define BASE_DEMANGLE_H_
#include <cstddef>
#include "config.h"
#include "glog/logging.h"
#if defined(GLOG_USE_GLOG_EXPORT)
# 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_ {
_START_GOOGLE_NAMESPACE_
// Demangle "mangled". On success, return true and write the
// demangled symbol name to "out". Otherwise, return false.
// "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_
} // namespace google
_END_GOOGLE_NAMESPACE_
#endif // GLOG_INTERNAL_DEMANGLE_H
#endif // BASE_DEMANGLE_H_

View File

@ -42,8 +42,8 @@
#include "googletest.h"
#include "utilities.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
@ -51,10 +51,10 @@ GLOG_DEFINE_bool(demangle_filter, false,
"Run demangle_unittest in filter mode");
using namespace std;
using namespace google;
using namespace GOOGLE_NAMESPACE;
// 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) {
static char demangled[4096];
if (Demangle(mangled, demangled, sizeof(demangled))) {
return demangled;
@ -65,25 +65,28 @@ static const char* DemangleIt(const char* const mangled) {
#if defined(GLOG_OS_WINDOWS)
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
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"));
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)"));
EXPECT_STREQ("int __cdecl foobarArray(int * const)",
EXPECT_STREQ(
"int __cdecl foobarArray(int * const)",
DemangleIt("?foobarArray@@YAHQAH@Z"));
}
# endif
#endif
#else
// Test corner cases of boundary conditions.
TEST(Demangle, CornerCases) {
const size_t size = 10;
char tmp[size] = {0};
const char* demangled = "foobar()";
const char* mangled = "_Z6foobarv";
char tmp[size] = { 0 };
const char *demangled = "foobar()";
const char *mangled = "_Z6foobarv";
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
// sizeof("foobar()") == size - 1
EXPECT_STREQ(demangled, tmp);
@ -144,11 +147,11 @@ TEST(Demangle, FromFile) {
#endif
int main(int argc, char** argv) {
InitGoogleTest(&argc, argv);
#ifdef GLOG_USE_GFLAGS
int main(int argc, char **argv) {
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
#endif
InitGoogleTest(&argc, argv);
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);

View File

@ -143,10 +143,3 @@ _Zrm1XS_ operator%()
# Template argument packs can start with I or J.
_Z3addIIiEEvDpT_ 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

@ -18,7 +18,7 @@
#include "demangle.h"
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* Data,
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data,
unsigned Size) {
if (Size >= 4095) {
return 0;

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.
//
// Redistribution and use in source and binary forms, with or without
@ -30,16 +30,6 @@
#ifndef 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:
//
// INFO:
@ -58,43 +48,27 @@ namespace google {
// Variables of type LogSeverity are widely taken to lie in the range
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
// you ever need to change their values or add a new severity.
using LogSeverity = int;
enum LogSeverity {
GLOG_INFO = 0,
GLOG_WARNING = 1,
GLOG_ERROR = 2,
GLOG_FATAL = 3,
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
NUM_SEVERITIES = 4;
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
# ifdef ERROR
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
# endif
INFO = GLOG_INFO,
WARNING = GLOG_WARNING,
ERROR = GLOG_ERROR,
FATAL = GLOG_FATAL
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
#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
#ifdef NDEBUG
# define DFATAL_LEVEL ERROR
#define DFATAL_LEVEL ERROR
#else
# define DFATAL_LEVEL FATAL
#define DFATAL_LEVEL FATAL
#endif
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
// NDEBUG usage helpers related to (RAW_)DCHECK:
//
// DEBUG_MODE is for small !NDEBUG uses like
@ -115,12 +89,10 @@ constexpr int NUM_SEVERITIES = 4;
//
#ifdef NDEBUG
enum { DEBUG_MODE = 0 };
# define IF_DEBUG_MODE(x)
#define IF_DEBUG_MODE(x)
#else
enum { DEBUG_MODE = 1 };
# define IF_DEBUG_MODE(x) x
#define IF_DEBUG_MODE(x) x
#endif
} // namespace google
#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.
//
// Redistribution and use in source and binary forms, with or without
@ -35,24 +35,23 @@
#define GLOG_PLATFORM_H
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
# define GLOG_OS_WINDOWS
#define GLOG_OS_WINDOWS
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
# define GLOG_OS_CYGWIN
#define GLOG_OS_CYGWIN
#elif defined(linux) || defined(__linux) || defined(__linux__)
# define GLOG_OS_LINUX
# if defined(__ANDROID__)
# define GLOG_OS_ANDROID
# endif
#ifndef GLOG_OS_LINUX
#define GLOG_OS_LINUX
#endif
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
# define GLOG_OS_MACOSX
#define GLOG_OS_MACOSX
#elif defined(__FreeBSD__)
# define GLOG_OS_FREEBSD
#define GLOG_OS_FREEBSD
#elif defined(__NetBSD__)
# define GLOG_OS_NETBSD
#define GLOG_OS_NETBSD
#elif defined(__OpenBSD__)
# define GLOG_OS_OPENBSD
#define GLOG_OS_OPENBSD
#elif defined(__EMSCRIPTEN__)
# define GLOG_OS_EMSCRIPTEN
#define GLOG_OS_EMSCRIPTEN
#else
// TODO(hamaji): Add other platforms.
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc.
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -36,18 +36,17 @@
#ifndef GLOG_RAW_LOGGING_H
#define GLOG_RAW_LOGGING_H
#if defined(GLOG_USE_GLOG_EXPORT)
# 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
#include <ctime>
@ac_google_start_namespace@
#include "glog/log_severity.h"
#include "glog/logging.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..,
// but
@ -65,7 +64,7 @@ namespace google {
// I20200821 211317 file.cc:142] RAW: status is 20
#define RAW_LOG(severity, ...) \
do { \
switch (google::GLOG_##severity) { \
switch (@ac_google_namespace@::GLOG_ ## severity) { \
case 0: \
RAW_LOG_INFO(__VA_ARGS__); \
break; \
@ -86,44 +85,44 @@ namespace google {
// The following STRIP_LOG testing is performed in the header file so that it's
// possible to completely compile out the logging code and the log messages.
#if !defined(STRIP_LOG) || STRIP_LOG == 0
# define RAW_VLOG(verboselevel, ...) \
#define RAW_VLOG(verboselevel, ...) \
do { \
if (VLOG_IS_ON(verboselevel)) { \
RAW_LOG_INFO(__VA_ARGS__); \
} \
} while (0)
#else
# define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
#endif // STRIP_LOG == 0
#if !defined(STRIP_LOG) || STRIP_LOG == 0
# define RAW_LOG_INFO(...) \
google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \
__FILE__, __LINE__, __VA_ARGS__)
#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
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
# define RAW_LOG_WARNING(...) \
google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \
__FILE__, __LINE__, __VA_ARGS__)
#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
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
# define RAW_LOG_ERROR(...) \
google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \
__FILE__, __LINE__, __VA_ARGS__)
#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
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
# define RAW_LOG_FATAL(...) \
google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \
__FILE__, __LINE__, __VA_ARGS__)
#else
# define RAW_LOG_FATAL(...) \
#define RAW_LOG_FATAL(...) \
do { \
google::RawLogStub__(0, __VA_ARGS__); \
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#endif // STRIP_LOG <= 3
@ -143,21 +142,28 @@ namespace google {
// Debug versions of RAW_LOG and RAW_CHECK
#ifndef NDEBUG
# define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
# define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
#else // NDEBUG
# define RAW_DLOG(severity, ...) \
while (false) RAW_LOG(severity, __VA_ARGS__)
# define RAW_DCHECK(condition, message) \
while (false) RAW_CHECK(condition, message)
#define RAW_DLOG(severity, ...) \
while (false) \
RAW_LOG(severity, __VA_ARGS__)
#define RAW_DCHECK(condition, message) \
while (false) \
RAW_CHECK(condition, message)
#endif // NDEBUG
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
// Stub log function used to work around for unused variable warnings when
// 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
// 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.
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
const char* format, ...)
#if defined(__has_attribute)
# if __has_attribute(used)
__attribute__((__format__(__printf__, 4, 5)))
# endif
#endif
;
} // namespace google
@ac_cv___attribute___printf_4_5@;
@ac_google_end_namespace@
#endif // GLOG_RAW_LOGGING_H

View File

@ -36,8 +36,8 @@
// CHECK_EQ(v1, v2);
//
#ifndef GLOG_STL_LOGGING_H
#define GLOG_STL_LOGGING_H
#ifndef UTIL_GTL_STL_LOGGING_INL_H_
#define UTIL_GTL_STL_LOGGING_INL_H_
#include <deque>
#include <list>
@ -52,78 +52,79 @@
// Forward declare these two, and define them after all the container streams
// operators so that we can recurse from pair -> container -> container -> pair
// properly.
template <class First, class Second>
template<class First, class Second>
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);
}
@ac_google_end_namespace@
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
template <class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \
template<class T1, class T2> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
}
OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list)
OUTPUT_TWO_ARG_CONTAINER(std::vector)
OUTPUT_TWO_ARG_CONTAINER(std::deque)
OUTPUT_TWO_ARG_CONTAINER(std::list)
#undef OUTPUT_TWO_ARG_CONTAINER
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
template <class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \
template<class T1, class T2, class T3> \
inline std::ostream& operator<<(std::ostream& out, \
const Sequence<T1, T2, T3>& seq) { \
google::PrintSequence(out, seq.begin(), seq.end()); \
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
return out; \
}
}
OUTPUT_THREE_ARG_CONTAINER(std::set)
OUTPUT_THREE_ARG_CONTAINER(std::multiset)
OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(
std::multiset)
#undef OUTPUT_THREE_ARG_CONTAINER
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
template <class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \
template<class T1, class T2, class T3, class T4> \
inline std::ostream& operator<<(std::ostream& out, \
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; \
}
}
OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(
std::multimap) OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)
OUTPUT_FOUR_ARG_CONTAINER(std::map)
OUTPUT_FOUR_ARG_CONTAINER(std::multimap)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_set)
OUTPUT_FOUR_ARG_CONTAINER(std::unordered_multiset)
#undef OUTPUT_FOUR_ARG_CONTAINER
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
template <class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \
template<class T1, class T2, class T3, class T4, class T5> \
inline std::ostream& operator<<(std::ostream& out, \
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; \
}
}
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
#undef OUTPUT_FIVE_ARG_CONTAINER
template <class First, class Second>
inline std::ostream& operator<<(std::ostream& out,
template <class First, class Second>
inline std::ostream& operator<<(
std::ostream& out,
const std::pair<First, Second>& p) {
out << '(' << p.first << ", " << p.second << ')';
return out;
}
namespace google {
@ac_google_start_namespace@
template <class Iter>
template<class Iter>
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
// Output at most 100 elements -- appropriate if used for logging.
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
@ -135,7 +136,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
// the std namespace for a reason though -- we are providing new operations on
@ -161,8 +162,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
// 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.
namespace std {
using ::operator<<;
}
namespace std { 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.
//
// 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.
//
#ifndef GLOG_VLOG_IS_ON_H
#define GLOG_VLOG_IS_ON_H
#ifndef BASE_VLOG_IS_ON_H_
#define BASE_VLOG_IS_ON_H_
#include <cstddef>
#if defined(GLOG_USE_GLOG_EXPORT)
# 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"
#include "glog/log_severity.h"
#if defined(__GNUC__)
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
@ -81,25 +72,21 @@
// it's either FLAGS_v or an appropriate internal variable
// matching the current source file that represents results of
// parsing of --vmodule flag and/or SetVLOGLevel calls.
# define VLOG_IS_ON(verboselevel) \
__extension__({ \
static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
google::int32 verbose_level__ = (verboselevel); \
(vlocal__.level == nullptr \
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \
verbose_level__) \
: *vlocal__.level >= verbose_level__); \
#define VLOG_IS_ON(verboselevel) \
__extension__ \
({ static @ac_google_namespace@::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
GLOG_IFDEF_THREAD_SANITIZER( \
AnnotateBenignRaceSized(__FILE__, __LINE__, &vlocal__, sizeof(@ac_google_namespace@::SiteFlag), "")); \
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
(vlocal__.level == nullptr ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
__FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \
})
#else
// GNU extensions not available, so we do not support --vmodule.
// Dynamic value of FLAGS_v always controls the logging level.
# define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#define VLOG_IS_ON(verboselevel) (FLAGS_v >= (verboselevel))
#endif
namespace google {
// Set VLOG(_IS_ON) level for module_pattern to log_level.
// This lets us dynamically control what is normally set by the --vmodule flag.
// 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: =========================
struct SiteFlag {
int32* level;
@ac_google_namespace@::int32* level;
const char* base_name;
std::size_t base_len;
SiteFlag* next;
@ -127,10 +114,9 @@ struct SiteFlag {
// verbose_level is the argument to VLOG_IS_ON
// We will return the return value for VLOG_IS_ON
// and if possible set *site_flag appropriately.
extern GLOG_EXPORT bool InitVLOG3__(SiteFlag* site_flag,
int32* site_default,
const char* fname,
int32 verbose_level);
} // namespace google
extern GLOG_EXPORT bool InitVLOG3__(
@ac_google_namespace@::SiteFlag* site_flag,
@ac_google_namespace@::int32* site_default, const char* fname,
@ac_google_namespace@::int32 verbose_level);
#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.
//
// Redistribution and use in source and binary forms, with or without
@ -31,7 +31,7 @@
// (based on googletest: http://code.google.com/p/googletest/)
#ifdef GOOGLETEST_H__
# error You must not include this file twice.
#error You must not include this file twice.
#endif
#define GOOGLETEST_H__
@ -51,40 +51,35 @@
#include <utility>
#include <vector>
#include "config.h"
#include "utilities.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(GLOG_USE_WINDOWS_PORT)
# include "port.h"
#endif // defined(GLOG_USE_WINDOWS_PORT)
#include "base/commandlineflags.h"
#include "utilities.h"
#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)
#else
# define GOOGLE_GLOG_THROW_BAD_ALLOC
#define GOOGLE_GLOG_THROW_BAD_ALLOC
#endif
using std::map;
using std::string;
using std::vector;
namespace google {
extern void (*g_logging_fail_func)();
extern void GetExistingTempDirectories(std::vector<std::string>& list);
extern int posix_strerror_r(int err, char* buf, size_t len);
extern std::string StrError(int err);
} // namespace google
_START_GOOGLE_NAMESPACE_
extern GLOG_EXPORT void (*g_logging_fail_func)();
_END_GOOGLE_NAMESPACE_
#undef GLOG_EXPORT
#define GLOG_EXPORT
static inline string GetTempDir() {
vector<string> temp_directories_list;
google::GetExistingTempDirectories(temp_directories_list);
google::GetExistingTempDirectories(&temp_directories_list);
if (temp_directories_list.empty()) {
fprintf(stderr, "No temporary directory found\n");
@ -124,7 +119,7 @@ DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
using testing::InitGoogleTest;
#else
namespace google {
_START_GOOGLE_NAMESPACE_
void InitGoogleTest(int*, char**);
@ -132,16 +127,16 @@ void InitGoogleTest(int*, char**) {}
// The following is some bare-bones testing infrastructure
# define EXPECT_NEAR(val1, val2, abs_error) \
#define EXPECT_NEAR(val1, val2, abs_error) \
do { \
if (abs(val1 - val2) > abs_error) { \
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \
#abs_error, #val2); \
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
#val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
# define EXPECT_TRUE(cond) \
#define EXPECT_TRUE(cond) \
do { \
if (!(cond)) { \
fprintf(stderr, "Check failed: %s\n", #cond); \
@ -149,22 +144,22 @@ void InitGoogleTest(int*, char**) {}
} \
} while (0)
# define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
#define EXPECT_FALSE(cond) EXPECT_TRUE(!(cond))
# define EXPECT_OP(op, val1, val2) \
#define EXPECT_OP(op, val1, val2) \
do { \
if (!((val1)op(val2))) { \
if (!((val1) op (val2))) { \
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
# define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
# define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
# define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
# define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
#define EXPECT_EQ(val1, val2) EXPECT_OP(==, val1, val2)
#define EXPECT_NE(val1, val2) EXPECT_OP(!=, val1, val2)
#define EXPECT_GT(val1, val2) EXPECT_OP(>, val1, val2)
#define EXPECT_LT(val1, val2) EXPECT_OP(<, val1, val2)
# define EXPECT_NAN(arg) \
#define EXPECT_NAN(arg) \
do { \
if (!isnan(arg)) { \
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
@ -172,7 +167,7 @@ void InitGoogleTest(int*, char**) {}
} \
} while (0)
# define EXPECT_INF(arg) \
#define EXPECT_INF(arg) \
do { \
if (!isinf(arg)) { \
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
@ -180,15 +175,15 @@ void InitGoogleTest(int*, char**) {}
} \
} while (0)
# define EXPECT_DOUBLE_EQ(val1, val2) \
#define EXPECT_DOUBLE_EQ(val1, val2) \
do { \
if (((val1) < (val2)-0.001 || (val1) > (val2) + 0.001)) { \
if (((val1) < (val2) - 0.001 || (val1) > (val2) + 0.001)) { \
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
exit(EXIT_FAILURE); \
} \
} while (0)
# define EXPECT_STREQ(val1, val2) \
#define EXPECT_STREQ(val1, val2) \
do { \
if (strcmp((val1), (val2)) != 0) { \
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
@ -196,31 +191,18 @@ void InitGoogleTest(int*, char**) {}
} \
} 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
# define TEST(a, b) \
#define TEST(a, b) \
struct Test_##a##_##b { \
Test_##a##_##b() { g_testlist.push_back(&Run); } \
static void Run() { \
FlagSaver fs; \
RunTest(); \
} \
static void Run() { FlagSaver fs; RunTest(); } \
static void RunTest(); \
}; \
static Test_##a##_##b g_test_##a##_##b; \
void Test_##a##_##b::RunTest()
static inline int RUN_ALL_TESTS() {
vector<void (*)()>::const_iterator it;
for (it = g_testlist.begin(); it != g_testlist.end(); ++it) {
@ -231,11 +213,11 @@ static inline int RUN_ALL_TESTS() {
return 0;
}
} // namespace google
_END_GOOGLE_NAMESPACE_
#endif // ! HAVE_LIB_GTEST
namespace google {
_START_GOOGLE_NAMESPACE_
static bool g_called_abort;
static jmp_buf g_jmp_buf;
@ -246,9 +228,9 @@ static inline void CalledAbort() {
#ifdef GLOG_OS_WINDOWS
// TODO(hamaji): Death test somehow doesn't work in Windows.
# define ASSERT_DEATH(fn, msg)
#define ASSERT_DEATH(fn, msg)
#else
# define ASSERT_DEATH(fn, msg) \
#define ASSERT_DEATH(fn, msg) \
do { \
g_called_abort = false; \
/* in logging.cc */ \
@ -265,14 +247,14 @@ static inline void CalledAbort() {
#endif
#ifdef NDEBUG
# define ASSERT_DEBUG_DEATH(fn, msg)
#define ASSERT_DEBUG_DEATH(fn, msg)
#else
# define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
#endif // NDEBUG
// Benchmark tools.
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_##n(#n, &n);
#define BENCHMARK(n) static BenchmarkRegisterer __benchmark_ ## n (#n, &n);
map<string, void (*)(int)> g_benchlist; // the benchmarks to run
@ -296,13 +278,13 @@ static inline void RunSpecifiedBenchmarks() {
double elapsed_ns = (static_cast<double>(clock()) - start) /
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat="
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat="
#endif
printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
iter_cnt);
#if defined(__GNUC__) && !defined(__clang__)
# pragma GCC diagnostic pop
#pragma GCC diagnostic pop
#endif
}
puts("");
@ -315,69 +297,77 @@ static inline void RunSpecifiedBenchmarks() {
class CapturedStream {
public:
CapturedStream(int fd, string filename)
: fd_(fd), filename_(std::move(filename)) {
: fd_(fd),
filename_(std::move(filename)) {
Capture();
}
~CapturedStream() {
if (uncaptured_fd_ != -1) {
CHECK(close(uncaptured_fd_) != -1);
}
}
// Start redirecting output to a file
void Capture() {
// Keep original stream for later
CHECK(!uncaptured_fd_) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_.reset(dup(fd_));
CHECK(uncaptured_fd_);
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
uncaptured_fd_ = dup(fd_);
CHECK(uncaptured_fd_ != -1);
// Open file to save stream to
FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR)};
CHECK(cap_fd);
int cap_fd = open(filename_.c_str(),
O_CREAT | O_TRUNC | O_WRONLY,
S_IRUSR | S_IWUSR);
CHECK(cap_fd != -1);
// Send stdout/stderr to this file
fflush(nullptr);
CHECK(dup2(cap_fd.get(), fd_) != -1);
CHECK(cap_fd.close() != -1);
CHECK(dup2(cap_fd, fd_) != -1);
CHECK(close(cap_fd) != -1);
}
// Remove output redirection
void StopCapture() {
// Restore original stream
if (uncaptured_fd_) {
if (uncaptured_fd_ != -1) {
fflush(nullptr);
CHECK(dup2(uncaptured_fd_.get(), fd_) != -1);
CHECK(dup2(uncaptured_fd_, fd_) != -1);
}
}
const string& filename() const { return filename_; }
const string & filename() const { return filename_; }
private:
int fd_; // file descriptor being captured
FileDescriptor
uncaptured_fd_; // where the stream was originally being sent to
int uncaptured_fd_{-1}; // where the stream was originally being sent to
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.
// fd - Should be stdout or stderr
// fd - Should be STDOUT_FILENO or STDERR_FILENO
// filename - File where output should be stored
static inline void CaptureTestOutput(int fd, const string& filename) {
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
CHECK(s_captured_streams.find(fd) == s_captured_streams.end());
s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename);
static inline void CaptureTestOutput(int fd, const string & filename) {
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
CHECK(s_captured_streams[fd] == nullptr);
s_captured_streams[fd] = new CapturedStream(fd, filename);
}
static inline void CaptureTestStdout() {
CaptureTestOutput(fileno(stdout), FLAGS_test_tmpdir + "/captured.out");
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
}
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
static inline size_t GetFileSize(FILE* file) {
static inline size_t GetFileSize(FILE * file) {
fseek(file, 0, SEEK_END);
return static_cast<size_t>(ftell(file));
}
// 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);
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_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
// pre-determined file size is reached.
do {
bytes_last_read =
fread(content.data() + bytes_read, 1, file_size - bytes_read, file);
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
bytes_read += bytes_last_read;
} 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) {
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams.at(fd));
s_captured_streams.erase(fd);
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
CapturedStream * const cap = s_captured_streams[fd];
CHECK(cap)
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
// Make sure everything is flushed.
cap->StopCapture();
// Read the captured file.
std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), "r")};
const string content = ReadEntireFile(file.get());
file.reset();
FILE * const file = fopen(cap->filename().c_str(), "r");
const string content = ReadEntireFile(file);
fclose(file);
delete cap;
s_captured_streams[fd] = nullptr;
return content;
}
// Get the captured stderr of a test as a string.
static inline string GetCapturedTestStderr() {
return GetCapturedTestOutput(fileno(stderr));
return GetCapturedTestOutput(STDERR_FILENO);
}
static const std::size_t kLoggingPrefixLength = 9;
@ -425,7 +421,7 @@ static inline bool IsLoggingPrefix(const string& s) {
}
if (!strchr("IWEF", s[0])) return false;
for (size_t i = 1; i <= 8; ++i) {
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i - 1]) return false;
if (!isdigit(s[i]) && s[i] != "YEARDATE"[i-1]) return false;
}
return true;
}
@ -465,14 +461,15 @@ static inline string MungeLine(const string& line) {
}
size_t index = thread_lineinfo.find(':');
CHECK_NE(string::npos, index);
thread_lineinfo = thread_lineinfo.substr(0, index + 1) + "LINE]";
thread_lineinfo = thread_lineinfo.substr(0, index+1) + "LINE]";
string rest;
std::getline(iss, rest);
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
MungeLine(rest));
}
static inline void StringReplace(string* str, const string& oldsub,
static inline void StringReplace(string* str,
const string& oldsub,
const string& newsub) {
size_t pos = str->find(oldsub);
if (pos != string::npos) {
@ -481,11 +478,11 @@ static inline void StringReplace(string* str, const string& oldsub,
}
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";
char buf[4096];
string result;
while (fgets(buf, 4095, fp.get())) {
while (fgets(buf, 4095, fp)) {
string line = MungeLine(buf);
const size_t str_size = 256;
char null_str[str_size];
@ -504,19 +501,19 @@ static inline string Munge(const string& filename) {
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
result += line + "\n";
}
fclose(fp);
return result;
}
static inline void WriteToFile(const string& body, const string& file) {
std::unique_ptr<FILE> fp{fopen(file.c_str(), "wb")};
fwrite(body.data(), 1, body.size(), fp.get());
FILE* fp = fopen(file.c_str(), "wb");
fwrite(body.data(), 1, body.size(), fp);
fclose(fp);
}
static inline bool MungeAndDiffTest(const string& golden_filename,
CapturedStream* cap) {
auto pos = s_captured_streams.find(fileno(stdout));
if (pos != s_captured_streams.end() && cap == pos->second.get()) {
if (cap == s_captured_streams[STDOUT_FILENO]) {
CHECK(cap) << ": did you forget CaptureTestStdout()?";
} else {
CHECK(cap) << ": did you forget CaptureTestStderr()?";
@ -551,17 +548,15 @@ static inline bool MungeAndDiffTest(const string& golden_filename,
}
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
return MungeAndDiffTest(golden_filename,
s_captured_streams.at(fileno(stderr)).get());
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
}
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
return MungeAndDiffTest(golden_filename,
s_captured_streams.at(fileno(stdout)).get());
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
}
// Save flags used from logging_unittest.cc.
#ifndef GLOG_USE_GFLAGS
#ifndef HAVE_LIB_GFLAGS
struct FlagSaver {
FlagSaver()
: v_(FLAGS_v),
@ -584,15 +579,70 @@ struct FlagSaver {
};
#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.
void (*g_new_hook)() = nullptr;
} // namespace google
_END_GOOGLE_NAMESPACE_
void* operator new(size_t size, const std::nothrow_t&) noexcept {
if (google::g_new_hook) {
google::g_new_hook();
if (GOOGLE_NAMESPACE::g_new_hook) {
GOOGLE_NAMESPACE::g_new_hook();
}
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,34 +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/stl_logging.h>
int main() {}

View File

@ -1,34 +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/vlog_is_on.h>
int main() { VLOG_IS_ON(0); }

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

File diff suppressed because it is too large Load Diff

View File

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

View File

@ -33,17 +33,17 @@
#include "mock-log.h"
#include <string>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <string>
namespace {
using google::GLOG_ERROR;
using google::GLOG_INFO;
using google::GLOG_WARNING;
using google::glog_testing::ScopedMockLog;
using GOOGLE_NAMESPACE::GLOG_ERROR;
using GOOGLE_NAMESPACE::GLOG_INFO;
using GOOGLE_NAMESPACE::GLOG_WARNING;
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
using std::string;
using testing::_;
using testing::EndsWith;
@ -57,7 +57,8 @@ TEST(ScopedMockLogTest, InterceptsLog) {
InSequence s;
EXPECT_CALL(log,
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!!"));
LOG(WARNING) << "Fishy.";
@ -66,9 +67,13 @@ TEST(ScopedMockLogTest, InterceptsLog) {
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() {
LOG(INFO) << "Logging the entire forest.";
@ -94,8 +99,8 @@ TEST(ScopedMockLogTest, LogDuringIntercept) {
} // namespace
int main(int argc, char** argv) {
google::InitGoogleLogging(argv[0]);
int main(int argc, char **argv) {
GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]);
testing::InitGoogleTest(&argc, argv);
testing::InitGoogleMock(&argc, argv);

View File

@ -1,3 +1,6 @@
#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.
//
// Redistribution and use in source and binary forms, with or without
@ -31,54 +31,55 @@
//
// logging_unittest.cc covers the functionality herein
#include <cerrno>
#include <cstdarg>
#include <cstdio>
#include <cstring>
#include <iomanip>
#include <mutex>
#include <ostream>
#include <streambuf>
#include <thread>
#include "config.h"
#include "utilities.h"
#ifdef HAVE_UNISTD_H
# include <unistd.h> // for close() and write()
#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)
# include <syscall.h> // for syscall()
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h> // for syscall()
#include <sys/syscall.h> // for syscall()
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#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)) && \
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
!defined(GLOG_OS_EMSCRIPTEN)
# define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#define safe_write(fd, s, len) syscall(SYS_write, fd, s, len)
#else
// Not so safe, but what can you do?
# define safe_write(fd, s, len) write(fd, s, len)
#define safe_write(fd, s, len) write(fd, s, len)
#endif
namespace google {
_START_GOOGLE_NAMESPACE_
#if defined(__GNUC__)
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
__attribute__((format(archetype, stringIndex, firstToCheck)))
# define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex) \
__attribute__((format_arg(stringIndex)))
#else
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
# define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
#endif
// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code
@ -102,15 +103,15 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
}
// Helper for RawLog__ below.
inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
va_list ap) {
inline static bool VADoRawLog(char** buf, size_t* size,
const char* format, va_list ap) {
#if defined(__GNUC__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#endif
int n = std::vsnprintf(*buf, *size, format, ap);
#if defined(__GNUC__)
# pragma GCC diagnostic pop
#pragma GCC diagnostic pop
#endif
if (n < 0 || static_cast<size_t>(n) > *size) return false;
*size -= static_cast<size_t>(n);
@ -119,29 +120,9 @@ inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
}
static const int kLogBufSize = 3000;
static std::once_flag crashed;
static logging::internal::CrashReason crash_reason;
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
static bool crashed = false;
static CrashReason crash_reason;
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
void RawLog__(LogSeverity severity, const char* file, int line,
@ -151,25 +132,16 @@ void RawLog__(LogSeverity severity, const char* file, int line,
!IsGoogleLoggingInitialized())) {
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
char buffer[kLogBufSize];
char* buf = buffer;
size_t size = sizeof(buffer);
// NOTE: this format should match the specification in base/logging.h
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %s %s:%d] RAW: ",
GetLogSeverityName(severity)[0], sbuf.data(),
const_basename(const_cast<char*>(file)), line);
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
LogSeverityNames[severity][0],
static_cast<unsigned int>(GetTID()),
const_basename(const_cast<char *>(file)), line);
// Record the position and size of the buffer after the prefix
const char* msg_start = buf;
@ -188,9 +160,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
// libc (to side-step any libc interception).
// 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) {
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.line_number = line;
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;
#endif
SetCrashReason(&crash_reason);
});
}
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.
//
// Redistribution and use in source and binary forms, with or without
@ -31,36 +31,22 @@
//
// Implementation of InstallFailureSignalHandler().
#include <algorithm>
#include <csignal>
#include <cstring>
#include <ctime>
#include <mutex>
#include <sstream>
#include <thread>
#include "config.h"
#include "glog/logging.h"
#include "glog/platform.h"
#include "stacktrace.h"
#include "symbolize.h"
#include "utilities.h"
#ifdef HAVE_UCONTEXT_H
# include <ucontext.h>
#endif
#ifdef HAVE_SYS_UCONTEXT_H
# include <sys/ucontext.h>
#endif
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#if defined(HAVE_SYS_SYSCALL_H) && defined(HAVE_SYS_TYPES_H)
# include <sys/syscall.h>
# include <sys/types.h>
#endif
#include <algorithm>
namespace google {
_START_GOOGLE_NAMESPACE_
namespace {
@ -71,14 +57,16 @@ namespace {
// The list should be synced with the comment in signalhandler.h.
const struct {
int number;
const char* name;
const char *name;
} kFailureSignals[] = {
{SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"},
{SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"},
{ SIGSEGV, "SIGSEGV" },
{ SIGILL, "SIGILL" },
{ SIGFPE, "SIGFPE" },
{ SIGABRT, "SIGABRT" },
#if !defined(GLOG_OS_WINDOWS)
{SIGBUS, "SIGBUS"},
{ SIGBUS, "SIGBUS" },
#endif
{SIGTERM, "SIGTERM"},
{ SIGTERM, "SIGTERM" },
};
static bool kFailureSignalHandlerInstalled = false;
@ -86,15 +74,14 @@ static bool kFailureSignalHandlerInstalled = false;
#if !defined(GLOG_OS_WINDOWS)
// Returns the program counter from signal context, nullptr if unknown.
void* GetPC(void* ucontext_in_void) {
# if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \
defined(PC_FROM_UCONTEXT)
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
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;
}
# else
#else
(void)ucontext_in_void;
# endif
#endif
return nullptr;
}
#endif
@ -103,13 +90,14 @@ void* GetPC(void* ucontext_in_void) {
// as it's not async signal safe.
class MinimalFormatter {
public:
MinimalFormatter(char* buffer, size_t size)
: buffer_(buffer), cursor_(buffer), end_(buffer + size) {}
MinimalFormatter(char *buffer, size_t size)
: buffer_(buffer),
cursor_(buffer),
end_(buffer + size) {
}
// Returns the number of bytes written in the buffer.
std::size_t num_bytes_written() const {
return static_cast<std::size_t>(cursor_ - buffer_);
}
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
// Appends string from "str" and updates the internal cursor.
void AppendString(const char* str) {
@ -155,14 +143,14 @@ class MinimalFormatter {
}
private:
char* buffer_;
char* cursor_;
const char* const end_;
char *buffer_;
char *cursor_;
const char * const end_;
};
// Writes the given data with the size to the standard error.
void WriteToStderr(const char* data, size_t size) {
if (write(fileno(stderr), data, size) < 0) {
if (write(STDERR_FILENO, data, size) < 0) {
// Ignore errors.
}
}
@ -189,7 +177,7 @@ void DumpTimeInfo() {
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
// Dumps information about the signal to STDERR.
void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
void DumpSignalInfo(int signal_number, siginfo_t *siginfo) {
// Get the signal name.
const char* signal_name = nullptr;
for (auto kFailureSignal : kFailureSignals) {
@ -215,25 +203,21 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
formatter.AppendString(")");
formatter.AppendString(" received by PID ");
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
formatter.AppendString(" (TID ");
std::ostringstream oss;
oss << std::showbase << std::hex << std::this_thread::get_id();
formatter.AppendString(oss.str().c_str());
# if defined(GLOG_OS_LINUX) && defined(HAVE_SYS_SYSCALL_H) && \
defined(HAVE_SYS_TYPES_H)
pid_t tid = syscall(SYS_gettid);
formatter.AppendString(" LWP ");
formatter.AppendUint64(static_cast<uint64>(tid), 10);
# endif
formatter.AppendString(" (TID 0x");
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
// returns a pointer.
pthread_t id = pthread_self();
formatter.AppendUint64(
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
formatter.AppendString(") ");
// 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.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
formatter.AppendString("; ");
# endif
#endif
formatter.AppendString("stack trace: ***\n");
g_failure_writer(buf, formatter.num_bytes_written());
}
@ -243,19 +227,14 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
// Dumps information about the stack frame to STDERR.
void DumpStackFrameInfo(const char* prefix, void* pc) {
// Get the symbol name.
const char* symbol = "(unknown)";
#if defined(HAVE_SYMBOLIZE)
const char *symbol = "(unknown)";
char symbolized[1024]; // Big enough for a sane symbol.
// Symbolizes the previous address of pc because pc may be in the
// next function.
if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,
sizeof(symbolized))) {
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
symbolized, sizeof(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.
MinimalFormatter formatter(buf, sizeof(buf));
@ -285,19 +264,52 @@ void InvokeDefaultSignalHandler(int signal_number) {
#endif
}
// This variable is used for protecting FailureSignalHandler() from dumping
// stuff while another thread is doing it. Our policy is to let the first
// thread dump stuff and let other threads do nothing.
// This variable is used for protecting FailureSignalHandler() from
// dumping stuff while another thread is doing it. Our policy is to let
// the first thread dump stuff and let other threads wait.
// 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
#if !defined(GLOG_OS_WINDOWS)
,
siginfo_t* signal_info, void* ucontext
// 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
) {
{
// 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
// do some interesting stuff from here.
// TODO(satorux): We might want to set timeout here using alarm(), but
@ -308,18 +320,18 @@ static void HandleSignal(int signal_number
#if !defined(GLOG_OS_WINDOWS)
// Get the program counter from ucontext.
void* pc = GetPC(ucontext);
void *pc = GetPC(ucontext);
DumpStackFrameInfo("PC: ", pc);
#endif
#ifdef HAVE_STACKTRACE
// Get the stack traces.
void* stack[32];
void *stack[32];
// +1 to exclude this function.
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
# ifdef HAVE_SIGACTION
DumpSignalInfo(signal_number, signal_info);
# elif !defined(GLOG_OS_WINDOWS)
#elif !defined(GLOG_OS_WINDOWS)
(void)signal_info;
# endif
// Dump the stack traces.
@ -341,31 +353,16 @@ static void HandleSignal(int signal_number
// Flush the logs before we do anything in case 'anything'
// causes problems.
FlushLogFilesUnsafe(GLOG_INFO);
FlushLogFilesUnsafe(0);
// Kill ourself by the default signal handler.
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 glog_internal_namespace_ {
bool IsFailureSignalHandlerInstalled() {
#ifdef HAVE_SIGACTION
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
@ -382,6 +379,8 @@ bool IsFailureSignalHandlerInstalled() {
return false;
}
} // namespace glog_internal_namespace_
void InstallFailureSignalHandler() {
#ifdef HAVE_SIGACTION
// Build the sigaction struct.
@ -397,7 +396,8 @@ void InstallFailureSignalHandler() {
kFailureSignalHandlerInstalled = true;
#elif defined(GLOG_OS_WINDOWS)
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;
#endif // HAVE_SIGACTION
@ -409,4 +409,4 @@ void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
#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.
//
// Redistribution and use in source and binary forms, with or without
@ -32,52 +32,52 @@
// This is a helper binary for testing signalhandler.cc. The actual test
// is done in signalhandler_unittest.sh.
#include "utilities.h"
#if defined(HAVE_PTHREAD)
# include <pthread.h>
#endif
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include <sstream>
#include <string>
#include <thread>
#include "config.h"
#include "glog/logging.h"
#include "stacktrace.h"
#include "symbolize.h"
#if defined(HAVE_UNISTD_H)
# include <unistd.h>
#endif
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
#if defined(_MSC_VER)
# include <io.h> // write
#endif
using namespace google;
using namespace GOOGLE_NAMESPACE;
static void DieInThread(int* a) {
std::ostringstream oss;
oss << std::showbase << std::hex << std::this_thread::get_id();
fprintf(stderr, "%s is dying\n", oss.str().c_str());
int b = 1 / *a;
static void* DieInThread(void*) {
// We assume pthread_t is an integral number or a pointer, rather
// than a complex struct. In some environments, pthread_self()
// returns an uint64 but in some other environments pthread_self()
// returns a pointer.
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);
return nullptr;
}
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.
}
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
InitGoogleLogging(argv[0]);
# ifdef GLOG_USE_GFLAGS
#ifdef HAVE_LIB_GFLAGS
ParseCommandLineFlags(&argc, &argv, true);
# endif
#endif
InstallFailureSignalHandler();
const std::string command = argc > 1 ? argv[1] : "none";
if (command == "segv") {
@ -85,15 +85,20 @@ int main(int argc, char** argv) {
LOG(INFO) << "create the log file";
LOG(INFO) << "a message before segv";
// We assume 0xDEAD is not writable.
int* a = (int*)0xDEAD;
int *a = (int*)0xDEAD;
*a = 0;
} else if (command == "loop") {
fprintf(stderr, "looping\n");
while (true)
;
while (true);
} else if (command == "die_in_thread") {
std::thread t{&DieInThread, nullptr};
t.join();
#if defined(HAVE_PTHREAD)
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") {
InstallFailureWriter(WriteToStdout);
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.
//
// 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
// thread-safe.
#ifndef GLOG_INTERNAL_STACKTRACE_H
#define GLOG_INTERNAL_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
#ifndef BASE_STACKTRACE_H_
#define BASE_STACKTRACE_H_
#include "config.h"
#if defined(HAVE_LIBUNWIND)
# 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
#include "glog/logging.h"
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
# 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)
_START_GOOGLE_NAMESPACE_
// This is similar to the GetStackFrames routine, except that it returns
// 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.
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_
} // namespace google
#endif // GLOG_INTERNAL_STACKTRACE_H
#endif // BASE_STACKTRACE_H_

View File

@ -37,13 +37,12 @@
#include "stacktrace.h"
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
static const int kStackLength = 64;
void* stack[kStackLength];
void * stack[kStackLength];
int size;
size = backtrace(stack, kStackLength);
@ -62,5 +61,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return result_count;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_

View File

@ -40,8 +40,7 @@ extern "C" {
#include "glog/raw_logging.h"
#include "stacktrace.h"
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// Sometimes, we can try to get a stack trace from within a stack
// trace, because libunwind can call mmap (maybe indirectly via an
@ -56,7 +55,7 @@ static __thread bool g_tl_entered; // Initialized to false.
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void* ip;
void *ip;
int n = 0;
unw_cursor_t cursor;
unw_context_t uc;
@ -72,7 +71,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
while (n < max_depth) {
int ret =
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t*>(&ip));
unw_get_reg(&cursor, UNW_REG_IP, reinterpret_cast<unw_word_t *>(&ip));
if (ret < 0) {
break;
}
@ -91,5 +90,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_

View File

@ -40,16 +40,15 @@
#include "stacktrace.h"
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template <bool STRICT_UNWINDING>
static void** NextStackFrame(void** old_sp) {
void** new_sp = static_cast<void**>(*old_sp);
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = static_cast<void **>(*old_sp);
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
@ -69,7 +68,7 @@ static void** NextStackFrame(void** old_sp) {
return nullptr;
}
}
if ((uintptr_t)new_sp & (sizeof(void*) - 1)) return nullptr;
if ((uintptr_t)new_sp & (sizeof(void *) - 1)) return nullptr;
return new_sp;
}
@ -79,15 +78,15 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void** sp;
void **sp;
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
// and Darwin 8.8.1 (Tiger) use as 1.38. This means we have to use a
// different asm syntax. I don't know quite the best way to discriminate
// systems using the old as from the new one; I've gone with __APPLE__.
#ifdef __APPLE__
__asm__ volatile("mr %0,r1" : "=r"(sp));
__asm__ volatile ("mr %0,r1" : "=r" (sp));
#else
__asm__ volatile("mr %0,1" : "=r"(sp));
__asm__ volatile ("mr %0,1" : "=r" (sp));
#endif
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
@ -112,18 +111,17 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
// it's in sp[1].
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
result[n++] = *(sp + 2);
result[n++] = *(sp+2);
#elif defined(_CALL_SYSV)
result[n++] = *(sp + 1);
#elif defined(__APPLE__) || \
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
result[n++] = *(sp+1);
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
// 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__)
// This check is in case the compiler doesn't define _CALL_SYSV.
result[n++] = *(sp + 1);
result[n++] = *(sp+1);
#else
# error Need to specify the PPC ABI for your architecture.
#error Need to specify the PPC ABI for your architecture.
#endif
}
// Use strict unwinding rules.
@ -132,5 +130,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
return n;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_

View File

@ -41,6 +41,8 @@
# include <execinfo.h>
#endif
using namespace GOOGLE_NAMESPACE;
#ifdef HAVE_STACKTRACE
// Obtain a backtrace, verify that the expected callers are present in the
@ -57,11 +59,11 @@ struct AddressRange {
// Expected function [start,end] range.
AddressRange expected_range[BACKTRACE_STEPS];
# if __GNUC__
#if __GNUC__
// Using GCC extension: address of a label can be taken with '&&label'.
// Start should be a label somewhere before recursive call, end somewhere
// after it.
# define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \
(prange)->start = &&start_label; \
(prange)->end = &&end_label; \
@ -72,72 +74,66 @@ AddressRange expected_range[BACKTRACE_STEPS];
// Without it, there is no code following the 'end' label, and GCC
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
// the recursive call.
# define DECLARE_ADDRESS_LABEL(a_label) \
a_label: \
do { \
__asm__ __volatile__(""); \
} while (0)
#define DECLARE_ADDRESS_LABEL(a_label) \
a_label: do { __asm__ __volatile__(""); } while (0)
// 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
// instruction (this actually happens with FDO).
// Adjust function range from __builtin_return_address.
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \
void* ra = __builtin_return_address(0); \
void *ra = __builtin_return_address(0); \
CHECK_LT((prange)->start, ra); \
if (ra > (prange)->end) { \
printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \
(prange)->end, (prange)->start, ra); \
printf("Adjusting range from %p..%p to %p..%p\n", \
(prange)->start, (prange)->end, \
(prange)->start, ra); \
(prange)->end = ra; \
} \
} while (0)
# else
#else
// Assume the Check* functions below are not longer than 256 bytes.
# define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
do { \
(prange)->start = reinterpret_cast<const void*>(&fn); \
(prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
(prange)->start = reinterpret_cast<const void *>(&fn); \
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
} while (0)
# define DECLARE_ADDRESS_LABEL(a_label) \
do { \
} while (0)
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
do { \
} while (0)
# endif // __GNUC__
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
#endif // __GNUC__
//-----------------------------------------------------------------------//
static void CheckRetAddrIsInFunction(void* ret_addr,
const AddressRange& range) {
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
{
CHECK_GE(ret_addr, range.start);
CHECK_LE(ret_addr, range.end);
}
//-----------------------------------------------------------------------//
# if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wgnu-label-as-value"
# endif
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
#endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
const int STACK_LEN = 10;
void* stack[STACK_LEN];
void *stack[STACK_LEN];
int size;
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
DECLARE_ADDRESS_LABEL(start);
size = google::GetStackTrace(stack, STACK_LEN, 0);
size = GetStackTrace(stack, STACK_LEN, 0);
printf("Obtained %d stack frames.\n", size);
CHECK_GE(size, 1);
CHECK_LE(size, STACK_LEN);
if (true) {
# ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
char** strings = backtrace_symbols(stack, size);
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
char **strings = backtrace_symbols(stack, size);
printf("Obtained %d stack frames.\n", size);
for (int i = 0; i < size; i++) {
printf("%s %p\n", strings[i], stack[i]);
@ -150,11 +146,11 @@ static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
printf("CheckStackTrace() addr: %p\n", p.p2);
free(strings);
# endif
#endif
}
for (int i = 0; i < BACKTRACE_STEPS; i++) {
printf("Backtrace %d: expected: %p..%p actual: %p ... ", i,
expected_range[i].start, expected_range[i].end, stack[i]);
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
i, expected_range[i].start, expected_range[i].end, stack[i]);
fflush(stdout);
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
printf("OK\n");
@ -202,7 +198,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
DECLARE_ADDRESS_LABEL(end);
}
# ifndef __GNUC__
#ifndef __GNUC__
// On non-GNU environment, we use the address of `CheckStackTrace` to
// guess the address range of this function. This guess is wrong for
// non-static function on Windows. This is probably because
@ -210,9 +206,8 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
// not the actual address of `CheckStackTrace`.
// See https://github.com/google/glog/issues/421 for the detail.
static
# endif
void ATTRIBUTE_NOINLINE
CheckStackTrace(int i) {
#endif
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
DECLARE_ADDRESS_LABEL(start);
for (int j = i; j >= 0; j--) {
@ -221,15 +216,15 @@ static
DECLARE_ADDRESS_LABEL(end);
}
# if defined(__clang__)
# pragma clang diagnostic pop
# endif
#if defined(__clang__)
#pragma clang diagnostic pop
#endif
//-----------------------------------------------------------------------//
int main(int, char** argv) {
int main(int, char ** argv) {
FLAGS_logtostderr = true;
google::InitGoogleLogging(argv[0]);
InitGoogleLogging(argv[0]);
CheckStackTrace(0);
@ -240,10 +235,10 @@ int main(int, char** argv) {
#else
int main() {
# ifdef GLOG_BAZEL_BUILD
#ifdef GLOG_BAZEL_BUILD
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
exit(EXIT_FAILURE);
# endif // GLOG_BAZEL_BUILD
#endif // GLOG_BAZEL_BUILD
printf("PASS (no stacktrace support)\n");
return 0;

View File

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

View File

@ -31,13 +31,12 @@
//
// Windows implementation - just use CaptureStackBackTrace
// clang-format off
#include <windows.h> // Must come before <dbghelp.h>
#include "config.h"
#include "port.h"
#include "stacktrace.h"
#include <dbghelp.h>
// clang-format on
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
int GetStackTrace(void** result, int max_depth, int skip_count) {
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);
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_

View File

@ -34,24 +34,23 @@
#include "utilities.h" // for OS_* macros
#if !defined(GLOG_OS_WINDOWS)
# include <sys/mman.h>
# include <unistd.h>
#include <unistd.h>
#include <sys/mman.h>
#endif
#include <cstdio> // for nullptr
#include "stacktrace.h"
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// Given a pointer to a stack frame, locate and return the calling
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
// checks (the strictness of which is controlled by the boolean parameter
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
template <bool STRICT_UNWINDING>
static void** NextStackFrame(void** old_sp) {
void** new_sp = static_cast<void**>(*old_sp);
template<bool STRICT_UNWINDING>
static void **NextStackFrame(void **old_sp) {
void **new_sp = static_cast<void **>(*old_sp);
// Check that the transition from frame pointer old_sp to frame
// pointer new_sp isn't clearly bogus
@ -76,7 +75,7 @@ static void** NextStackFrame(void** old_sp) {
return nullptr;
}
}
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void*) - 1)) {
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void *) - 1)) {
return nullptr;
}
#ifdef __i386__
@ -93,8 +92,8 @@ static void** NextStackFrame(void** old_sp) {
// Note: NextStackFrame<false>() is only called while the program
// is already on its last leg, so it's ok to be slow here.
static int page_size = getpagesize();
void* new_sp_aligned =
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_sp) &
void *new_sp_aligned =
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(new_sp) &
static_cast<uintptr_t>(~(page_size - 1)));
if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {
return nullptr;
@ -106,12 +105,12 @@ static void** NextStackFrame(void** old_sp) {
// If you change this function, also change GetStackFrames below.
int GetStackTrace(void** result, int max_depth, int skip_count) {
void** sp;
void **sp;
#ifdef __GNUC__
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
# define USE_BUILTIN_FRAME_ADDRESS
# endif
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
#define USE_BUILTIN_FRAME_ADDRESS
#endif
#endif
#ifdef USE_BUILTIN_FRAME_ADDRESS
@ -122,7 +121,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// sp[1] caller address
// sp[2] first argument
// ...
sp = (void**)&result - 2;
sp = (void **)&result - 2;
#elif defined(__x86_64__)
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
unsigned long rbp;
@ -133,10 +132,10 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
// would be (before this __asm__ instruction) to call Noop() defined as
// static void Noop() __attribute__ ((noinline)); // prevent inlining
// static void Noop() { asm(""); } // prevent optimizing-away
__asm__ volatile("mov %%rbp, %0" : "=r"(rbp));
__asm__ volatile ("mov %%rbp, %0" : "=r" (rbp));
// Arguments are passed in registers on x86-64, so we can't just
// offset from &result
sp = (void**)rbp;
sp = (void **) rbp;
#endif
int n = 0;
@ -149,12 +148,12 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
if (skip_count > 0) {
skip_count--;
} else {
result[n++] = *(sp + 1);
result[n++] = *(sp+1);
}
// Use strict unwinding rules.
sp = NextStackFrame<true>(sp);
}
return n;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_

View File

@ -62,14 +62,14 @@ static void TestSTLLogging() {
{
// Test a sorted pair associative container.
map<int, string> m;
map< int, string > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
ostringstream ss;
ss << m;
EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
map<int, string> copied_m(m);
map< int, string > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
@ -95,14 +95,14 @@ static void TestSTLLogging() {
{
// Test a sorted pair associative container.
// Use a non-default comparison functor.
map<int, string, greater<>> m;
map<int, string, greater<> > m;
m[20] = "twenty";
m[10] = "ten";
m[30] = "thirty";
ostringstream ss;
ss << m;
EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
map<int, string, greater<>> copied_m(m);
map<int, string, greater<> > copied_m(m);
CHECK_EQ(m, copied_m); // This must compile.
}
}

View File

@ -44,7 +44,7 @@
GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'");
using std::string;
using namespace google;
using namespace GOOGLE_NAMESPACE;
int CheckNoReturn(bool b) {
string s;
@ -57,13 +57,13 @@ int CheckNoReturn(bool b) {
}
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.

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc.
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -49,123 +49,111 @@
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
#ifdef GLOG_BUILD_CONFIG_INCLUDE
# include GLOG_BUILD_CONFIG_INCLUDE
#include GLOG_BUILD_CONFIG_INCLUDE
#endif // GLOG_BUILD_CONFIG_INCLUDE
#include "symbolize.h"
#include "utilities.h"
#if defined(HAVE_SYMBOLIZE)
# include <algorithm>
# include <cstdlib>
# include <cstring>
# include <limits>
#include <cstring>
# include "demangle.h"
#include <algorithm>
#include <limits>
#include "symbolize.h"
#include "demangle.h"
_START_GOOGLE_NAMESPACE_
// We don't use assert() since it's not guaranteed to be
// async-signal-safe. Instead we define a minimal assertion
// macro. So far, we don't need pretty printing for __FILE__, etc.
# define GLOG_SAFE_ASSERT(expr) ((expr) ? 0 : (std::abort(), 0))
namespace google {
inline namespace glog_internal_namespace_ {
namespace {
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);
}
}
// A wrapper for abort() to make it callable in ? :.
static int AssertFail() {
abort();
return 0; // Should not reach.
}
} // namespace
#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
static SymbolizeCallback g_symbolize_callback = nullptr;
void InstallSymbolizeCallback(SymbolizeCallback callback) {
g_symbolize_callback = callback;
}
static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
nullptr;
void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback) {
g_symbolize_open_object_file_callback = callback;
}
} // namespace glog_internal_namespace_
} // namespace google
# if defined(HAVE_LINK_H)
# if defined(HAVE_DLFCN_H)
# include <dlfcn.h>
# endif
# include <fcntl.h>
# include <sys/stat.h>
# include <sys/types.h>
# include <unistd.h>
# include <cerrno>
# include <climits>
# include <cstddef>
# include <cstdint>
# include <cstdio>
# include <cstdlib>
# include <cstring>
# include "config.h"
# include "glog/raw_logging.h"
# include "symbolize.h"
namespace google {
inline namespace glog_internal_namespace_ {
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) {
// 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.
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);
}
}
return result;
}
} // namespace
_END_GOOGLE_NAMESPACE_
#if defined(__ELF__)
#if defined(HAVE_DLFCN_H)
#include <dlfcn.h>
#endif
#if defined(GLOG_OS_OPENBSD)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#endif
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <cerrno>
#include <climits>
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include "config.h"
#include "glog/raw_logging.h"
#include "symbolize.h"
// Re-runs fn until it doesn't cause EINTR.
#define NO_INTR(fn) do {} while ((fn) < 0 && errno == EINTR)
_START_GOOGLE_NAMESPACE_
// 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
// and EINTR. On success, return the number of bytes read. Otherwise, return
// -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) {
GLOG_SAFE_ASSERT(fd >= 0);
GLOG_SAFE_ASSERT(count <=
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
char* buf0 = reinterpret_cast<char*>(buf);
SAFE_ASSERT(fd >= 0);
SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
char *buf0 = reinterpret_cast<char *>(buf);
size_t num_bytes = 0;
while (num_bytes < count) {
ssize_t len = FailureRetry([fd, p = buf0 + num_bytes, n = count - num_bytes,
m = static_cast<off_t>(offset + num_bytes)] {
return pread(fd, p, n, m);
});
ssize_t len;
NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes,
static_cast<off_t>(offset + num_bytes)));
if (len < 0) { // There was an error other than EINTR.
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);
}
GLOG_SAFE_ASSERT(num_bytes <= count);
SAFE_ASSERT(num_bytes <= count);
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
// short reads and EINTR. On success, return true. Otherwise, return
// false.
static bool ReadFromOffsetExact(const int fd, void* buf, const size_t count,
const size_t offset) {
static bool ReadFromOffsetExact(const int fd, void *buf,
const size_t count, const size_t offset) {
ssize_t len = ReadFromOffset(fd, buf, count, offset);
return static_cast<size_t>(len) == count;
}
@ -205,11 +193,9 @@ static int FileGetElfType(const int fd) {
// and return true. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
ElfW(Half) sh_num,
const size_t sh_offset,
ElfW(Word) type,
ElfW(Shdr) * out) {
static ATTRIBUTE_NOINLINE bool
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
ElfW(Word) type, ElfW(Shdr) *out) {
// Read at most 16 section headers at a time to save read calls.
ElfW(Shdr) buf[16];
for (size_t i = 0; i < sh_num;) {
@ -221,9 +207,9 @@ static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
if (len == -1) {
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]);
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) {
if (buf[j].sh_type == type) {
*out = buf[j];
@ -240,8 +226,8 @@ static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
const int kMaxSectionNameLen = 64;
// name_len should include terminating '\0'.
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
ElfW(Shdr) * out) {
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out) {
ElfW(Ehdr) elf_header;
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
return false;
@ -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) {
size_t section_header_offset =
(elf_header.e_shoff + elf_header.e_shentsize * i);
size_t section_header_offset = (elf_header.e_shoff +
elf_header.e_shentsize * i);
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
return false;
}
char header_name[kMaxSectionNameLen];
if (sizeof(header_name) < name_len) {
RAW_LOG(WARNING,
"Section name '%s' is too long (%zu); "
"section will not be found (even if present).",
name, name_len);
RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
"section will not be found (even if present).", name, name_len);
// No point in even trying.
return false;
}
@ -291,11 +275,10 @@ bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
// to out. Otherwise, return false.
// To keep stack consumption low, we would like this function to not get
// inlined.
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
size_t out_size,
uint64_t symbol_offset,
const ElfW(Shdr) * strtab,
const ElfW(Shdr) * symtab) {
static ATTRIBUTE_NOINLINE bool
FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
const ElfW(Shdr) *symtab) {
if (symtab == nullptr) {
return false;
}
@ -306,20 +289,20 @@ static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
// If we are reading Elf64_Sym's, we want to limit this array to
// 32 elements (to keep stack consumption low), otherwise we can
// have a 64 element Elf32_Sym array.
# if defined(__WORDSIZE) && __WORDSIZE == 64
#if defined(__WORDSIZE) && __WORDSIZE == 64
const size_t NUM_SYMBOLS = 32U;
# else
#else
const size_t NUM_SYMBOLS = 64U;
# endif
#endif
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
ElfW(Sym) buf[NUM_SYMBOLS];
size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
const ssize_t len =
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]);
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) {
const ElfW(Sym)& symbol = buf[j];
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,
// write the symbol name to "out" and return true. Otherwise, return
// false.
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
size_t out_size, uint64_t base_address) {
static bool GetSymbolFromObjectFile(const int fd,
uint64_t pc,
char* out,
size_t out_size,
uint64_t base_address) {
// Read the ELF header.
ElfW(Ehdr) elf_header;
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.
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_SYMTAB, &symtab)) {
if (!ReadFromOffsetExact(
fd, &strtab, sizeof(strtab),
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
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 (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
SHT_DYNSYM, &symtab)) {
if (!ReadFromOffsetExact(
fd, &strtab, sizeof(strtab),
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
symtab.sh_link * sizeof(symtab))) {
return false;
}
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
@ -386,6 +370,22 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
}
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.
//
@ -394,7 +394,7 @@ namespace {
// and std::snprintf().
class LineReader {
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)
: fd_(fd),
buf_(buf),
buf_len_(buf_len),
@ -408,7 +408,7 @@ class LineReader {
//
// Note: if the last line doesn't end with '\n', the line will be
// dropped. It's an intentional behavior to make the code simple.
bool ReadLine(const char** bol, const char** eol) {
bool ReadLine(const char **bol, const char **eol) {
if (BufferIsEmpty()) { // First time.
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
if (num_bytes <= 0) { // EOF or error.
@ -419,13 +419,13 @@ class LineReader {
bol_ = buf_;
} else {
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()) {
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
// Move the trailing incomplete line to the beginning.
memmove(buf_, bol_, incomplete_line_length);
// Read text from file and append it.
char* const append_pos = buf_ + incomplete_line_length;
char * const append_pos = buf_ + incomplete_line_length;
const size_t capacity_left = buf_len_ - incomplete_line_length;
const ssize_t num_bytes =
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
@ -449,53 +449,57 @@ class LineReader {
}
// Beginning of line.
const char* bol() { return bol_; }
// End of line.
const char* eol() { return eol_; }
private:
LineReader(const LineReader&) = delete;
void operator=(const LineReader&) = delete;
char* FindLineFeed() {
return reinterpret_cast<char*>(
memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
const char *bol() {
return bol_;
}
bool BufferIsEmpty() { return buf_ == eod_; }
// End of line.
const char *eol() {
return eol_;
}
private:
LineReader(const LineReader &) = delete;
void operator=(const LineReader &) = delete;
char *FindLineFeed() {
return reinterpret_cast<char *>(memchr(bol_, '\n', static_cast<size_t>(eod_ - bol_)));
}
bool BufferIsEmpty() {
return buf_ == eod_;
}
bool HasCompleteLine() {
return !BufferIsEmpty() && FindLineFeed() != nullptr;
}
const int fd_;
char* const buf_;
char * const buf_;
const size_t buf_len_;
size_t offset_;
char* bol_;
char* eol_;
const char* eod_; // End of data in "buf_".
char *bol_;
char *eol_;
const char *eod_; // End of data in "buf_".
};
} // namespace
// Place the hex number read from "start" into "*hex". The pointer to
// the first non-hex character or "end" is returned.
static char* GetHex(const char* start, const char* end, uint64_t* hex) {
static char *GetHex(const char *start, const char *end, uint64_t *hex) {
*hex = 0;
const char* p;
const char *p;
for (p = start; p < end; ++p) {
int ch = *p;
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
(ch >= 'a' && ch <= 'f')) {
*hex = (*hex << 4U) |
(ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
if ((ch >= '0' && ch <= '9') ||
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
*hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
} else { // Encountered the first non-hex character.
break;
}
}
GLOG_SAFE_ASSERT(p <= end);
return const_cast<char*>(p);
SAFE_ASSERT(p <= end);
return const_cast<char *>(p);
}
// Searches for the object file (from /proc/self/maps) that contains
@ -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,
// returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator).
static ATTRIBUTE_NOINLINE FileDescriptor
static ATTRIBUTE_NOINLINE int
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t& start_address,
uint64_t& base_address,
char* out_file_name,
uint64_t &start_address,
uint64_t &base_address,
char *out_file_name,
size_t out_file_name_size) {
FileDescriptor maps_fd{
FailureRetry([] { return open("/proc/self/maps", O_RDONLY); })};
if (!maps_fd) {
return nullptr;
int object_fd;
int maps_fd;
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{
FailureRetry([] { return open("/proc/self/mem", O_RDONLY); })};
if (!mem_fd) {
return nullptr;
int mem_fd;
NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
FileDescriptor wrapped_mem_fd(mem_fd);
if (wrapped_mem_fd.get() < 0) {
return -1;
}
// Iterate over maps and look for the map containing the pc. Then
// look into the symbol tables inside.
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) {
const char* cursor;
const char* eol;
const char *cursor;
const char *eol;
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
return nullptr;
return -1;
}
// Start parsing line in /proc/self/maps. Here is an example:
@ -545,7 +553,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// Read start address.
cursor = GetHex(cursor, eol, &start_address);
if (cursor == eol || *cursor != '-') {
return nullptr; // Malformed line.
return -1; // Malformed line.
}
++cursor; // Skip '-'.
@ -553,26 +561,25 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t end_address;
cursor = GetHex(cursor, eol, &end_address);
if (cursor == eol || *cursor != ' ') {
return nullptr; // Malformed line.
return -1; // Malformed line.
}
++cursor; // Skip ' '.
// Read flags. Skip flags until we encounter a space or eol.
const char* const flags_start = cursor;
const char * const flags_start = cursor;
while (cursor < eol && *cursor != ' ') {
++cursor;
}
// We expect at least four letters for flags (ex. "r-xp").
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.
ElfW(Ehdr) ehdr;
// Skip non-readable maps.
if (flags_start[0] == 'r' &&
ReadFromOffsetExact(mem_fd.get(), &ehdr, sizeof(ElfW(Ehdr)),
start_address) &&
ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
switch (ehdr.e_type) {
case ET_EXEC:
@ -591,7 +598,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
ElfW(Phdr) phdr;
if (ReadFromOffsetExact(
mem_fd.get(), &phdr, sizeof(phdr),
mem_fd, &phdr, sizeof(phdr),
start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
base_address = start_address - phdr.p_vaddr;
@ -607,7 +614,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
}
// 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.
}
@ -621,7 +628,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
uint64_t file_offset;
cursor = GetHex(cursor, eol, &file_offset);
if (cursor == eol || *cursor != ' ') {
return nullptr; // Malformed line.
return -1; // Malformed line.
}
++cursor; // Skip ' '.
@ -639,16 +646,20 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
++cursor;
}
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);
// Making sure |out_file_name| is always null-terminated.
out_file_name[out_file_name_size - 1] = '\0';
// Finally, "cursor" now points to file name of our interest.
return FileDescriptor{
FailureRetry([cursor] { return open(cursor, O_RDONLY); })};
return -1;
}
return object_fd;
}
}
@ -659,8 +670,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
// appended.
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
size_t padding) {
static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
// Make sure we can write at least one NUL byte.
size_t n = 1;
if (n > sz) {
@ -672,11 +682,11 @@ static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
return nullptr;
}
char* start = buf;
char *start = buf;
// Loop until we have converted the entire number. Output at least one
// character (i.e. '0').
char* ptr = start;
char *ptr = start;
do {
// Make sure there is still enough space left in our output buffer.
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.
static void SafeAppendString(const char* source, char* dest, size_t dest_size) {
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_size -= dest_string_length;
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.
// To keep stack consumption low, we would like this function to not
// get inlined.
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size) {
auto pc0 = reinterpret_cast<uintptr_t>(pc);
uint64_t start_address = 0;
uint64_t base_address = 0;
FileDescriptor object_fd;
int object_fd = -1;
if (out_size < 1) {
return false;
@ -751,19 +761,24 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
SafeAppendString("(", out, out_size);
if (g_symbolize_open_object_file_callback) {
object_fd.reset(g_symbolize_open_object_file_callback(
pc0, start_address, base_address, out + 1, out_size - 1));
object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
base_address, out + 1,
out_size - 1);
} else {
object_fd = OpenObjectFileContainingPcAndGetStartAddress(
pc0, start_address, base_address, out + 1, out_size - 1);
object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
base_address,
out + 1,
out_size - 1);
}
# if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
FileDescriptor wrapped_object_fd(object_fd);
#if defined(PRINT_UNSYMBOLIZED_STACK_TRACES)
{
# else
#else
// Check whether a file name was returned.
if (!object_fd) {
# endif
if (object_fd < 0) {
#endif
if (out[1]) {
// The object file containing PC was determined successfully however the
// object file was not opened successfully. This is still considered
@ -778,7 +793,7 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
// Failed to determine the object file containing PC. Bail out.
return false;
}
int elf_type = FileGetElfType(object_fd.get());
int elf_type = FileGetElfType(wrapped_object_fd.get());
if (elf_type == -1) {
return false;
}
@ -787,15 +802,16 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
// Note: relocation (and much of the rest of this code) will be
// wrong for prelinked shared libraries and PIE executables.
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
int num_bytes_written =
g_symbolize_callback(object_fd.get(), pc, out, out_size, relocation);
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
pc, out, out_size,
relocation);
if (num_bytes_written > 0) {
out += 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,
base_address)) {
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
out, out_size, base_address)) {
if (out[1] && !g_symbolize_callback) {
// The object file containing PC was opened successfully however the
// symbol was not found. The object may have been stripped. This is still
@ -815,20 +831,17 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
return true;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
# 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>
_START_GOOGLE_NAMESPACE_
namespace google {
inline namespace glog_internal_namespace_ {
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size) {
Dl_info info;
if (dladdr(pc, &info)) {
if (info.dli_sname) {
@ -843,30 +856,31 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
return false;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
# 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 {
inline namespace glog_internal_namespace_ {
#ifdef _MSC_VER
#pragma comment(lib, "dbghelp")
#endif
namespace {
_START_GOOGLE_NAMESPACE_
class SymInitializer final {
public:
class SymInitializer {
public:
HANDLE process;
bool ready;
SymInitializer() : process(GetCurrentProcess()), ready(false) {
SymInitializer() : process(nullptr), ready(false) {
// Initialize the symbol handler.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
process = GetCurrentProcess();
// Defer symbol loading.
// We do not request undecorated symbols with SYMOPT_UNDNAME
// because the mangling library calls UnDecorateSymbolName.
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
SymSetOptions(SYMOPT_DEFERRED_LOADS);
if (SymInitialize(process, nullptr, true)) {
ready = true;
}
@ -875,18 +889,13 @@ class SymInitializer final {
SymCleanup(process);
// We do not need to close `HANDLE process` because it's a "pseudo handle."
}
SymInitializer(const SymInitializer&) = delete;
SymInitializer& operator=(const SymInitializer&) = delete;
SymInitializer(SymInitializer&&) = delete;
SymInitializer& operator=(SymInitializer&&) = delete;
private:
SymInitializer(const SymInitializer&);
SymInitializer& operator=(const SymInitializer&);
};
} // namespace
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
size_t out_size,
SymbolizeOptions options) {
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
size_t out_size) {
const static SymInitializer symInitializer;
if (!symInitializer.ready) {
return false;
@ -894,70 +903,52 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
// Resolve symbol information from address.
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
SYMBOL_INFO* symbol = reinterpret_cast<SYMBOL_INFO*>(buf);
SYMBOL_INFO *symbol = reinterpret_cast<SYMBOL_INFO *>(buf);
symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol->MaxNameLen = MAX_SYM_NAME;
// We use the ANSI version to ensure the string type is always `char *`.
// This could break if a symbol has Unicode in it.
BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc),
0, symbol);
std::size_t namelen = static_cast<size_t>(symbol->NameLen);
if (ret && namelen < out_size) {
std::strncpy(out, symbol->Name, namelen);
out[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);
}
BOOL ret = SymFromAddr(symInitializer.process,
reinterpret_cast<DWORD64>(pc), 0, symbol);
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
// `NameLen` does not include the null terminating character.
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
out[static_cast<size_t>(symbol->NameLen)] = '\0';
// Symbolization succeeded. Now we try to demangle the symbol.
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 false;
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
# else
#else
# error BUG: HAVE_SYMBOLIZE was wrongly set
# endif
#endif
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
bool Symbolize(void* pc, char* out, size_t out_size, SymbolizeOptions options) {
return SymbolizeAndDemangle(pc, out, out_size, options);
bool Symbolize(void *pc, char *out, size_t out_size) {
return SymbolizeAndDemangle(pc, out, out_size);
}
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
#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

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc.
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -51,61 +51,38 @@
// malloc() and other unsafe operations. It should be both
// thread-safe and async-signal-safe.
#ifndef GLOG_INTERNAL_SYMBOLIZE_H
#define GLOG_INTERNAL_SYMBOLIZE_H
#include <cstddef>
#include <cstdint>
#include <type_traits>
#ifndef BASE_SYMBOLIZE_H_
#define BASE_SYMBOLIZE_H_
#include "config.h"
#include "glog/platform.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)
#include "glog/logging.h"
#include "utilities.h"
#ifdef HAVE_SYMBOLIZE
# if !defined(SIZEOF_VOID_P) && defined(__SIZEOF_POINTER__)
# define SIZEOF_VOID_P __SIZEOF_POINTER__
# endif
#if defined(__ELF__) // defined by gcc
#if defined(__OpenBSD__)
#include <sys/exec_elf.h>
#else
#include <elf.h>
#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.
# ifndef ElfW
#ifndef ElfW
# if SIZEOF_VOID_P == 4
# define ElfW(type) Elf32_##type
# elif SIZEOF_VOID_P == 8
@ -113,24 +90,20 @@
# else
# error "Unknown sizeof(void *)"
# endif
# endif
#endif
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// Gets the section header for the given name, if it exists. Returns true on
// success. Otherwise, returns false.
GLOG_NO_EXPORT
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
ElfW(Shdr) * out);
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
ElfW(Shdr) *out);
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
# endif
#endif /* __ELF__ */
namespace google {
inline namespace glog_internal_namespace_ {
_START_GOOGLE_NAMESPACE_
// Restrictions on the callbacks that follow:
// - The callbacks must not use heaps but only use stacks.
@ -143,8 +116,8 @@ inline namespace glog_internal_namespace_ {
// counter "pc". The callback function should write output to "out"
// and return the size of the output written. On error, the callback
// function should return -1.
using SymbolizeCallback = int (*)(int, void*, char*, size_t, uint64_t);
GLOG_NO_EXPORT
using SymbolizeCallback = int (*)(int, void *, char *, size_t, uint64_t);
GLOG_EXPORT
void InstallSymbolizeCallback(SymbolizeCallback callback);
// 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,
// returns -1. |out_file_name_size| is the size of the file name buffer
// (including the null-terminator).
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&,
char*, size_t);
GLOG_NO_EXPORT
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t &,
uint64_t &, char *, size_t);
void InstallSymbolizeOpenObjectFileCallback(
SymbolizeOpenObjectFileCallback callback);
} // namespace glog_internal_namespace_
} // namespace google
_END_GOOGLE_NAMESPACE_
#endif
namespace google {
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));
}
_START_GOOGLE_NAMESPACE_
// Symbolizes a program counter. On success, returns true and write the
// symbol name to "out". The symbol name is demangled if possible
// (supports symbols generated by GCC 3.x or newer). Otherwise,
// returns false.
GLOG_NO_EXPORT bool Symbolize(
void* pc, char* out, size_t out_size,
SymbolizeOptions options = SymbolizeOptions::kNone);
GLOG_EXPORT bool Symbolize(void* pc, char* out, size_t out_size);
#endif // defined(HAVE_SYMBOLIZE)
_END_GOOGLE_NAMESPACE_
} // namespace glog_internal_namespace_
} // namespace google
#endif // GLOG_INTERNAL_SYMBOLIZE_H
#endif // BASE_SYMBOLIZE_H_

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc.
// Copyright (c) 2006, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -40,49 +40,46 @@
#include "glog/logging.h"
#include "googletest.h"
#include "utilities.h"
#include "stacktrace.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
using namespace std;
using namespace google;
using namespace GOOGLE_NAMESPACE;
// Avoid compile error due to "cast between pointer-to-function and
// pointer-to-object is an extension" warnings.
#if defined(__GNUG__)
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wpedantic"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
#endif
#if defined(HAVE_STACKTRACE)
# define always_inline
#define always_inline
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) || \
defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
#if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
// A wrapper function for Symbolize() to make the unit test simple.
static const char* TrySymbolize(void* pc, google::SymbolizeOptions options =
google::SymbolizeOptions::kNone) {
static const char *TrySymbolize(void *pc) {
static char symbol[4096];
if (Symbolize(pc, symbol, sizeof(symbol), options)) {
if (Symbolize(pc, symbol, sizeof(symbol))) {
return symbol;
} else {
return nullptr;
}
}
# endif
#endif
# if defined(__ELF__)
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
// This unit tests make sense only with GCC.
// Uses lots of GCC specific features.
# if defined(__GNUC__) && !defined(__OPENCC__)
#if defined(__GNUC__) && !defined(__OPENCC__)
# if __GNUC__ >= 4
# define TEST_WITH_MODERN_GCC
# if defined(__i386__) && __i386__ // always_inline isn't supported for
// x86_64 with GCC 4.1.0.
# if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
# undef always_inline
# define always_inline __attribute__((always_inline))
# define HAVE_ALWAYS_INLINE
@ -90,7 +87,7 @@ static const char* TrySymbolize(void* pc, google::SymbolizeOptions options =
# else
# endif // __GNUC__ >= 4
# define TEST_WITH_LABEL_ADDRESSES
# endif
#endif
// Make them C linkage to avoid mangled names.
extern "C" {
@ -115,18 +112,18 @@ TEST(Symbolize, Symbolize) {
// reinterpret_cast<void *>(&func).
// Compilers should give us pointers to them.
EXPECT_STREQ("nonstatic_func", TrySymbolize((void*)(&nonstatic_func)));
EXPECT_STREQ("nonstatic_func", TrySymbolize((void *)(&nonstatic_func)));
// The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here.
const char* static_func_symbol =
TrySymbolize(reinterpret_cast<void*>(&static_func));
const char *static_func_symbol =
TrySymbolize(reinterpret_cast<void *>(&static_func));
# if !defined(_MSC_VER) || !defined(NDEBUG)
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(nullptr != static_func_symbol);
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
strcmp("static_func()", static_func_symbol) == 0);
# endif
#endif
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
}
@ -144,18 +141,14 @@ void ATTRIBUTE_NOINLINE Foo::func(int x) {
// With a modern GCC, Symbolize() should return demangled symbol
// names. Function parameters should be omitted.
# ifdef TEST_WITH_MODERN_GCC
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
# 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)));
# endif
# endif
#if !defined(_MSC_VER) || !defined(NDEBUG)
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
#endif
}
# endif
#endif
// Tests that verify that Symbolize footprint is within some limit.
@ -174,9 +167,9 @@ TEST(Symbolize, SymbolizeWithDemangling) {
// calls Symbolize. The difference between the stack consumption of these
// two signals handlers should give us the Symbolize stack foorprint.
static void* g_pc_to_symbolize;
static void *g_pc_to_symbolize;
static char g_symbolize_buffer[4096];
static char* g_symbolize_result;
static char *g_symbolize_result;
static void EmptySignalHandler(int /*signo*/) {}
@ -195,7 +188,7 @@ const char kAlternateStackFillValue = 0x55;
// These helper functions look at the alternate stack buffer, and figure
// out what portion of this buffer has been touched - this is the stack
// consumption of the signal handler running on this alternate stack.
static ATTRIBUTE_NOINLINE bool StackGrowsDown(int* x) {
static ATTRIBUTE_NOINLINE bool StackGrowsDown(int *x) {
int y;
return &y < x;
}
@ -217,10 +210,11 @@ static int GetStackConsumption(const char* alt_stack) {
return -1;
}
# ifdef HAVE_SIGALTSTACK
#ifdef HAVE_SIGALTSTACK
// 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;
// The alt-signal-stack cannot be heap allocated because there is a
@ -288,131 +282,120 @@ static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
return g_symbolize_result;
}
# if !defined(HAVE___CXA_DEMANGLE)
# ifdef __ppc64__
#ifdef __ppc64__
// Symbolize stack consumption should be within 4kB.
constexpr int kStackConsumptionUpperLimit = 4096;
# else
const int kStackConsumptionUpperLimit = 4096;
#else
// Symbolize stack consumption should be within 2kB.
constexpr int kStackConsumptionUpperLimit = 2048;
# endif
# endif
const int kStackConsumptionUpperLimit = 2048;
#endif
TEST(Symbolize, SymbolizeStackConsumption) {
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&nonstatic_func),
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&nonstatic_func),
&stack_consumed);
EXPECT_STREQ("nonstatic_func", symbol);
EXPECT_GT(stack_consumed, 0);
# if !defined(HAVE___CXA_DEMANGLE)
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
# endif
// The name of an internal linkage symbol is not specified; allow either a
// mangled or an unmangled name here.
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&static_func),
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&static_func),
&stack_consumed);
CHECK(nullptr != symbol);
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
strcmp("static_func()", symbol) == 0);
EXPECT_GT(stack_consumed, 0);
# if !defined(HAVE___CXA_DEMANGLE)
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
# endif
}
# if defined(TEST_WITH_MODERN_GCC) && !defined(HAVE___CXA_DEMANGLE)
#ifdef TEST_WITH_MODERN_GCC
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
Foo::func(100);
int stack_consumed;
const char* symbol;
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&Foo::func),
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func),
&stack_consumed);
# if defined(HAVE___CXA_DEMANGLE)
EXPECT_STREQ("Foo::func(int)", symbol);
# else
EXPECT_STREQ("Foo::func()", symbol);
# endif
EXPECT_GT(stack_consumed, 0);
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
}
# endif
#endif
# endif // HAVE_SIGALTSTACK
#endif // HAVE_SIGALTSTACK
// x86 specific tests. Uses some inline assembler.
extern "C" {
inline void* always_inline inline_func() {
void* pc = nullptr;
# ifdef TEST_WITH_LABEL_ADDRESSES
void *pc = nullptr;
#ifdef TEST_WITH_LABEL_ADDRESSES
pc = &&curr_pc;
curr_pc:
# endif
curr_pc:
#endif
return pc;
}
void* ATTRIBUTE_NOINLINE non_inline_func();
void* ATTRIBUTE_NOINLINE non_inline_func() {
void* pc = nullptr;
# ifdef TEST_WITH_LABEL_ADDRESSES
void *pc = nullptr;
#ifdef TEST_WITH_LABEL_ADDRESSES
pc = &&curr_pc;
curr_pc:
# endif
curr_pc:
#endif
return pc;
}
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)
void* pc = non_inline_func();
const char* symbol = TrySymbolize(pc);
#if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)
void *pc = non_inline_func();
const char *symbol = TrySymbolize(pc);
# if !defined(_MSC_VER) || !defined(NDEBUG)
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr);
CHECK_STREQ(symbol, "non_inline_func");
# endif
#endif
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
# endif
#endif
}
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)
void* pc = inline_func(); // Must be inlined.
const char* symbol = TrySymbolize(pc);
#if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)
void *pc = inline_func(); // Must be inlined.
const char *symbol = TrySymbolize(pc);
# if !defined(_MSC_VER) || !defined(NDEBUG)
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr);
CHECK_STREQ(symbol, __FUNCTION__);
# endif
#endif
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
# endif
#endif
}
}
// Test with a return address.
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
# if defined(HAVE_ATTRIBUTE_NOINLINE)
void* return_address = __builtin_return_address(0);
const char* symbol =
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
#if defined(HAVE_ATTRIBUTE_NOINLINE)
void *return_address = __builtin_return_address(0);
const char *symbol = TrySymbolize(return_address);
# if !defined(_MSC_VER) || !defined(NDEBUG)
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr);
CHECK_STREQ(symbol, "main");
# endif
#endif
cout << "Test case TestWithReturnAddress passed." << endl;
# endif
#endif
}
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
# ifdef _MSC_VER
# include <intrin.h>
# pragma intrinsic(_ReturnAddress)
# endif
#ifdef _MSC_VER
#include <intrin.h>
#pragma intrinsic(_ReturnAddress)
#endif
struct Foo {
static void func(int x);
@ -427,38 +410,37 @@ __declspec(noinline) void Foo::func(int x) {
TEST(Symbolize, SymbolizeWithDemangling) {
Foo::func(100);
const char* ret = TrySymbolize((void*)(&Foo::func));
const char* ret = TrySymbolize((void *)(&Foo::func));
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret);
# endif
#endif
}
__declspec(noinline) void TestWithReturnAddress() {
void* return_address =
# ifdef __GNUC__ // Cygwin and MinGW support
void *return_address =
#ifdef __GNUC__ // Cygwin and MinGW support
__builtin_return_address(0)
# else
#else
_ReturnAddress()
# endif
#endif
;
const char* symbol =
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
# if !defined(_MSC_VER) || !defined(NDEBUG)
const char *symbol = TrySymbolize(return_address);
#if !defined(_MSC_VER) || !defined(NDEBUG)
CHECK(symbol != nullptr);
CHECK_STREQ(symbol, "main");
# endif
#endif
cout << "Test case TestWithReturnAddress passed." << endl;
}
# endif
# endif // __ELF__
#endif // HAVE_STACKTRACE
int main(int argc, char** argv) {
int main(int argc, char **argv) {
FLAGS_logtostderr = true;
InitGoogleLogging(argv[0]);
InitGoogleTest(&argc, argv);
#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
// used to install some callback function at InitGoogle() time.
InstallSymbolizeCallback(nullptr);
@ -473,7 +455,7 @@ int main(int argc, char** argv) {
# else // GLOG_OS_WINDOWS
printf("PASS (no symbolize_unittest support)\n");
return 0;
# endif // defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
# endif // __ELF__
#else
printf("PASS (no symbolize support)\n");
return 0;
@ -481,5 +463,5 @@ int main(int argc, char** argv) {
}
#if defined(__GNUG__)
# pragma GCC diagnostic pop
#pragma GCC diagnostic pop
#endif

View File

@ -1,4 +1,4 @@
// Copyright (c) 2024, Google Inc.
// Copyright (c) 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
@ -29,33 +29,21 @@
//
// Author: Shinichiro Hamaji
#define _GNU_SOURCE 1
#include "config.h"
#include "utilities.h"
#include <atomic>
#include <cerrno>
#include <csignal>
#include <cstdio>
#include <cstdlib>
#include "base/googleinit.h"
#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
#include <csignal>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#endif
#include <ctime>
#if defined(HAVE_SYSCALL_H)
# include <syscall.h> // for syscall()
#include <syscall.h> // for syscall()
#elif defined(HAVE_SYS_SYSCALL_H)
# include <sys/syscall.h> // for syscall()
#include <sys/syscall.h> // for syscall()
#endif
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
@ -66,14 +54,15 @@
#ifdef HAVE_PWD_H
# include <pwd.h>
#endif
#if defined(HAVE___PROGNAME)
extern char* __progname;
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "base/googleinit.h"
using std::string;
namespace google {
_START_GOOGLE_NAMESPACE_
static const char* g_program_invocation_short_name = nullptr;
@ -81,45 +70,19 @@ bool IsGoogleLoggingInitialized() {
return g_program_invocation_short_name != nullptr;
}
inline namespace glog_internal_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
_END_GOOGLE_NAMESPACE_
// The following APIs are all internal.
#ifdef HAVE_STACKTRACE
# include "base/commandlineflags.h"
# include "stacktrace.h"
# include "symbolize.h"
#include "stacktrace.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*);
@ -127,29 +90,33 @@ using DebugWriter = void(const char*, void*);
// For some environments, add two extra bytes for the leading "0x".
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.
if (write(fileno(stderr), data, strlen(data)) < 0) {
if (write(STDERR_FILENO, data, strlen(data)) < 0) {
// Ignore errors.
}
AlsoErrorWrite(GLOG_FATAL,
glog_internal_namespace_::ProgramInvocationShortName(), data);
#if defined(__ANDROID__)
// 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) {
reinterpret_cast<string*>(arg)->append(data);
}
# ifdef HAVE_SYMBOLIZE
#ifdef HAVE_SYMBOLIZE
// Print a program counter and its symbol name.
static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
const char* const prefix) {
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char tmp[1024];
const char* symbol = "(unknown)";
const char *symbol = "(unknown)";
// Symbolizes the previous address of pc because pc may be in the
// next function. The overrun happens when the function ends with
// a call to a function annotated noreturn (e.g. CHECK).
if (Symbolize(reinterpret_cast<char*>(pc) - 1, tmp, sizeof(tmp))) {
if (Symbolize(reinterpret_cast<char *>(pc) - 1, tmp, sizeof(tmp))) {
symbol = tmp;
}
char buf[1024];
@ -157,10 +124,10 @@ static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
kPrintfPointerFieldWidth, pc, symbol);
writerfn(buf, arg);
}
# endif
#endif
static void DumpPC(DebugWriter* writerfn, void* arg, void* pc,
const char* const prefix) {
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
const char * const prefix) {
char buf[100];
std::snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth,
pc);
@ -168,26 +135,26 @@ static void DumpPC(DebugWriter* writerfn, void* arg, void* pc,
}
// Dump current stack trace as directed by writerfn
static void DumpStackTrace(int skip_count, DebugWriter* writerfn, void* arg) {
static void DumpStackTrace(int skip_count, DebugWriter *writerfn, void *arg) {
// Print stack trace
void* stack[32];
int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count + 1);
int depth = GetStackTrace(stack, ARRAYSIZE(stack), skip_count+1);
for (int i = 0; i < depth; i++) {
# if defined(HAVE_SYMBOLIZE)
#if defined(HAVE_SYMBOLIZE)
if (FLAGS_symbolize_stacktrace) {
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
} else {
DumpPC(writerfn, arg, stack[i], " ");
}
# else
#else
DumpPC(writerfn, arg, stack[i], " ");
# endif
#endif
}
}
# ifdef __GNUC__
#ifdef __GNUC__
__attribute__((noreturn))
# endif
#endif
static void
DumpStackTraceAndExit() {
DumpStackTrace(1, DebugWriteToStderr, nullptr);
@ -196,55 +163,88 @@ DumpStackTraceAndExit() {
if (IsFailureSignalHandlerInstalled()) {
// Set the default signal handler for SIGABRT, to avoid invoking our
// own signal handler installed by InstallFailureSignalHandler().
# ifdef HAVE_SIGACTION
#ifdef HAVE_SIGACTION
struct sigaction sig_action;
memset(&sig_action, 0, sizeof(sig_action));
sigemptyset(&sig_action.sa_mask);
sig_action.sa_handler = SIG_DFL;
sigaction(SIGABRT, &sig_action, nullptr);
# elif defined(GLOG_OS_WINDOWS)
#elif defined(GLOG_OS_WINDOWS)
signal(SIGABRT, SIG_DFL);
# endif // HAVE_SIGACTION
#endif // HAVE_SIGACTION
}
abort();
}
} // namespace google
_END_GOOGLE_NAMESPACE_
#endif // HAVE_STACKTRACE
namespace google {
_START_GOOGLE_NAMESPACE_
inline 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;
}
namespace glog_internal_namespace_ {
const char* ProgramInvocationShortName() {
if (g_program_invocation_short_name != nullptr) {
return g_program_invocation_short_name;
}
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
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
} else {
// TODO(hamaji): Use /proc/self/cmdline and so?
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
#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();
int32 GetMainThreadPid() { return g_main_thread_pid; }
int32 GetMainThreadPid() {
return g_main_thread_pid;
}
bool PidHasChanged() {
int32 pid = getpid();
@ -255,8 +255,66 @@ bool PidHasChanged() {
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;
const string& MyUserName() { return g_my_user_name; }
const string& MyUserName() {
return g_my_user_name;
}
static void MyUserNameInitializer() {
// TODO(hamaji): Probably this is not portable.
#if defined(GLOG_OS_WINDOWS)
@ -287,19 +345,30 @@ static void 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
// 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) {
const logging::internal::CrashReason* expected = nullptr;
g_reason.compare_exchange_strong(expected, r);
void SetCrashReason(const CrashReason* r) {
sync_val_compare_and_swap(&g_reason,
reinterpret_cast<const CrashReason*>(0),
r);
}
void InitGoogleLoggingUtilities(const char* argv0) {
CHECK(!IsGoogleLoggingInitialized())
<< "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
InstallFailureFunction(&DumpStackTraceAndExit);
@ -308,8 +377,7 @@ void InitGoogleLoggingUtilities(const char* argv0) {
void ShutdownGoogleLoggingUtilities() {
CHECK(IsGoogleLoggingInitialized())
<< "You called ShutdownGoogleLogging() without calling "
"InitGoogleLogging() first!";
<< "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
g_program_invocation_short_name = nullptr;
#ifdef HAVE_SYSLOG_H
closelog();
@ -318,12 +386,17 @@ void ShutdownGoogleLoggingUtilities() {
} // namespace glog_internal_namespace_
#ifdef HAVE_STACKTRACE
std::string GetStackTrace() {
std::string stacktrace;
DumpStackTrace(1, DebugWriteToString, &stacktrace);
return stacktrace;
}
#endif
_END_GOOGLE_NAMESPACE_
} // 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.
//
// Redistribution and use in source and binary forms, with or without
@ -28,25 +28,17 @@
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Author: Shinichiro Hamaji
// Sergiu Deitsch
//
// Define utilities for glog internal usage.
#ifndef GLOG_INTERNAL_UTILITIES_H
#define GLOG_INTERNAL_UTILITIES_H
#include <cstddef>
#include <cstdio>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#ifndef UTILITIES_H__
#define UTILITIES_H__
// printf macros for size_t, in the style of inttypes.h
#ifdef _LP64
# define __PRIS_PREFIX "z"
#define __PRIS_PREFIX "z"
#else
# define __PRIS_PREFIX
#define __PRIS_PREFIX
#endif
// Use these macros after a % in a printf format string
@ -60,25 +52,16 @@
#define PRIXS __PRIS_PREFIX "X"
#define PRIoS __PRIS_PREFIX "o"
#include "config.h"
#include "glog/platform.h"
#if defined(GLOG_USE_WINDOWS_PORT)
#include <string>
#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"
#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 "glog/types.h"
#include "config.h"
// 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.
// 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
// There is a better way, but this is good enough for our purpose.
# define ARRAYSIZE(a) (sizeof(a) / sizeof(*(a)))
#endif
namespace google {
_START_GOOGLE_NAMESPACE_
namespace logging {
namespace internal {
namespace glog_internal_namespace_ {
#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 {
CrashReason() = default;
@ -125,159 +202,15 @@ struct CrashReason {
int depth{0};
};
} // namespace internal
} // 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 SetCrashReason(const CrashReason* r);
void InitGoogleLoggingUtilities(const char* argv0);
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 google
_END_GOOGLE_NAMESPACE_
template <>
struct std::default_delete<std::FILE> {
void operator()(FILE* p) const noexcept { fclose(p); }
};
using namespace GOOGLE_NAMESPACE::glog_internal_namespace_;
#endif // GLOG_INTERNAL_UTILITIES_H
#endif // UTILITIES_H__

View File

@ -33,18 +33,25 @@
#include "glog/logging.h"
#include "googletest.h"
#ifdef GLOG_USE_GFLAGS
# include <gflags/gflags.h>
#ifdef HAVE_LIB_GFLAGS
#include <gflags/gflags.h>
using namespace GFLAGS_NAMESPACE;
#endif
using namespace google;
using namespace GOOGLE_NAMESPACE;
TEST(utilities, sync_val_compare_and_swap) {
bool now_entering = false;
EXPECT_FALSE(sync_val_compare_and_swap(&now_entering, false, true));
EXPECT_TRUE(sync_val_compare_and_swap(&now_entering, false, true));
EXPECT_TRUE(sync_val_compare_and_swap(&now_entering, false, true));
}
TEST(utilities, InitGoogleLoggingDeathTest) {
ASSERT_DEATH(InitGoogleLogging("foobar"), "");
}
int main(int argc, char** argv) {
int main(int argc, char **argv) {
InitGoogleLogging(argv[0]);
InitGoogleTest(&argc, argv);

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