Compare commits
1 Commits
master
...
ubuntu-run
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4ef97e07a |
@ -1,8 +1,8 @@
|
|||||||
---
|
---
|
||||||
tasks:
|
tasks:
|
||||||
ubuntu1804:
|
ubuntu1804:
|
||||||
name: "Ubuntu 22.04"
|
name: "Ubuntu 18.04"
|
||||||
platform: ubuntu2204
|
platform: ubuntu1804
|
||||||
build_flags:
|
build_flags:
|
||||||
- "--features=layering_check"
|
- "--features=layering_check"
|
||||||
- "--copt=-Werror"
|
- "--copt=-Werror"
|
||||||
|
|||||||
@ -58,7 +58,7 @@ ConstructorInitializerIndentWidth: 4
|
|||||||
ContinuationIndentWidth: 4
|
ContinuationIndentWidth: 4
|
||||||
Cpp11BracedListStyle: true
|
Cpp11BracedListStyle: true
|
||||||
DeriveLineEnding: true
|
DeriveLineEnding: true
|
||||||
DerivePointerAlignment: false
|
DerivePointerAlignment: true
|
||||||
DisableFormat: false
|
DisableFormat: false
|
||||||
ExperimentalAutoDetectBinPacking: false
|
ExperimentalAutoDetectBinPacking: false
|
||||||
FixNamespaceComments: true
|
FixNamespaceComments: true
|
||||||
@ -84,7 +84,7 @@ IncludeIsMainRegex: '([-_](test|unittest))?$'
|
|||||||
IncludeIsMainSourceRegex: ''
|
IncludeIsMainSourceRegex: ''
|
||||||
IndentCaseLabels: true
|
IndentCaseLabels: true
|
||||||
IndentGotoLabels: true
|
IndentGotoLabels: true
|
||||||
IndentPPDirectives: AfterHash
|
IndentPPDirectives: None
|
||||||
IndentWidth: 2
|
IndentWidth: 2
|
||||||
IndentWrappedFunctionNames: false
|
IndentWrappedFunctionNames: false
|
||||||
JavaScriptQuotes: Leave
|
JavaScriptQuotes: Leave
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*'
|
Checks: 'clang-diagnostic-*,clang-analyzer-*,google-*,modernize-*,-modernize-use-trailing-return-type,readability-*,portability-*,performance-*,bugprone-*,android-*,darwin-*,clang-analyzer-*'
|
||||||
WarningsAsErrors: ''
|
WarningsAsErrors: ''
|
||||||
HeaderFilterRegex: ''
|
HeaderFilterRegex: ''
|
||||||
|
AnalyzeTemporaryDtors: false
|
||||||
FormatStyle: file
|
FormatStyle: file
|
||||||
CheckOptions:
|
CheckOptions:
|
||||||
- key: cert-dcl16-c.NewSuffixes
|
- key: cert-dcl16-c.NewSuffixes
|
||||||
|
|||||||
2
.github/workflows/android.yml
vendored
2
.github/workflows/android.yml
vendored
@ -5,7 +5,7 @@ on: [push, pull_request]
|
|||||||
jobs:
|
jobs:
|
||||||
build-android:
|
build-android:
|
||||||
name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}
|
name: NDK-C++${{matrix.std}}-${{matrix.abi}}-${{matrix.build_type}}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04-8core
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
|
|||||||
11
.github/workflows/emscripten.yml
vendored
11
.github/workflows/emscripten.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
|
name: Emscripten-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04-8core
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@ -40,11 +40,18 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}
|
CXXFLAGS: -Wall -Wextra -Wsign-conversion -Wtautological-compare -Wformat-nonliteral -Wundef -Werror -Wno-error=wasm-exception-spec ${{env.CXXFLAGS}}
|
||||||
run: |
|
run: |
|
||||||
emcmake cmake -S . -B build_${{matrix.build_type}} \
|
cmake -S . -B build_${{matrix.build_type}} \
|
||||||
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
|
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} \
|
||||||
|
-DCMAKE_AR=$(which emar) \
|
||||||
|
-DCMAKE_CXX_COMPILER=$(which em++) \
|
||||||
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
-DCMAKE_CXX_STANDARD=${{matrix.std}} \
|
||||||
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
-DCMAKE_CXX_STANDARD_REQUIRED=ON \
|
||||||
|
-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY \
|
||||||
|
-DCMAKE_FIND_ROOT_PATH_MODE_LIBRARY=ONLY \
|
||||||
|
-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY \
|
||||||
|
-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER \
|
||||||
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
|
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/install \
|
||||||
|
-DCMAKE_RANLIB=$(which emranlib) \
|
||||||
-G Ninja \
|
-G Ninja \
|
||||||
-Werror
|
-Werror
|
||||||
|
|
||||||
|
|||||||
41
.github/workflows/linux.yml
vendored
41
.github/workflows/linux.yml
vendored
@ -8,7 +8,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
shell: bash
|
shell: bash
|
||||||
name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
|
name: GCC-C++${{matrix.std}}-${{matrix.build_type}}-${{matrix.lib}}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04-8core
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@ -31,20 +31,42 @@ jobs:
|
|||||||
- name: Setup Dependencies
|
- name: Setup Dependencies
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y --no-install-suggests --no-install-recommends \
|
DEBIAN_FRONTEND=noninteractive sudo apt-get install -y \
|
||||||
g++ \
|
build-essential \
|
||||||
cmake \
|
cmake \
|
||||||
gcovr \
|
gcovr \
|
||||||
libgflags-dev \
|
libgflags-dev \
|
||||||
libgmock-dev \
|
|
||||||
libgtest-dev \
|
|
||||||
libunwind-dev \
|
libunwind-dev \
|
||||||
ninja-build
|
ninja-build
|
||||||
|
|
||||||
|
- name: Cache GTest
|
||||||
|
id: cache-gtest
|
||||||
|
uses: actions/cache@v3
|
||||||
|
with:
|
||||||
|
path: gtest/
|
||||||
|
key: ${{runner.os}}-gtest-1.11
|
||||||
|
|
||||||
|
- name: Download GTest
|
||||||
|
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
wget https://github.com/google/googletest/archive/refs/tags/release-1.11.0.tar.gz
|
||||||
|
tar xvf release-1.11.0.tar.gz
|
||||||
|
|
||||||
|
- name: Build GTest
|
||||||
|
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
||||||
|
run: |
|
||||||
|
cmake -S googletest-release-1.11.0 -B build-googletest \
|
||||||
|
-DBUILD_SHARED_LIBS=${{matrix.shared}} \
|
||||||
|
-DCMAKE_BUILD_TYPE=${{matrix.build_type}} \
|
||||||
|
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/gtest \
|
||||||
|
-G Ninja
|
||||||
|
cmake --build build-googletest --target install
|
||||||
|
|
||||||
- name: Setup Environment
|
- name: Setup Environment
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
run: |
|
run: |
|
||||||
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
|
echo 'CXXFLAGS=--coverage' >> $GITHUB_ENV
|
||||||
|
echo 'GTest_ROOT=${{github.workspace}}/gtest' >> $GITHUB_ENV
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
env:
|
env:
|
||||||
@ -106,10 +128,17 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd build_${{matrix.build_type}}
|
cd build_${{matrix.build_type}}
|
||||||
gcovr -r .. . -s --xml coverage.xml
|
gcovr -r .. . -s --xml coverage.xml
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
for file in src/glog/*.h.in; do
|
||||||
|
name=$(basename ${file})
|
||||||
|
name_we=${name%.h.in}
|
||||||
|
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
|
||||||
|
done
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: build_${{matrix.build_type}}/coverage.xml
|
files: build_${{matrix.build_type}}/coverage.xml
|
||||||
|
|||||||
10
.github/workflows/macos.yml
vendored
10
.github/workflows/macos.yml
vendored
@ -63,12 +63,18 @@ jobs:
|
|||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
run: |
|
run: |
|
||||||
cd build_${{matrix.build_type}}
|
cd build_${{matrix.build_type}}
|
||||||
rm -r Tests/
|
|
||||||
gcovr -r .. . -s --cobertura coverage.xml
|
gcovr -r .. . -s --cobertura coverage.xml
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
for file in src/glog/*.h.in; do
|
||||||
|
name=$(basename ${file})
|
||||||
|
name_we=${name%.h.in}
|
||||||
|
sed -i "" "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
|
||||||
|
done
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: build_${{matrix.build_type}}/coverage.xml
|
files: build_${{matrix.build_type}}/coverage.xml
|
||||||
|
|||||||
23
.github/workflows/windows.yml
vendored
23
.github/workflows/windows.yml
vendored
@ -42,21 +42,21 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache GTest
|
- name: Cache GTest
|
||||||
id: cache-gtest
|
id: cache-gtest
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: gtest/
|
path: gtest/
|
||||||
key: ${{runner.os}}-gtest-1.14-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
|
key: ${{runner.os}}-gtest-1.11-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
|
||||||
|
|
||||||
- name: Download GTest
|
- name: Download GTest
|
||||||
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
(New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/v1.14.0.zip", "v1.14.0.zip")
|
(New-Object System.Net.WebClient).DownloadFile("https://github.com/google/googletest/archive/refs/tags/release-1.11.0.zip", "release-1.11.0.zip")
|
||||||
Expand-Archive v1.14.0.zip .
|
Expand-Archive release-1.11.0.zip .
|
||||||
|
|
||||||
- name: Build GTest
|
- name: Build GTest
|
||||||
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
if: steps.cache-gtest.outputs.cache-hit != 'true'
|
||||||
run: |
|
run: |
|
||||||
cmake -S googletest-1.14.0 -B build-googletest `
|
cmake -S googletest-release-1.11.0 -B build-googletest `
|
||||||
-A ${{matrix.arch}} `
|
-A ${{matrix.arch}} `
|
||||||
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
|
-DBUILD_SHARED_LIBS=${{matrix.lib == 'shared'}} `
|
||||||
-Dgtest_force_shared_crt=ON `
|
-Dgtest_force_shared_crt=ON `
|
||||||
@ -67,7 +67,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Cache gflags
|
- name: Cache gflags
|
||||||
id: cache-gflags
|
id: cache-gflags
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: gflags/
|
path: gflags/
|
||||||
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
|
key: ${{runner.os}}-gflags-2.2.2-${{matrix.lib}}-${{matrix.arch}}-${{matrix.build_type}}
|
||||||
@ -188,7 +188,7 @@ jobs:
|
|||||||
- name: Setup Coverage Dependencies
|
- name: Setup Coverage Dependencies
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
run: |
|
run: |
|
||||||
pip install 'gcovr==7.0'
|
pip install 'gcovr==6.0'
|
||||||
|
|
||||||
- name: Setup Environment
|
- name: Setup Environment
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
@ -231,10 +231,17 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cd build_${{matrix.build_type}}
|
cd build_${{matrix.build_type}}
|
||||||
gcovr -r .. . -s --cobertura coverage.xml
|
gcovr -r .. . -s --cobertura coverage.xml
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
for file in src/glog/*.h.in; do
|
||||||
|
name=$(basename ${file})
|
||||||
|
name_we=${name%.h.in}
|
||||||
|
sed -i "s|build_${{matrix.build_type}}/glog/${name_we}.h|${file}|g" build_${{matrix.build_type}}/coverage.xml
|
||||||
|
done
|
||||||
|
|
||||||
- name: Upload Coverage to Codecov
|
- name: Upload Coverage to Codecov
|
||||||
if: matrix.build_type == 'Debug'
|
if: matrix.build_type == 'Debug'
|
||||||
uses: codecov/codecov-action@v5
|
uses: codecov/codecov-action@v3
|
||||||
with:
|
with:
|
||||||
token: ${{ secrets.CODECOV_TOKEN }}
|
token: ${{ secrets.CODECOV_TOKEN }}
|
||||||
files: build_${{matrix.build_type}}/coverage.xml
|
files: build_${{matrix.build_type}}/coverage.xml
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1,6 +1,3 @@
|
|||||||
*.orig
|
*.orig
|
||||||
/build*/
|
/build*/
|
||||||
/site/
|
|
||||||
bazel-*
|
bazel-*
|
||||||
# Bzlmod lockfile
|
|
||||||
/MODULE.bazel.lock
|
|
||||||
|
|||||||
@ -17,6 +17,6 @@ platform(
|
|||||||
constraint_values = [
|
constraint_values = [
|
||||||
"@platforms//cpu:x86_64",
|
"@platforms//cpu:x86_64",
|
||||||
"@platforms//os:windows",
|
"@platforms//os:windows",
|
||||||
"@rules_cc//cc/private/toolchain:clang-cl",
|
"@bazel_tools//tools/cpp:clang-cl",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
630
CMakeLists.txt
630
CMakeLists.txt
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required (VERSION 3.22)
|
cmake_minimum_required (VERSION 3.21)
|
||||||
project (glog
|
project (glog
|
||||||
VERSION 0.8.0
|
VERSION 0.7.0
|
||||||
DESCRIPTION "C++ implementation of the Google logging module"
|
DESCRIPTION "C++ implementation of the Google logging module"
|
||||||
HOMEPAGE_URL https://github.com/google/glog
|
HOMEPAGE_URL https://github.com/google/glog
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
@ -8,17 +8,20 @@ project (glog
|
|||||||
|
|
||||||
set (CPACK_PACKAGE_NAME glog)
|
set (CPACK_PACKAGE_NAME glog)
|
||||||
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library")
|
set (CPACK_PACKAGE_DESCRIPTION_SUMMARY "Google logging library")
|
||||||
set (CPACK_PACKAGE_VERSION_MAJOR ${glog_VERSION_MAJOR})
|
set (CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR})
|
||||||
set (CPACK_PACKAGE_VERSION_MINOR ${glog_VERSION_MINOR})
|
set (CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR})
|
||||||
set (CPACK_PACKAGE_VERSION_PATCH ${glog_VERSION_PATCH})
|
set (CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH})
|
||||||
set (CPACK_PACKAGE_VERSION ${glog_VERSION})
|
set (CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||||
|
|
||||||
list (APPEND CMAKE_MODULE_PATH ${glog_SOURCE_DIR}/cmake)
|
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
include (CheckCXXCompilerFlag)
|
||||||
include (CheckCXXSourceCompiles)
|
include (CheckCXXSourceCompiles)
|
||||||
include (CheckCXXSourceRuns)
|
include (CheckCXXSourceRuns)
|
||||||
include (CheckCXXSymbolExists)
|
include (CheckCXXSymbolExists)
|
||||||
|
include (CheckFunctionExists)
|
||||||
include (CheckIncludeFileCXX)
|
include (CheckIncludeFileCXX)
|
||||||
|
include (CheckLibraryExists)
|
||||||
include (CheckStructHasMember)
|
include (CheckStructHasMember)
|
||||||
include (CheckTypeSize)
|
include (CheckTypeSize)
|
||||||
include (CMakeDependentOption)
|
include (CMakeDependentOption)
|
||||||
@ -32,39 +35,42 @@ include (GetCacheVariables)
|
|||||||
include (GNUInstallDirs)
|
include (GNUInstallDirs)
|
||||||
|
|
||||||
option (BUILD_SHARED_LIBS "Build shared libraries" ON)
|
option (BUILD_SHARED_LIBS "Build shared libraries" ON)
|
||||||
option (BUILD_EXAMPLES "Build examples" ON)
|
|
||||||
option (PRINT_UNSYMBOLIZED_STACK_TRACES
|
option (PRINT_UNSYMBOLIZED_STACK_TRACES
|
||||||
"Print file offsets in traces instead of symbolizing" OFF)
|
"Print file offsets in traces instead of symbolizing" OFF)
|
||||||
option (WITH_GFLAGS "Use gflags" ON)
|
option (WITH_GFLAGS "Use gflags" ON)
|
||||||
option (WITH_GTEST "Use Google Test" ON)
|
option (WITH_GTEST "Use Google Test" ON)
|
||||||
option (WITH_PKGCONFIG "Enable pkg-config support" OFF)
|
option (WITH_PKGCONFIG "Enable pkg-config support" ON)
|
||||||
option (WITH_SYMBOLIZE "Enable symbolize module" ON)
|
option (WITH_SYMBOLIZE "Enable symbolize module" ON)
|
||||||
|
option (WITH_THREADS "Enable multithreading support" ON)
|
||||||
option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON)
|
option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON)
|
||||||
|
option (WITH_UNWIND "Enable libunwind support" ON)
|
||||||
set (WITH_UNWIND libunwind CACHE STRING "unwind driver")
|
|
||||||
set_property (CACHE WITH_UNWIND PROPERTY STRINGS none unwind libunwind)
|
|
||||||
|
|
||||||
cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF)
|
cmake_dependent_option (WITH_GMOCK "Use Google Mock" ON WITH_GTEST OFF)
|
||||||
|
|
||||||
set (WITH_FUZZING none CACHE STRING "Fuzzing engine")
|
set (WITH_FUZZING none CACHE STRING "Fuzzing engine")
|
||||||
set_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz)
|
set_property (CACHE WITH_FUZZING PROPERTY STRINGS none libfuzzer ossfuzz)
|
||||||
|
|
||||||
if (WITH_UNWIND STREQUAL none)
|
if (NOT WITH_UNWIND)
|
||||||
set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON)
|
set (CMAKE_DISABLE_FIND_PACKAGE_Unwind ON)
|
||||||
endif (WITH_UNWIND STREQUAL none)
|
endif (NOT WITH_UNWIND)
|
||||||
|
|
||||||
if (NOT WITH_GTEST)
|
if (NOT WITH_GTEST)
|
||||||
set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)
|
set (CMAKE_DISABLE_FIND_PACKAGE_GTest ON)
|
||||||
endif (NOT WITH_GTEST)
|
endif (NOT WITH_GTEST)
|
||||||
|
|
||||||
|
if (NOT WITH_THREADS)
|
||||||
|
set (CMAKE_DISABLE_FIND_PACKAGE_Threads ON)
|
||||||
|
endif (NOT WITH_THREADS)
|
||||||
|
|
||||||
set (CMAKE_C_VISIBILITY_PRESET hidden)
|
set (CMAKE_C_VISIBILITY_PRESET hidden)
|
||||||
set (CMAKE_CXX_VISIBILITY_PRESET hidden)
|
set (CMAKE_CXX_VISIBILITY_PRESET hidden)
|
||||||
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
|
set (CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
set (CMAKE_VISIBILITY_INLINES_HIDDEN ON)
|
||||||
|
|
||||||
set (CMAKE_DEBUG_POSTFIX d)
|
set (CMAKE_DEBUG_POSTFIX d)
|
||||||
|
set (CMAKE_THREAD_PREFER_PTHREAD 1)
|
||||||
|
|
||||||
find_package (GTest 1.11 COMPONENTS GTest OPTIONAL_COMPONENTS GMock NO_MODULE)
|
find_package (GTest NO_MODULE)
|
||||||
|
|
||||||
if (GTest_FOUND)
|
if (GTest_FOUND)
|
||||||
set (HAVE_LIB_GTEST 1)
|
set (HAVE_LIB_GTEST 1)
|
||||||
@ -83,54 +89,25 @@ if (WITH_GFLAGS)
|
|||||||
endif (gflags_FOUND)
|
endif (gflags_FOUND)
|
||||||
endif (WITH_GFLAGS)
|
endif (WITH_GFLAGS)
|
||||||
|
|
||||||
find_package (Threads REQUIRED)
|
find_package (Threads)
|
||||||
find_package (Unwind)
|
find_package (Unwind)
|
||||||
|
|
||||||
if (Unwind_FOUND)
|
if (Unwind_FOUND)
|
||||||
cmake_push_check_state (RESET)
|
set (HAVE_LIB_UNWIND 1)
|
||||||
set (CMAKE_REQUIRED_LIBRARIES unwind::unwind)
|
else (Unwind_FOUND)
|
||||||
|
|
||||||
# Check whether linking actually succeeds. ARM toolchains of LLVM unwind
|
# Check whether linking actually succeeds. ARM toolchains of LLVM unwind
|
||||||
# implementation do not necessarily provide the _Unwind_Backtrace function
|
# implementation do not necessarily provide the _Unwind_Backtrace function
|
||||||
# which causes the previous check to succeed but the linking to fail.
|
# which causes the previous check to succeed but the linking to fail.
|
||||||
check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE)
|
check_cxx_symbol_exists (_Unwind_Backtrace unwind.h HAVE__UNWIND_BACKTRACE)
|
||||||
check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP)
|
check_cxx_symbol_exists (_Unwind_GetIP unwind.h HAVE__UNWIND_GETIP)
|
||||||
|
|
||||||
check_cxx_symbol_exists (unw_get_reg libunwind.h HAVE_UNW_GET_REG)
|
|
||||||
check_cxx_symbol_exists (unw_getcontext libunwind.h HAVE_UNW_GETCONTEXT)
|
|
||||||
check_cxx_symbol_exists (unw_init_local libunwind.h HAVE_UNW_INIT_LOCAL)
|
|
||||||
check_cxx_symbol_exists (unw_step libunwind.h HAVE_UNW_STEP)
|
|
||||||
|
|
||||||
if (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)
|
|
||||||
set (_HAVE_UNWIND 1)
|
|
||||||
endif (HAVE__UNWIND_BACKTRACE AND HAVE__UNWIND_GETIP)
|
|
||||||
|
|
||||||
if (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)
|
|
||||||
set (_HAVE_LIBUNWIND 1)
|
|
||||||
endif (HAVE_UNW_GET_REG AND HAVE_UNW_GETCONTEXT AND HAVE_UNW_INIT_LOCAL AND HAVE_UNW_STEP)
|
|
||||||
|
|
||||||
if (WITH_UNWIND STREQUAL unwind)
|
|
||||||
if (_HAVE_UNWIND)
|
|
||||||
set (HAVE_UNWIND 1)
|
|
||||||
endif (_HAVE_UNWIND)
|
|
||||||
elseif (WITH_UNWIND STREQUAL libunwind)
|
|
||||||
if (_HAVE_LIBUNWIND)
|
|
||||||
set (HAVE_LIBUNWIND 1)
|
|
||||||
endif (_HAVE_LIBUNWIND)
|
|
||||||
endif (WITH_UNWIND STREQUAL unwind)
|
|
||||||
|
|
||||||
unset (_HAVE_LIBUNWIND)
|
|
||||||
unset (_HAVE_UNWIND)
|
|
||||||
|
|
||||||
cmake_pop_check_state ()
|
|
||||||
endif (Unwind_FOUND)
|
endif (Unwind_FOUND)
|
||||||
|
|
||||||
check_include_file_cxx (dlfcn.h HAVE_DLFCN_H)
|
check_include_file_cxx (dlfcn.h HAVE_DLFCN_H)
|
||||||
check_include_file_cxx (elf.h HAVE_ELF_H)
|
|
||||||
check_include_file_cxx (glob.h HAVE_GLOB_H)
|
check_include_file_cxx (glob.h HAVE_GLOB_H)
|
||||||
check_include_file_cxx (link.h HAVE_LINK_H)
|
check_include_file_cxx (memory.h HAVE_MEMORY_H)
|
||||||
check_include_file_cxx (pwd.h HAVE_PWD_H)
|
check_include_file_cxx (pwd.h HAVE_PWD_H)
|
||||||
check_include_file_cxx (sys/exec_elf.h HAVE_SYS_EXEC_ELF_H)
|
check_include_file_cxx (strings.h HAVE_STRINGS_H)
|
||||||
|
check_include_file_cxx (sys/stat.h HAVE_SYS_STAT_H)
|
||||||
check_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H)
|
check_include_file_cxx (sys/syscall.h HAVE_SYS_SYSCALL_H)
|
||||||
check_include_file_cxx (sys/time.h HAVE_SYS_TIME_H)
|
check_include_file_cxx (sys/time.h HAVE_SYS_TIME_H)
|
||||||
check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)
|
check_include_file_cxx (sys/types.h HAVE_SYS_TYPES_H)
|
||||||
@ -144,38 +121,93 @@ check_include_file_cxx (unistd.h HAVE_UNISTD_H)
|
|||||||
check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)
|
check_type_size (mode_t HAVE_MODE_T LANGUAGE CXX)
|
||||||
check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)
|
check_type_size (ssize_t HAVE_SSIZE_T LANGUAGE CXX)
|
||||||
|
|
||||||
check_cxx_symbol_exists (dladdr dlfcn.h HAVE_DLADDR)
|
check_function_exists (dladdr HAVE_DLADDR)
|
||||||
check_cxx_symbol_exists (fcntl fcntl.h HAVE_FCNTL)
|
check_function_exists (fcntl HAVE_FCNTL)
|
||||||
check_cxx_symbol_exists (posix_fadvise fcntl.h HAVE_POSIX_FADVISE)
|
check_function_exists (pread HAVE_PREAD)
|
||||||
check_cxx_symbol_exists (pread unistd.h HAVE_PREAD)
|
check_function_exists (pwrite HAVE_PWRITE)
|
||||||
check_cxx_symbol_exists (pwrite unistd.h HAVE_PWRITE)
|
check_function_exists (sigaction HAVE_SIGACTION)
|
||||||
check_cxx_symbol_exists (sigaction csignal HAVE_SIGACTION)
|
check_function_exists (sigaltstack HAVE_SIGALTSTACK)
|
||||||
check_cxx_symbol_exists (sigaltstack csignal HAVE_SIGALTSTACK)
|
|
||||||
|
|
||||||
check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
|
check_cxx_symbol_exists (backtrace execinfo.h HAVE_EXECINFO_BACKTRACE)
|
||||||
check_cxx_symbol_exists (backtrace_symbols execinfo.h
|
check_cxx_symbol_exists (backtrace_symbols execinfo.h
|
||||||
HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
||||||
check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)
|
check_cxx_symbol_exists (_chsize_s io.h HAVE__CHSIZE_S)
|
||||||
|
|
||||||
|
# NOTE gcc does not fail if you pass a non-existent -Wno-* option as an
|
||||||
|
# argument. However, it will happily fail if you pass the corresponding -W*
|
||||||
|
# option. So, we check whether options that disable warnings exist by testing
|
||||||
|
# the availability of the corresponding option that enables the warning. This
|
||||||
|
# eliminates the need to check for compiler for several (mainly Clang) options.
|
||||||
|
|
||||||
|
check_cxx_compiler_flag (-Wdeprecated HAVE_NO_DEPRECATED)
|
||||||
|
check_cxx_compiler_flag (-Wunnamed-type-template-args
|
||||||
|
HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
|
||||||
|
|
||||||
cmake_push_check_state (RESET)
|
cmake_push_check_state (RESET)
|
||||||
set (CMAKE_REQUIRED_LIBRARIES dbghelp)
|
|
||||||
check_cxx_symbol_exists (UnDecorateSymbolName "windows.h;dbghelp.h" HAVE_DBGHELP)
|
if (Threads_FOUND)
|
||||||
|
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
|
||||||
|
endif (Threads_FOUND)
|
||||||
|
|
||||||
|
check_cxx_symbol_exists (pthread_threadid_np "pthread.h" HAVE_PTHREAD_THREADID_NP)
|
||||||
cmake_pop_check_state ()
|
cmake_pop_check_state ()
|
||||||
|
|
||||||
if (WITH_FUZZING STREQUAL none)
|
# NOTE: Cannot use check_function_exists here since >=vc-14.0 can define
|
||||||
# Disable compiler demangler if fuzzing is active; we only want to use the
|
# snprintf as an inline function
|
||||||
# glog demangler then.
|
check_cxx_symbol_exists (snprintf cstdio HAVE_SNPRINTF)
|
||||||
check_cxx_symbol_exists (abi::__cxa_demangle cxxabi.h HAVE___CXA_DEMANGLE)
|
|
||||||
endif (WITH_FUZZING STREQUAL none)
|
|
||||||
|
|
||||||
check_cxx_symbol_exists (__argv cstdlib HAVE___ARGV)
|
check_library_exists (dbghelp UnDecorateSymbolName "" HAVE_DBGHELP)
|
||||||
check_cxx_symbol_exists (getprogname cstdlib HAVE_GETPROGNAME)
|
|
||||||
check_cxx_symbol_exists (program_invocation_short_name cerrno HAVE_PROGRAM_INVOCATION_SHORT_NAME)
|
check_cxx_source_compiles ("
|
||||||
check_cxx_source_compiles ([=[
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
extern char* __progname;
|
static void foo(void) __attribute__ ((unused));
|
||||||
int main() { return __progname != nullptr ? EXIT_SUCCESS : EXIT_FAILURE; }
|
int main(void) { return 0; }
|
||||||
]=] HAVE___PROGNAME)
|
" HAVE___ATTRIBUTE__)
|
||||||
|
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
#include <cstdlib>
|
||||||
|
static void foo(void) __attribute__ ((visibility(\"default\")));
|
||||||
|
int main(void) { return 0; }
|
||||||
|
" HAVE___ATTRIBUTE__VISIBILITY_DEFAULT)
|
||||||
|
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
#include <cstdlib>
|
||||||
|
static void foo(void) __attribute__ ((visibility(\"hidden\")));
|
||||||
|
int main(void) { return 0; }
|
||||||
|
" HAVE___ATTRIBUTE__VISIBILITY_HIDDEN)
|
||||||
|
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
int main(void) { if (__builtin_expect(0, 0)) return 1; return 0; }
|
||||||
|
" HAVE___BUILTIN_EXPECT)
|
||||||
|
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int a; if (__sync_val_compare_and_swap(&a, 0, 1)) return 1; return 0;
|
||||||
|
}
|
||||||
|
" HAVE___SYNC_VAL_COMPARE_AND_SWAP)
|
||||||
|
|
||||||
|
if (Threads_FOUND)
|
||||||
|
cmake_push_check_state (RESET)
|
||||||
|
set (CMAKE_REQUIRED_LIBRARIES Threads::Threads)
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
#define _XOPEN_SOURCE 500
|
||||||
|
#include <pthread.h>
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
pthread_rwlock_t l;
|
||||||
|
pthread_rwlock_init(&l, NULL);
|
||||||
|
pthread_rwlock_rdlock(&l);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
" HAVE_RWLOCK)
|
||||||
|
cmake_pop_check_state ()
|
||||||
|
endif (Threads_FOUND)
|
||||||
|
|
||||||
|
check_cxx_source_compiles ("
|
||||||
|
__declspec(selectany) int a;
|
||||||
|
int main(void) { return 0; }
|
||||||
|
" HAVE___DECLSPEC)
|
||||||
|
|
||||||
if (WITH_TLS)
|
if (WITH_TLS)
|
||||||
set (GLOG_THREAD_LOCAL_STORAGE 1)
|
set (GLOG_THREAD_LOCAL_STORAGE 1)
|
||||||
@ -238,6 +270,58 @@ if (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
|
|||||||
cmake_pop_check_state ()
|
cmake_pop_check_state ()
|
||||||
endif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
|
endif (HAVE_UCONTEXT_H AND NOT DEFINED PC_FROM_UCONTEXT)
|
||||||
|
|
||||||
|
set (GOOGLE_NAMESPACE google)
|
||||||
|
set (_START_GOOGLE_NAMESPACE_ "namespace ${GOOGLE_NAMESPACE} {")
|
||||||
|
set (_END_GOOGLE_NAMESPACE_ "}")
|
||||||
|
set (ac_cv_have_glog_export 1)
|
||||||
|
|
||||||
|
if (HAVE_LIB_GFLAGS)
|
||||||
|
set (ac_cv_have_libgflags 1)
|
||||||
|
else (HAVE_LIB_GFLAGS)
|
||||||
|
set (ac_cv_have_libgflags 0)
|
||||||
|
endif (HAVE_LIB_GFLAGS)
|
||||||
|
|
||||||
|
if (HAVE_SYS_TYPES_H)
|
||||||
|
set (ac_cv_have_systypes_h 1)
|
||||||
|
else (HAVE_SYS_TYPES_H)
|
||||||
|
set (ac_cv_have_systypes_h 0)
|
||||||
|
endif (HAVE_SYS_TYPES_H)
|
||||||
|
|
||||||
|
if (HAVE_SSIZE_T)
|
||||||
|
set (ac_cv_have_ssize_t 1)
|
||||||
|
else (HAVE_SSIZE_T)
|
||||||
|
set (ac_cv_have_ssize_t 0)
|
||||||
|
endif (HAVE_SSIZE_T)
|
||||||
|
|
||||||
|
if (HAVE_MODE_T)
|
||||||
|
set (ac_cv_have_mode_t 1)
|
||||||
|
else (HAVE_MODE_T)
|
||||||
|
set (ac_cv_have_mode_t 0)
|
||||||
|
endif (HAVE_MODE_T)
|
||||||
|
|
||||||
|
if (HAVE_UNISTD_H)
|
||||||
|
set (ac_cv_have_unistd_h 1)
|
||||||
|
else (HAVE_UNISTD_H)
|
||||||
|
set (ac_cv_have_unistd_h 0)
|
||||||
|
endif (HAVE_UNISTD_H)
|
||||||
|
|
||||||
|
set (ac_google_namespace ${GOOGLE_NAMESPACE})
|
||||||
|
set (ac_google_end_namespace ${_END_GOOGLE_NAMESPACE_})
|
||||||
|
set (ac_google_start_namespace ${_START_GOOGLE_NAMESPACE_})
|
||||||
|
|
||||||
|
if (HAVE___ATTRIBUTE__)
|
||||||
|
set (ac_cv___attribute___noinline "__attribute__((noinline))")
|
||||||
|
set (ac_cv___attribute___printf_4_5 "__attribute__((__format__(__printf__, 4, 5)))")
|
||||||
|
elseif (HAVE___DECLSPEC)
|
||||||
|
#set (ac_cv___attribute___noinline "__declspec(noinline)")
|
||||||
|
endif (HAVE___ATTRIBUTE__)
|
||||||
|
|
||||||
|
if (HAVE___BUILTIN_EXPECT)
|
||||||
|
set (ac_cv_have___builtin_expect 1)
|
||||||
|
else (HAVE___BUILTIN_EXPECT)
|
||||||
|
set (ac_cv_have___builtin_expect 0)
|
||||||
|
endif (HAVE___BUILTIN_EXPECT)
|
||||||
|
|
||||||
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
||||||
set (HAVE_STACKTRACE 1)
|
set (HAVE_STACKTRACE 1)
|
||||||
endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
endif (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS)
|
||||||
@ -278,12 +362,19 @@ if (WITH_SYMBOLIZE)
|
|||||||
if (HAVE_SYMBOLIZE)
|
if (HAVE_SYMBOLIZE)
|
||||||
set (HAVE_STACKTRACE 1)
|
set (HAVE_STACKTRACE 1)
|
||||||
endif (HAVE_SYMBOLIZE)
|
endif (HAVE_SYMBOLIZE)
|
||||||
|
elseif (UNIX)
|
||||||
|
cmake_push_check_state (RESET)
|
||||||
|
check_cxx_source_compiles ([=[
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
#ifndef __ELF__
|
||||||
|
#error __ELF__ not defined
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
]=] HAVE_SYMBOLIZE)
|
||||||
|
cmake_pop_check_state ()
|
||||||
elseif (APPLE AND HAVE_DLADDR)
|
elseif (APPLE AND HAVE_DLADDR)
|
||||||
set (HAVE_SYMBOLIZE 1)
|
set (HAVE_SYMBOLIZE 1)
|
||||||
elseif (UNIX)
|
|
||||||
if (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)
|
|
||||||
set (HAVE_SYMBOLIZE 1)
|
|
||||||
endif (HAVE_ELF_H OR HAVE_SYS_EXEC_ELF_H)
|
|
||||||
endif (WIN32 OR CYGWIN)
|
endif (WIN32 OR CYGWIN)
|
||||||
endif (WITH_SYMBOLIZE)
|
endif (WITH_SYMBOLIZE)
|
||||||
|
|
||||||
@ -291,23 +382,46 @@ endif (WITH_SYMBOLIZE)
|
|||||||
# building the library.
|
# building the library.
|
||||||
add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)
|
add_compile_definitions (GLOG_NO_SYMBOLIZE_DETECTION)
|
||||||
|
|
||||||
check_cxx_symbol_exists (gmtime_r "cstdlib;ctime" HAVE_GMTIME_R)
|
check_cxx_source_compiles ("
|
||||||
check_cxx_symbol_exists (localtime_r "cstdlib;ctime" HAVE_LOCALTIME_R)
|
#include <cstdlib>
|
||||||
|
#include <ctime>
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
time_t timep;
|
||||||
|
struct tm result;
|
||||||
|
localtime_r(&timep, &result);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
" HAVE_LOCALTIME_R)
|
||||||
|
|
||||||
set (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
set (SIZEOF_VOID_P ${CMAKE_SIZEOF_VOID_P})
|
||||||
|
|
||||||
|
if (WITH_THREADS AND Threads_FOUND)
|
||||||
|
if (CMAKE_USE_PTHREADS_INIT)
|
||||||
|
set (HAVE_PTHREAD 1)
|
||||||
|
endif (CMAKE_USE_PTHREADS_INIT)
|
||||||
|
else (WITH_THREADS AND Threads_FOUND)
|
||||||
|
set (NO_THREADS 1)
|
||||||
|
endif (WITH_THREADS AND Threads_FOUND)
|
||||||
|
|
||||||
# fopen/open on Cygwin can not handle unix-type paths like /home/....
|
# fopen/open on Cygwin can not handle unix-type paths like /home/....
|
||||||
# therefore we translate TEST_SRC_DIR to windows-path.
|
# therefore we translate TEST_SRC_DIR to windows-path.
|
||||||
if (CYGWIN)
|
if (CYGWIN)
|
||||||
execute_process (COMMAND cygpath.exe -m ${glog_SOURCE_DIR}
|
execute_process (COMMAND cygpath.exe -m ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
OUTPUT_VARIABLE TEST_SRC_DIR)
|
OUTPUT_VARIABLE TEST_SRC_DIR)
|
||||||
set (TEST_SRC_DIR \"${TEST_SRC_DIR}\")
|
set (TEST_SRC_DIR \"${TEST_SRC_DIR}\")
|
||||||
else (CYGWIN)
|
else (CYGWIN)
|
||||||
set (TEST_SRC_DIR \"${glog_SOURCE_DIR}\")
|
set (TEST_SRC_DIR \"${CMAKE_CURRENT_SOURCE_DIR}\")
|
||||||
endif (CYGWIN)
|
endif (CYGWIN)
|
||||||
|
|
||||||
configure_file (src/config.h.cmake.in config.h)
|
configure_file (src/config.h.cmake.in config.h)
|
||||||
|
configure_file (src/glog/logging.h.in glog/logging.h @ONLY)
|
||||||
|
configure_file (src/glog/raw_logging.h.in glog/raw_logging.h @ONLY)
|
||||||
|
configure_file (src/glog/stl_logging.h.in glog/stl_logging.h @ONLY)
|
||||||
|
configure_file (src/glog/vlog_is_on.h.in glog/vlog_is_on.h @ONLY)
|
||||||
|
|
||||||
|
add_compile_options ($<$<AND:$<BOOL:${HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS}>,$<NOT:$<CXX_COMPILER_ID:GNU>>>:-Wno-unnamed-type-template-args>)
|
||||||
|
|
||||||
set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})
|
set (_glog_CMake_BINDIR ${CMAKE_INSTALL_BINDIR})
|
||||||
set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
set (_glog_CMake_INCLUDE_DIR ${CMAKE_INSTALL_INCLUDEDIR})
|
||||||
@ -317,14 +431,14 @@ set (_glog_CMake_INSTALLDIR ${_glog_CMake_LIBDIR}/cmake/glog)
|
|||||||
set (_glog_CMake_DIR glog/cmake)
|
set (_glog_CMake_DIR glog/cmake)
|
||||||
set (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR})
|
set (_glog_CMake_DATADIR ${CMAKE_INSTALL_DATAROOTDIR}/${_glog_CMake_DIR})
|
||||||
set (_glog_BINARY_CMake_DATADIR
|
set (_glog_BINARY_CMake_DATADIR
|
||||||
${glog_BINARY_DIR}/${_glog_CMake_DATADIR})
|
${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
|
||||||
|
|
||||||
# Add additional CMake find modules here.
|
# Add additional CMake find modules here.
|
||||||
set (_glog_CMake_MODULES)
|
set (_glog_CMake_MODULES)
|
||||||
|
|
||||||
if (Unwind_FOUND)
|
if (Unwind_FOUND)
|
||||||
# Copy the module only if libunwind is actually used.
|
# Copy the module only if libunwind is actually used.
|
||||||
list (APPEND _glog_CMake_MODULES ${glog_SOURCE_DIR}/cmake/FindUnwind.cmake)
|
list (APPEND _glog_CMake_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/cmake/FindUnwind.cmake)
|
||||||
endif (Unwind_FOUND)
|
endif (Unwind_FOUND)
|
||||||
|
|
||||||
# Generate file name for each module in the binary directory
|
# Generate file name for each module in the binary directory
|
||||||
@ -348,29 +462,25 @@ if (_glog_CMake_MODULES)
|
|||||||
endif (_glog_CMake_MODULES)
|
endif (_glog_CMake_MODULES)
|
||||||
|
|
||||||
set (GLOG_PUBLIC_H
|
set (GLOG_PUBLIC_H
|
||||||
${glog_BINARY_DIR}/glog/export.h
|
${CMAKE_CURRENT_BINARY_DIR}/glog/export.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/glog/logging.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/glog/raw_logging.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/glog/stl_logging.h
|
||||||
|
${CMAKE_CURRENT_BINARY_DIR}/glog/vlog_is_on.h
|
||||||
src/glog/log_severity.h
|
src/glog/log_severity.h
|
||||||
src/glog/logging.h
|
|
||||||
src/glog/platform.h
|
src/glog/platform.h
|
||||||
src/glog/raw_logging.h
|
|
||||||
src/glog/stl_logging.h
|
|
||||||
src/glog/types.h
|
|
||||||
src/glog/flags.h
|
|
||||||
src/glog/vlog_is_on.h
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set (GLOG_SRCS
|
set (GLOG_SRCS
|
||||||
${GLOG_PUBLIC_H}
|
${GLOG_PUBLIC_H}
|
||||||
src/base/commandlineflags.h
|
src/base/commandlineflags.h
|
||||||
src/base/googleinit.h
|
src/base/googleinit.h
|
||||||
|
src/base/mutex.h
|
||||||
src/demangle.cc
|
src/demangle.cc
|
||||||
src/demangle.h
|
src/demangle.h
|
||||||
src/flags.cc
|
|
||||||
src/logging.cc
|
src/logging.cc
|
||||||
src/raw_logging.cc
|
src/raw_logging.cc
|
||||||
src/signalhandler.cc
|
src/signalhandler.cc
|
||||||
src/stacktrace.cc
|
|
||||||
src/stacktrace.h
|
|
||||||
src/symbolize.cc
|
src/symbolize.cc
|
||||||
src/symbolize.h
|
src/symbolize.h
|
||||||
src/utilities.cc
|
src/utilities.cc
|
||||||
@ -378,14 +488,12 @@ set (GLOG_SRCS
|
|||||||
src/vlog_is_on.cc
|
src/vlog_is_on.cc
|
||||||
)
|
)
|
||||||
|
|
||||||
# NOTE MSYS2 defines both WIN32 and UNIX. Do not use windows port in this case.
|
if (CYGWIN OR WIN32)
|
||||||
if ((CYGWIN OR WIN32) AND NOT UNIX)
|
|
||||||
list (APPEND GLOG_SRCS
|
list (APPEND GLOG_SRCS
|
||||||
src/windows/port.cc
|
src/windows/port.cc
|
||||||
src/windows/port.h
|
src/windows/port.h
|
||||||
)
|
)
|
||||||
set (_glog_USE_WINDOWS_PORT TRUE)
|
endif (CYGWIN OR WIN32)
|
||||||
endif ((CYGWIN OR WIN32) AND NOT UNIX)
|
|
||||||
|
|
||||||
add_library (glog_internal OBJECT
|
add_library (glog_internal OBJECT
|
||||||
${_glog_BINARY_CMake_MODULES}
|
${_glog_BINARY_CMake_MODULES}
|
||||||
@ -413,26 +521,6 @@ add_library (glog::glog ALIAS glog)
|
|||||||
|
|
||||||
set (glog_libraries_options_for_static_linking)
|
set (glog_libraries_options_for_static_linking)
|
||||||
|
|
||||||
# CMake always uses the generated export header
|
|
||||||
target_compile_definitions (glog PUBLIC GLOG_USE_GLOG_EXPORT)
|
|
||||||
|
|
||||||
if (_glog_USE_WINDOWS_PORT)
|
|
||||||
target_compile_definitions (glog PRIVATE GLOG_USE_WINDOWS_PORT)
|
|
||||||
endif (_glog_USE_WINDOWS_PORT)
|
|
||||||
|
|
||||||
unset (_glog_USE_WINDOWS_PORT)
|
|
||||||
|
|
||||||
if (WIN32)
|
|
||||||
# Do not define min and max as macros
|
|
||||||
target_compile_definitions (glog PRIVATE NOMINMAX)
|
|
||||||
# Exclude unnecessary funcitonality
|
|
||||||
target_compile_definitions (glog PRIVATE WIN32_LEAN_AND_MEAN)
|
|
||||||
endif (WIN32)
|
|
||||||
|
|
||||||
if (HAVE_LIB_GFLAGS)
|
|
||||||
target_compile_definitions (glog PUBLIC GLOG_USE_GFLAGS)
|
|
||||||
endif (HAVE_LIB_GFLAGS)
|
|
||||||
|
|
||||||
if (Unwind_FOUND)
|
if (Unwind_FOUND)
|
||||||
target_link_libraries (glog PRIVATE unwind::unwind)
|
target_link_libraries (glog PRIVATE unwind::unwind)
|
||||||
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind")
|
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -lunwind")
|
||||||
@ -444,11 +532,13 @@ if (HAVE_DBGHELP)
|
|||||||
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp")
|
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -ldbghelp")
|
||||||
endif (HAVE_DBGHELP)
|
endif (HAVE_DBGHELP)
|
||||||
|
|
||||||
target_link_libraries (glog PRIVATE Threads::Threads)
|
if (HAVE_PTHREAD)
|
||||||
|
target_link_libraries (glog PRIVATE ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
|
||||||
if (CMAKE_THREAD_LIBS_INIT)
|
if (CMAKE_THREAD_LIBS_INIT)
|
||||||
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}")
|
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} ${CMAKE_THREAD_LIBS_INIT}")
|
||||||
endif (CMAKE_THREAD_LIBS_INIT)
|
endif (CMAKE_THREAD_LIBS_INIT)
|
||||||
|
endif (HAVE_PTHREAD)
|
||||||
|
|
||||||
if (gflags_FOUND)
|
if (gflags_FOUND)
|
||||||
# Prefer the gflags target that uses double colon convention
|
# Prefer the gflags target that uses double colon convention
|
||||||
@ -466,8 +556,8 @@ if (ANDROID)
|
|||||||
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -llog")
|
set (glog_libraries_options_for_static_linking "${glog_libraries_options_for_static_linking} -llog")
|
||||||
endif (ANDROID)
|
endif (ANDROID)
|
||||||
|
|
||||||
set_target_properties (glog PROPERTIES VERSION ${glog_VERSION})
|
set_target_properties (glog PROPERTIES VERSION ${PROJECT_VERSION})
|
||||||
set_target_properties (glog PROPERTIES SOVERSION 3)
|
set_target_properties (glog PROPERTIES SOVERSION 1)
|
||||||
|
|
||||||
if (CYGWIN OR WIN32)
|
if (CYGWIN OR WIN32)
|
||||||
target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)
|
target_compile_definitions (glog PUBLIC GLOG_NO_ABBREVIATED_SEVERITIES)
|
||||||
@ -476,20 +566,20 @@ endif (CYGWIN OR WIN32)
|
|||||||
set_target_properties (glog PROPERTIES PUBLIC_HEADER "${GLOG_PUBLIC_H}")
|
set_target_properties (glog PROPERTIES PUBLIC_HEADER "${GLOG_PUBLIC_H}")
|
||||||
|
|
||||||
target_include_directories (glog BEFORE PUBLIC
|
target_include_directories (glog BEFORE PUBLIC
|
||||||
"$<BUILD_INTERFACE:${glog_BINARY_DIR}>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>"
|
||||||
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src>"
|
||||||
"$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>"
|
"$<INSTALL_INTERFACE:${_glog_CMake_INCLUDE_DIR}>"
|
||||||
PRIVATE ${glog_BINARY_DIR}
|
PRIVATE ${CMAKE_CURRENT_BINARY_DIR}
|
||||||
PRIVATE ${glog_SOURCE_DIR}/src)
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src)
|
||||||
|
|
||||||
if (CYGWIN OR WIN32)
|
if (CYGWIN OR WIN32)
|
||||||
target_include_directories (glog_internal PUBLIC
|
target_include_directories (glog_internal PUBLIC
|
||||||
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
|
||||||
PRIVATE ${glog_SOURCE_DIR}/src/windows)
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
|
||||||
|
|
||||||
target_include_directories (glog PUBLIC
|
target_include_directories (glog PUBLIC
|
||||||
"$<BUILD_INTERFACE:${glog_SOURCE_DIR}/src/windows>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/src/windows>"
|
||||||
PRIVATE ${glog_SOURCE_DIR}/src/windows)
|
PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/windows)
|
||||||
endif (CYGWIN OR WIN32)
|
endif (CYGWIN OR WIN32)
|
||||||
|
|
||||||
set_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)
|
set_target_properties (glog PROPERTIES DEFINE_SYMBOL GOOGLE_GLOG_IS_A_DLL)
|
||||||
@ -502,20 +592,20 @@ target_compile_definitions (glog_internal PUBLIC
|
|||||||
|
|
||||||
generate_export_header (glog
|
generate_export_header (glog
|
||||||
EXPORT_MACRO_NAME GLOG_EXPORT
|
EXPORT_MACRO_NAME GLOG_EXPORT
|
||||||
EXPORT_FILE_NAME ${glog_BINARY_DIR}/glog/export.h)
|
EXPORT_FILE_NAME ${CMAKE_CURRENT_BINARY_DIR}/glog/export.h)
|
||||||
|
|
||||||
string (STRIP "${glog_libraries_options_for_static_linking}" glog_libraries_options_for_static_linking)
|
string (STRIP "${glog_libraries_options_for_static_linking}" glog_libraries_options_for_static_linking)
|
||||||
|
|
||||||
if (WITH_PKGCONFIG)
|
if (WITH_PKGCONFIG)
|
||||||
set (VERSION ${glog_VERSION})
|
set (VERSION ${PROJECT_VERSION})
|
||||||
set (prefix ${CMAKE_INSTALL_PREFIX})
|
set (prefix ${CMAKE_INSTALL_PREFIX})
|
||||||
set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR})
|
set (exec_prefix ${CMAKE_INSTALL_FULL_BINDIR})
|
||||||
set (libdir ${CMAKE_INSTALL_FULL_LIBDIR})
|
set (libdir ${CMAKE_INSTALL_FULL_LIBDIR})
|
||||||
set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
|
set (includedir ${CMAKE_INSTALL_FULL_INCLUDEDIR})
|
||||||
|
|
||||||
configure_file (
|
configure_file (
|
||||||
"${glog_SOURCE_DIR}/libglog.pc.in"
|
"${PROJECT_SOURCE_DIR}/libglog.pc.in"
|
||||||
"${glog_BINARY_DIR}/libglog.pc"
|
"${PROJECT_BINARY_DIR}/libglog.pc"
|
||||||
@ONLY
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -570,6 +660,16 @@ if (BUILD_TESTING)
|
|||||||
|
|
||||||
target_link_libraries (stl_logging_unittest PRIVATE glog_test)
|
target_link_libraries (stl_logging_unittest PRIVATE glog_test)
|
||||||
|
|
||||||
|
if (HAVE_NO_DEPRECATED)
|
||||||
|
set_property (TARGET stl_logging_unittest APPEND PROPERTY COMPILE_OPTIONS
|
||||||
|
-Wno-deprecated)
|
||||||
|
endif (HAVE_NO_DEPRECATED)
|
||||||
|
|
||||||
|
if (HAVE_EXT_SLIST)
|
||||||
|
target_compile_definitions (stl_logging_unittest PRIVATE
|
||||||
|
GLOG_STL_LOGGING_FOR_EXT_SLIST)
|
||||||
|
endif (HAVE_EXT_SLIST)
|
||||||
|
|
||||||
if (HAVE_SYMBOLIZE)
|
if (HAVE_SYMBOLIZE)
|
||||||
add_executable (symbolize_unittest
|
add_executable (symbolize_unittest
|
||||||
src/symbolize_unittest.cc
|
src/symbolize_unittest.cc
|
||||||
@ -584,13 +684,6 @@ if (BUILD_TESTING)
|
|||||||
|
|
||||||
target_link_libraries (demangle_unittest PRIVATE glog_test)
|
target_link_libraries (demangle_unittest PRIVATE glog_test)
|
||||||
|
|
||||||
add_test (NAME demangle COMMAND demangle_unittest)
|
|
||||||
|
|
||||||
if (HAVE___CXA_DEMANGLE)
|
|
||||||
# Demangle tests use a different (reduced) representation of symbols
|
|
||||||
set_tests_properties (demangle PROPERTIES DISABLED ON)
|
|
||||||
endif (HAVE___CXA_DEMANGLE)
|
|
||||||
|
|
||||||
if (HAVE_STACKTRACE)
|
if (HAVE_STACKTRACE)
|
||||||
add_executable (stacktrace_unittest
|
add_executable (stacktrace_unittest
|
||||||
src/stacktrace_unittest.cc
|
src/stacktrace_unittest.cc
|
||||||
@ -613,6 +706,7 @@ if (BUILD_TESTING)
|
|||||||
target_link_libraries (signalhandler_unittest PRIVATE glog_test)
|
target_link_libraries (signalhandler_unittest PRIVATE glog_test)
|
||||||
endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
|
endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
|
||||||
|
|
||||||
|
add_test (NAME demangle COMMAND demangle_unittest)
|
||||||
add_test (NAME logging COMMAND logging_unittest)
|
add_test (NAME logging COMMAND logging_unittest)
|
||||||
|
|
||||||
set_tests_properties (logging PROPERTIES TIMEOUT 30)
|
set_tests_properties (logging PROPERTIES TIMEOUT 30)
|
||||||
@ -665,15 +759,15 @@ if (BUILD_TESTING)
|
|||||||
get_cache_variables (_CACHEVARS)
|
get_cache_variables (_CACHEVARS)
|
||||||
|
|
||||||
set (_INITIAL_CACHE
|
set (_INITIAL_CACHE
|
||||||
${glog_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake)
|
${CMAKE_CURRENT_BINARY_DIR}/test_package_config/glog_package_config_initial_cache.cmake)
|
||||||
|
|
||||||
# Package config test
|
# Package config test
|
||||||
|
|
||||||
add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND}
|
add_test (NAME cmake_package_config_init COMMAND ${CMAKE_COMMAND}
|
||||||
-DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config
|
-DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config
|
||||||
-DINITIAL_CACHE=${_INITIAL_CACHE}
|
-DINITIAL_CACHE=${_INITIAL_CACHE}
|
||||||
-DCACHEVARS=${_CACHEVARS}
|
-DCACHEVARS=${_CACHEVARS}
|
||||||
-P ${glog_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestInitPackageConfig.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND}
|
add_test (NAME cmake_package_config_generate COMMAND ${CMAKE_COMMAND}
|
||||||
@ -681,21 +775,21 @@ if (BUILD_TESTING)
|
|||||||
-DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
-DGENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
||||||
-DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
-DGENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
||||||
-DINITIAL_CACHE=${_INITIAL_CACHE}
|
-DINITIAL_CACHE=${_INITIAL_CACHE}
|
||||||
-DPACKAGE_DIR=${glog_BINARY_DIR}
|
-DPACKAGE_DIR=${CMAKE_CURRENT_BINARY_DIR}
|
||||||
-DPATH=$ENV{PATH}
|
-DPATH=$ENV{PATH}
|
||||||
-DSOURCE_DIR=${glog_SOURCE_DIR}/src/package_config_unittest/working_config
|
-DSOURCE_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/package_config_unittest/working_config
|
||||||
-DTEST_BINARY_DIR=${glog_BINARY_DIR}/test_package_config/working_config
|
-DTEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
|
||||||
-P ${glog_SOURCE_DIR}/cmake/TestPackageConfig.cmake
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/TestPackageConfig.cmake
|
||||||
)
|
)
|
||||||
|
|
||||||
add_test (NAME cmake_package_config_build COMMAND
|
add_test (NAME cmake_package_config_build COMMAND
|
||||||
${CMAKE_COMMAND} --build ${glog_BINARY_DIR}/test_package_config/working_config
|
${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/test_package_config/working_config
|
||||||
--config $<CONFIG>
|
--config $<CONFIG>
|
||||||
)
|
)
|
||||||
|
|
||||||
add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E
|
add_test (NAME cmake_package_config_cleanup COMMAND ${CMAKE_COMMAND} -E
|
||||||
remove_directory
|
remove_directory
|
||||||
${glog_BINARY_DIR}/test_package_config
|
${CMAKE_CURRENT_BINARY_DIR}/test_package_config
|
||||||
)
|
)
|
||||||
|
|
||||||
# Fixtures setup
|
# Fixtures setup
|
||||||
@ -729,7 +823,7 @@ if (BUILD_TESTING)
|
|||||||
|
|
||||||
target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE glog_test)
|
target_link_libraries (cleanup_with_relative_prefix_unittest PRIVATE glog_test)
|
||||||
|
|
||||||
set (CLEANUP_LOG_DIR ${glog_BINARY_DIR}/cleanup_tests)
|
set (CLEANUP_LOG_DIR ${CMAKE_CURRENT_BINARY_DIR}/cleanup_tests)
|
||||||
|
|
||||||
add_test (NAME cleanup_init COMMAND
|
add_test (NAME cleanup_init COMMAND
|
||||||
${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR})
|
${CMAKE_COMMAND} -E make_directory ${CLEANUP_LOG_DIR})
|
||||||
@ -740,21 +834,21 @@ if (BUILD_TESTING)
|
|||||||
-DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest>
|
-DLOGCLEANUP=$<TARGET_FILE:cleanup_immediately_unittest>
|
||||||
# NOTE The trailing slash is important
|
# NOTE The trailing slash is important
|
||||||
-DTEST_DIR=${CLEANUP_LOG_DIR}/
|
-DTEST_DIR=${CLEANUP_LOG_DIR}/
|
||||||
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest1.cmake
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest1.cmake
|
||||||
WORKING_DIRECTORY ${glog_BINARY_DIR})
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
add_test (NAME cleanup_with_absolute_prefix COMMAND
|
add_test (NAME cleanup_with_absolute_prefix COMMAND
|
||||||
${CMAKE_COMMAND}
|
${CMAKE_COMMAND}
|
||||||
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest>
|
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_absolute_prefix_unittest>
|
||||||
-DTEST_DIR=${glog_BINARY_DIR}/
|
-DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
|
||||||
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest2.cmake
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest2.cmake
|
||||||
WORKING_DIRECTORY ${glog_BINARY_DIR})
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
add_test (NAME cleanup_with_relative_prefix COMMAND
|
add_test (NAME cleanup_with_relative_prefix COMMAND
|
||||||
${CMAKE_COMMAND}
|
${CMAKE_COMMAND}
|
||||||
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest>
|
-DLOGCLEANUP=$<TARGET_FILE:cleanup_with_relative_prefix_unittest>
|
||||||
-DTEST_DIR=${glog_BINARY_DIR}/
|
-DTEST_DIR=${CMAKE_CURRENT_BINARY_DIR}/
|
||||||
-DTEST_SUBDIR=test_subdir/
|
-DTEST_SUBDIR=test_subdir/
|
||||||
-P ${glog_SOURCE_DIR}/cmake/RunCleanerTest3.cmake
|
-P ${CMAKE_CURRENT_SOURCE_DIR}/cmake/RunCleanerTest3.cmake
|
||||||
WORKING_DIRECTORY ${glog_BINARY_DIR})
|
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
# Fixtures setup
|
# Fixtures setup
|
||||||
set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest)
|
set_tests_properties (cleanup_init PROPERTIES FIXTURES_SETUP logcleanuptest)
|
||||||
@ -764,208 +858,8 @@ if (BUILD_TESTING)
|
|||||||
set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
set_tests_properties (cleanup_immediately PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
||||||
set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
set_tests_properties (cleanup_with_absolute_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
||||||
set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
set_tests_properties (cleanup_with_relative_prefix PROPERTIES FIXTURES_REQUIRED logcleanuptest)
|
||||||
|
|
||||||
add_executable (striplog0_unittest
|
|
||||||
src/striplog_unittest.cc
|
|
||||||
)
|
|
||||||
target_compile_definitions (striplog0_unittest PRIVATE GOOGLE_STRIP_LOG=0)
|
|
||||||
target_link_libraries (striplog0_unittest PRIVATE glog_test)
|
|
||||||
|
|
||||||
add_test (NAME striplog0 COMMAND striplog0_unittest)
|
|
||||||
|
|
||||||
add_executable (striplog2_unittest
|
|
||||||
src/striplog_unittest.cc
|
|
||||||
)
|
|
||||||
target_compile_definitions (striplog2_unittest PRIVATE GOOGLE_STRIP_LOG=2)
|
|
||||||
target_link_libraries (striplog2_unittest PRIVATE glog_test)
|
|
||||||
|
|
||||||
add_test (NAME striplog2 COMMAND striplog2_unittest)
|
|
||||||
|
|
||||||
add_executable (striplog10_unittest
|
|
||||||
src/striplog_unittest.cc
|
|
||||||
)
|
|
||||||
target_compile_definitions (striplog10_unittest PRIVATE GOOGLE_STRIP_LOG=10)
|
|
||||||
target_link_libraries (striplog10_unittest PRIVATE glog_test)
|
|
||||||
|
|
||||||
add_test (NAME striplog10 COMMAND striplog10_unittest)
|
|
||||||
|
|
||||||
set_tests_properties (
|
|
||||||
striplog0
|
|
||||||
striplog2
|
|
||||||
striplog10
|
|
||||||
PROPERTIES WILL_FAIL ON
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME log_severity_constants COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/log_severity_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/log_severity_constants"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_log_severity_constants
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
set_tests_properties (log_severity_constants PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "COMPACT_GOOGLE_LOG_[1-3]"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME log_severity_conversion COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/log_severity_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/log_severity_conversion"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_log_severity_conversion
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
if (CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
set_tests_properties (log_severity_conversion PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "error: invalid conversion from (‘|')int(’|')"
|
|
||||||
)
|
|
||||||
elseif (CMAKE_CXX_COMPILER_ID MATCHES Clang)
|
|
||||||
set_tests_properties (log_severity_conversion PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "no known conversion from 'int'"
|
|
||||||
)
|
|
||||||
elseif (MSVC)
|
|
||||||
set_tests_properties (log_severity_conversion PROPERTIES
|
|
||||||
PASS_REGULAR_EXPRESSION "error C2440"
|
|
||||||
)
|
|
||||||
else (CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
message (AUTHOR_WARNING
|
|
||||||
"Unsupported C++ compiler ${CMAKE_CXX_COMPILER_ID}: "
|
|
||||||
"log_severity_conversion test will be disabled"
|
|
||||||
)
|
|
||||||
set_tests_properties (log_severity_conversion DISABLED ON)
|
|
||||||
endif (CMAKE_COMPILER_IS_GNUCXX)
|
|
||||||
|
|
||||||
add_test (NAME includes_logging COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/includes_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/includes_logging"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_includes_logging
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME includes_vlog_is_on COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/includes_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/includes_vlog_is_on"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_includes_vlog_is_on
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME includes_raw_logging COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/includes_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/includes_raw_logging"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_includes_raw_logging
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME includes_stl_logging COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config $<CONFIG>
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/includes_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/includes_stl_logging"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_includes_stl_logging
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_BUILD_TYPE=$<CONFIG>
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM}
|
|
||||||
-DCMAKE_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET}
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME dcheck_on COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config Debug
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/dcheck_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/dcheck_on"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
|
|
||||||
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_dcheck
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
--test-command glog_dcheck
|
|
||||||
)
|
|
||||||
set_tests_properties (dcheck_on PROPERTIES
|
|
||||||
DISABLED $<NOT:$<CONFIG:Debug,RelWithDebInfo>>
|
|
||||||
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>"
|
|
||||||
PASS_REGULAR_EXPRESSION "Assert failed: false"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_test (NAME dcheck_off COMMAND ${CMAKE_CTEST_COMMAND}
|
|
||||||
--build-config Release
|
|
||||||
--build-and-test
|
|
||||||
"${glog_SOURCE_DIR}/src/dcheck_unittest"
|
|
||||||
"${glog_BINARY_DIR}/Tests/dcheck_off"
|
|
||||||
--build-generator ${CMAKE_GENERATOR}
|
|
||||||
--build-generator-platform "${CMAKE_GENERATOR_PLATFORM}"
|
|
||||||
--build-generator-toolset "${CMAKE_GENERATOR_TOOLSET}"
|
|
||||||
--build-makeprogram ${CMAKE_MAKE_PROGRAM}
|
|
||||||
--build-target glog_dcheck
|
|
||||||
--build-options
|
|
||||||
-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}
|
|
||||||
-DCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRY=ON
|
|
||||||
-Dglog_DIR=${glog_BINARY_DIR}
|
|
||||||
--test-command glog_dcheck
|
|
||||||
)
|
|
||||||
# There should be no output
|
|
||||||
set_tests_properties (dcheck_off PROPERTIES
|
|
||||||
DISABLED $<NOT:$<CONFIG:Release,MinSizeRel>>
|
|
||||||
ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$<TARGET_FILE_DIR:glog>"
|
|
||||||
PASS_REGULAR_EXPRESSION ""
|
|
||||||
)
|
|
||||||
endif (BUILD_TESTING)
|
endif (BUILD_TESTING)
|
||||||
|
|
||||||
if (BUILD_EXAMPLES)
|
|
||||||
add_executable (custom_sink_example examples/custom_sink.cc)
|
|
||||||
target_link_libraries (custom_sink_example PRIVATE glog::glog)
|
|
||||||
endif (BUILD_EXAMPLES)
|
|
||||||
|
|
||||||
install (TARGETS glog
|
install (TARGETS glog
|
||||||
EXPORT glog-targets
|
EXPORT glog-targets
|
||||||
RUNTIME DESTINATION ${_glog_CMake_BINDIR}
|
RUNTIME DESTINATION ${_glog_CMake_BINDIR}
|
||||||
@ -975,7 +869,7 @@ install (TARGETS glog
|
|||||||
|
|
||||||
if (WITH_PKGCONFIG)
|
if (WITH_PKGCONFIG)
|
||||||
install (
|
install (
|
||||||
FILES "${glog_BINARY_DIR}/libglog.pc"
|
FILES "${PROJECT_BINARY_DIR}/libglog.pc"
|
||||||
DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig"
|
DESTINATION "${_glog_CMake_LIBDIR}/pkgconfig"
|
||||||
)
|
)
|
||||||
endif (WITH_PKGCONFIG)
|
endif (WITH_PKGCONFIG)
|
||||||
@ -996,12 +890,12 @@ if (gflags_FOUND)
|
|||||||
endif (gflags_FOUND)
|
endif (gflags_FOUND)
|
||||||
|
|
||||||
configure_package_config_file (glog-config.cmake.in
|
configure_package_config_file (glog-config.cmake.in
|
||||||
${glog_BINARY_DIR}/glog-config.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
|
||||||
INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR}
|
INSTALL_DESTINATION ${_glog_CMake_INSTALLDIR}
|
||||||
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
|
||||||
|
|
||||||
write_basic_package_version_file (
|
write_basic_package_version_file (
|
||||||
${glog_BINARY_DIR}/glog-config-version.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
|
||||||
COMPATIBILITY SameMajorVersion)
|
COMPATIBILITY SameMajorVersion)
|
||||||
|
|
||||||
export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)
|
export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)
|
||||||
@ -1019,10 +913,10 @@ get_filename_component (glog_REL_CMake_DATADIR ${glog_REL_CMake_MODULES}
|
|||||||
DIRECTORY)
|
DIRECTORY)
|
||||||
|
|
||||||
set (glog_FULL_CMake_DATADIR
|
set (glog_FULL_CMake_DATADIR
|
||||||
${glog_BINARY_DIR}/${_glog_CMake_DATADIR})
|
${CMAKE_CURRENT_BINARY_DIR}/${_glog_CMake_DATADIR})
|
||||||
|
|
||||||
configure_file (glog-modules.cmake.in
|
configure_file (glog-modules.cmake.in
|
||||||
${glog_BINARY_DIR}/glog-modules.cmake @ONLY)
|
${CMAKE_CURRENT_BINARY_DIR}/glog-modules.cmake @ONLY)
|
||||||
|
|
||||||
install (CODE
|
install (CODE
|
||||||
"
|
"
|
||||||
@ -1033,10 +927,10 @@ if (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
|
|||||||
set (glog_DATADIR_DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${glog_DATADIR_DESTINATION}\")
|
set (glog_DATADIR_DESTINATION \"\${CMAKE_INSTALL_PREFIX}/\${glog_DATADIR_DESTINATION}\")
|
||||||
endif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
|
endif (NOT IS_ABSOLUTE ${_glog_CMake_INSTALLDIR})
|
||||||
|
|
||||||
configure_file (\"${glog_SOURCE_DIR}/glog-modules.cmake.in\"
|
configure_file (\"${CMAKE_CURRENT_SOURCE_DIR}/glog-modules.cmake.in\"
|
||||||
\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" @ONLY)
|
\"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\" @ONLY)
|
||||||
file (INSTALL
|
file (INSTALL
|
||||||
\"${glog_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\"
|
\"${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/glog-modules.cmake\"
|
||||||
DESTINATION
|
DESTINATION
|
||||||
\"\${glog_DATADIR_DESTINATION}\")
|
\"\${glog_DATADIR_DESTINATION}\")
|
||||||
"
|
"
|
||||||
@ -1044,8 +938,8 @@ file (INSTALL
|
|||||||
)
|
)
|
||||||
|
|
||||||
install (FILES
|
install (FILES
|
||||||
${glog_BINARY_DIR}/glog-config.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
|
||||||
${glog_BINARY_DIR}/glog-config-version.cmake
|
${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
|
||||||
DESTINATION ${_glog_CMake_INSTALLDIR})
|
DESTINATION ${_glog_CMake_INSTALLDIR})
|
||||||
|
|
||||||
# Find modules in share/glog/cmake
|
# Find modules in share/glog/cmake
|
||||||
|
|||||||
65
COPYING
Normal file
65
COPYING
Normal 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.
|
||||||
10
ChangeLog
10
ChangeLog
@ -1,13 +1,3 @@
|
|||||||
2024-06-08 Google Inc. <opensource@google.com>
|
|
||||||
|
|
||||||
* google-glog: version 0.7.1.
|
|
||||||
* See git log for the details.
|
|
||||||
|
|
||||||
2024-02-17 Google Inc. <opensource@google.com>
|
|
||||||
|
|
||||||
* google-glog: version 0.7.0.
|
|
||||||
* See git log for the details.
|
|
||||||
|
|
||||||
2022-04-05 Google Inc. <opensource@google.com>
|
2022-04-05 Google Inc. <opensource@google.com>
|
||||||
|
|
||||||
* google-glog: version 0.6.0.
|
* google-glog: version 0.6.0.
|
||||||
|
|||||||
27
LICENSE.md
27
LICENSE.md
@ -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.
|
|
||||||
13
MODULE.bazel
13
MODULE.bazel
@ -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")
|
|
||||||
869
README.rst
869
README.rst
@ -7,10 +7,877 @@ Google Logging (glog) is a C++14 library that implements application-level
|
|||||||
logging. The library provides logging APIs based on C++-style streams and
|
logging. The library provides logging APIs based on C++-style streams and
|
||||||
various helper macros.
|
various helper macros.
|
||||||
|
|
||||||
|
.. role:: cmake(code)
|
||||||
|
:language: cmake
|
||||||
|
|
||||||
|
.. role:: cmd(code)
|
||||||
|
:language: bash
|
||||||
|
|
||||||
|
.. role:: cpp(code)
|
||||||
|
:language: cpp
|
||||||
|
|
||||||
|
.. role:: bazel(code)
|
||||||
|
:language: starlark
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
Getting Started
|
||||||
---------------
|
---------------
|
||||||
|
|
||||||
Please refer to project's `documentation <https://google.github.io/glog/>`_.
|
You can log a message by simply streaming things to ``LOG``\ (<a
|
||||||
|
particular `severity level <#severity-levels>`__>), e.g.,
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
#include <glog/logging.h>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[]) {
|
||||||
|
// Initialize Google’s 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. Here’s 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 don’t have CMake installed already, you can
|
||||||
|
download it for from CMake’s `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 glog’s 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 isn’t 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 won’t change the log destination. If you want to set this
|
||||||
|
// value, you should do this before google::InitGoogleLogging .
|
||||||
|
FLAGS_log_dir = "/some/log/directory";
|
||||||
|
LOG(INFO) << "the same file";
|
||||||
|
|
||||||
|
Conditional / Occasional Logging
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Sometimes, you may only want to log a message under certain conditions.
|
||||||
|
You can use the following macros to perform conditional logging:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
|
||||||
|
|
||||||
|
The "Got lots of cookies" message is logged only when the variable
|
||||||
|
``num_cookies`` exceeds 10. If a line of code is executed many times, it
|
||||||
|
may be useful to only log a message at certain intervals. This kind of
|
||||||
|
logging is most useful for informational messages.
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
|
||||||
|
|
||||||
|
The above line outputs a log messages on the 1st, 11th, 21st, ... times
|
||||||
|
it is executed. Note that the special ``google::COUNTER`` value is used
|
||||||
|
to identify which repetition is happening.
|
||||||
|
|
||||||
|
You can combine conditional and occasional logging with the following
|
||||||
|
macro.
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_IF_EVERY_N(INFO, (size > 1024), 10) << "Got the " << google::COUNTER
|
||||||
|
<< "th big cookie";
|
||||||
|
|
||||||
|
Instead of outputting a message every nth time, you can also limit the
|
||||||
|
output to the first n occurrences:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_FIRST_N(INFO, 20) << "Got the " << google::COUNTER << "th cookie";
|
||||||
|
|
||||||
|
Outputs log messages for the first 20 times it is executed. Again, the
|
||||||
|
``google::COUNTER`` identifier indicates which repetition is happening.
|
||||||
|
|
||||||
|
Other times, it is desired to only log a message periodically based on a time.
|
||||||
|
So for example, to log a message every 10ms:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_EVERY_T(INFO, 0.01) << "Got a cookie";
|
||||||
|
|
||||||
|
Or every 2.35s:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
LOG_EVERY_T(INFO, 2.35) << "Got a cookie";
|
||||||
|
|
||||||
|
Debug Mode Support
|
||||||
|
~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Special "debug mode" logging macros only have an effect in debug mode
|
||||||
|
and are compiled away to nothing for non-debug mode compiles. Use these
|
||||||
|
macros to avoid slowing down your production application due to
|
||||||
|
excessive logging.
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
DLOG(INFO) << "Found cookies";
|
||||||
|
DLOG_IF(INFO, num_cookies > 10) << "Got lots of cookies";
|
||||||
|
DLOG_EVERY_N(INFO, 10) << "Got the " << google::COUNTER << "th cookie";
|
||||||
|
|
||||||
|
|
||||||
|
``CHECK`` Macros
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
It is a good practice to check expected conditions in your program
|
||||||
|
frequently to detect errors as early as possible. The ``CHECK`` macro
|
||||||
|
provides the ability to abort the application when a condition is not
|
||||||
|
met, similar to the ``assert`` macro defined in the standard C library.
|
||||||
|
|
||||||
|
``CHECK`` aborts the application if a condition is not true. Unlike
|
||||||
|
``assert``, it is \*not\* controlled by ``NDEBUG``, so the check will be
|
||||||
|
executed regardless of compilation mode. Therefore, ``fp->Write(x)`` in
|
||||||
|
the following example is always executed:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
CHECK(fp->Write(x) == 4) << "Write failed!";
|
||||||
|
|
||||||
|
There are various helper macros for equality/inequality checks -
|
||||||
|
``CHECK_EQ``, ``CHECK_NE``, ``CHECK_LE``, ``CHECK_LT``, ``CHECK_GE``,
|
||||||
|
and ``CHECK_GT``. They compare two values, and log a ``FATAL`` message
|
||||||
|
including the two values when the result is not as expected. The values
|
||||||
|
must have :cpp:`operator<<(ostream, ...)` defined.
|
||||||
|
|
||||||
|
You may append to the error message like so:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
CHECK_NE(1, 2) << ": The world must be ending!";
|
||||||
|
|
||||||
|
We are very careful to ensure that each argument is evaluated exactly
|
||||||
|
once, and that anything which is legal to pass as a function argument is
|
||||||
|
legal here. In particular, the arguments may be temporary expressions
|
||||||
|
which will end up being destroyed at the end of the apparent statement,
|
||||||
|
for example:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
CHECK_EQ(string("abc")[1], ’b’);
|
||||||
|
|
||||||
|
The compiler reports an error if one of the arguments is a pointer and the other
|
||||||
|
is :cpp:`nullptr`. To work around this, simply :cpp:`static_cast` :cpp:`nullptr` to
|
||||||
|
the type of the desired pointer.
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
CHECK_EQ(some_ptr, static_cast<SomeType*>(nullptr));
|
||||||
|
|
||||||
|
Better yet, use the ``CHECK_NOTNULL`` macro:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
CHECK_NOTNULL(some_ptr);
|
||||||
|
some_ptr->DoSomething();
|
||||||
|
|
||||||
|
Since this macro returns the given pointer, this is very useful in
|
||||||
|
constructor initializer lists.
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
struct S {
|
||||||
|
S(Something* ptr) : ptr_(CHECK_NOTNULL(ptr)) {}
|
||||||
|
Something* ptr_;
|
||||||
|
};
|
||||||
|
|
||||||
|
Note that you cannot use this macro as a C++ stream due to this feature.
|
||||||
|
Please use ``CHECK_EQ`` described above to log a custom message before
|
||||||
|
aborting the application.
|
||||||
|
|
||||||
|
If you are comparing C strings (:cpp:`char *`), a handy set of macros performs
|
||||||
|
case sensitive as well as case insensitive comparisons - ``CHECK_STREQ``,
|
||||||
|
``CHECK_STRNE``, ``CHECK_STRCASEEQ``, and ``CHECK_STRCASENE``. The CASE versions
|
||||||
|
are case-insensitive. You can safely pass :cpp:`nullptr` pointers for this macro. They
|
||||||
|
treat :cpp:`nullptr` and any non-:cpp:`nullptr` string as not equal. Two :cpp:`nullptr`\
|
||||||
|
s are equal.
|
||||||
|
|
||||||
|
Note that both arguments may be temporary strings which are destructed
|
||||||
|
at the end of the current "full expression" (e.g.,
|
||||||
|
:cpp:`CHECK_STREQ(Foo().c_str(), Bar().c_str())` where ``Foo`` and ``Bar``
|
||||||
|
return C++’s :cpp:`std::string`).
|
||||||
|
|
||||||
|
The ``CHECK_DOUBLE_EQ`` macro checks the equality of two floating point
|
||||||
|
values, accepting a small error margin. ``CHECK_NEAR`` accepts a third
|
||||||
|
floating point argument, which specifies the acceptable error margin.
|
||||||
|
|
||||||
|
Verbose Logging
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
When you are chasing difficult bugs, thorough log messages are very useful.
|
||||||
|
However, you may want to ignore too verbose messages in usual development. For
|
||||||
|
such verbose logging, glog provides the ``VLOG`` macro, which allows you to
|
||||||
|
define your own numeric logging levels. The :cmd:`--v` command line option
|
||||||
|
controls which verbose messages are logged:
|
||||||
|
|
||||||
|
.. code:: cpp
|
||||||
|
|
||||||
|
VLOG(1) << "I’m printed when you run the program with --v=1 or higher";
|
||||||
|
VLOG(2) << "I’m 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>`__.
|
||||||
|
|
||||||
|
There’s 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 can’t 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))
|
||||||
|
<< "I’m printed when size is more than 1024 and when you run the "
|
||||||
|
"program with --v=1 or more";
|
||||||
|
VLOG_EVERY_N(1, 10)
|
||||||
|
<< "I’m 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)
|
||||||
|
<< "I’m 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 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.
|
||||||
|
|
||||||
|
.. 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, it’s 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 won’t 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:
|
||||||
|
|
||||||
|
- ``#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 won’t.
|
||||||
|
|
||||||
|
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, glibc’s unwinder has a deadlock issue.
|
||||||
|
However, if you don’t use :cpp:`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.
|
||||||
|
|
||||||
|
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
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
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 <./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. 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>`__.
|
||||||
|
|
||||||
|
|
||||||
.. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg
|
.. |Linux Github actions| image:: https://github.com/google/glog/actions/workflows/linux.yml/badge.svg
|
||||||
|
|||||||
18
WORKSPACE
Normal file
18
WORKSPACE
Normal 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"],
|
||||||
|
)
|
||||||
@ -1 +0,0 @@
|
|||||||
# WORKSPACE marker file needed by Bazel
|
|
||||||
@ -4,6 +4,6 @@ cc_test(
|
|||||||
srcs = ["main.cc"],
|
srcs = ["main.cc"],
|
||||||
deps = [
|
deps = [
|
||||||
"//:glog",
|
"//:glog",
|
||||||
"@gflags//:gflags",
|
"@com_github_gflags_gflags//:gflags",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|||||||
128
bazel/glog.bzl
128
bazel/glog.bzl
@ -25,7 +25,13 @@ expand_template = rule(
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
def glog_library(with_gflags = 1, **kwargs):
|
def dict_union(x, y):
|
||||||
|
z = {}
|
||||||
|
z.update(x)
|
||||||
|
z.update(y)
|
||||||
|
return z
|
||||||
|
|
||||||
|
def glog_library(namespace = "google", with_gflags = 1, **kwargs):
|
||||||
if native.repository_name() != "@":
|
if native.repository_name() != "@":
|
||||||
repo_name = native.repository_name()[1:] # Strip the first leading @
|
repo_name = native.repository_name()[1:] # Strip the first leading @
|
||||||
gendir = "$(GENDIR)/external/" + repo_name
|
gendir = "$(GENDIR)/external/" + repo_name
|
||||||
@ -48,8 +54,12 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
|
|
||||||
common_copts = [
|
common_copts = [
|
||||||
"-std=c++14",
|
"-std=c++14",
|
||||||
|
"-DGLOG_BAZEL_BUILD",
|
||||||
|
# Inject a C++ namespace.
|
||||||
|
"-DGOOGLE_NAMESPACE='%s'" % namespace,
|
||||||
|
"-DHAVE_STRING_H",
|
||||||
"-I%s/glog_internal" % gendir,
|
"-I%s/glog_internal" % gendir,
|
||||||
] + (["-DGLOG_USE_GFLAGS"] if with_gflags else [])
|
] + (["-DHAVE_LIB_GFLAGS"] if with_gflags else [])
|
||||||
|
|
||||||
wasm_copts = [
|
wasm_copts = [
|
||||||
# Disable warnings that exists in glog.
|
# Disable warnings that exists in glog.
|
||||||
@ -57,32 +67,27 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
"-Wno-unused-function",
|
"-Wno-unused-function",
|
||||||
"-Wno-unused-local-typedefs",
|
"-Wno-unused-local-typedefs",
|
||||||
"-Wno-unused-variable",
|
"-Wno-unused-variable",
|
||||||
|
# Allows src/base/mutex.h to include pthread.h.
|
||||||
|
"-DHAVE_PTHREAD",
|
||||||
# Allows src/logging.cc to determine the host name.
|
# Allows src/logging.cc to determine the host name.
|
||||||
"-DHAVE_SYS_UTSNAME_H",
|
"-DHAVE_SYS_UTSNAME_H",
|
||||||
# For src/utilities.cc.
|
# For src/utilities.cc.
|
||||||
"-DHAVE_SYS_TIME_H",
|
"-DHAVE_SYS_TIME_H",
|
||||||
# NOTE: users could optionally patch -DHAVE_UNWIND off if
|
"-DHAVE__UNWIND_BACKTRACE",
|
||||||
# stacktrace dumping is not needed
|
"-DHAVE__UNWIND_GETIP",
|
||||||
"-DHAVE_UNWIND",
|
|
||||||
# Enable dumping stacktrace upon sigaction.
|
# Enable dumping stacktrace upon sigaction.
|
||||||
"-DHAVE_SIGACTION",
|
"-DHAVE_SIGACTION",
|
||||||
# For logging.cc.
|
# For logging.cc.
|
||||||
"-DHAVE_PREAD",
|
"-DHAVE_PREAD",
|
||||||
# -DHAVE_MODE_T prevent repeated typedef mode_t leading
|
"-DHAVE___ATTRIBUTE__",
|
||||||
# to emcc compilation failure
|
|
||||||
"-DHAVE_MODE_T",
|
|
||||||
"-DHAVE_UNISTD_H",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
linux_or_darwin_copts = wasm_copts + [
|
linux_or_darwin_copts = wasm_copts + [
|
||||||
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
"-DGLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
||||||
"-DGLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
|
||||||
"-DHAVE_POSIX_FADVISE",
|
|
||||||
"-DHAVE_SSIZE_T",
|
|
||||||
"-DHAVE_SYS_TYPES_H",
|
|
||||||
# For src/utilities.cc.
|
# For src/utilities.cc.
|
||||||
"-DHAVE_SYS_SYSCALL_H",
|
"-DHAVE_SYS_SYSCALL_H",
|
||||||
# For src/logging.cc to create symlinks.
|
# For src/logging.cc to create symlinks.
|
||||||
|
"-DHAVE_UNISTD_H",
|
||||||
"-fvisibility-inlines-hidden",
|
"-fvisibility-inlines-hidden",
|
||||||
"-fvisibility=hidden",
|
"-fvisibility=hidden",
|
||||||
]
|
]
|
||||||
@ -90,30 +95,26 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
freebsd_only_copts = [
|
freebsd_only_copts = [
|
||||||
# Enable declaration of _Unwind_Backtrace
|
# Enable declaration of _Unwind_Backtrace
|
||||||
"-D_GNU_SOURCE",
|
"-D_GNU_SOURCE",
|
||||||
"-DHAVE_LINK_H",
|
|
||||||
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
|
|
||||||
]
|
]
|
||||||
|
|
||||||
linux_only_copts = [
|
linux_only_copts = [
|
||||||
# For utilities.h.
|
# For utilities.h.
|
||||||
"-DHAVE_EXECINFO_H",
|
"-DHAVE_EXECINFO_H",
|
||||||
"-DHAVE_LINK_H",
|
|
||||||
"-DHAVE_SYMBOLIZE", # Supported by <link.h>
|
|
||||||
]
|
]
|
||||||
|
|
||||||
darwin_only_copts = [
|
darwin_only_copts = [
|
||||||
# For stacktrace.
|
# For stacktrace.
|
||||||
"-DHAVE_DLADDR",
|
"-DHAVE_DLADDR",
|
||||||
|
# Avoid deprecated syscall().
|
||||||
|
"-DHAVE_PTHREAD_THREADID_NP",
|
||||||
]
|
]
|
||||||
|
|
||||||
windows_only_copts = [
|
windows_only_copts = [
|
||||||
# Override -DGLOG_EXPORT= from the cc_library's defines.
|
# Override -DGLOG_EXPORT= from the cc_library's defines.
|
||||||
"-DGLOG_EXPORT=__declspec(dllexport)",
|
"-DGLOG_EXPORT=__declspec(dllexport)",
|
||||||
"-DGLOG_NO_ABBREVIATED_SEVERITIES",
|
"-DGLOG_NO_ABBREVIATED_SEVERITIES",
|
||||||
"-DGLOG_NO_EXPORT=",
|
"-DHAVE_SNPRINTF",
|
||||||
"-DGLOG_USE_WINDOWS_PORT",
|
|
||||||
"-DHAVE__CHSIZE_S",
|
"-DHAVE__CHSIZE_S",
|
||||||
"-DHAVE_DBGHELP",
|
|
||||||
"-I" + src_windows,
|
"-I" + src_windows,
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -123,26 +124,25 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
]
|
]
|
||||||
|
|
||||||
windows_only_srcs = [
|
windows_only_srcs = [
|
||||||
|
"src/glog/log_severity.h",
|
||||||
"src/windows/dirent.h",
|
"src/windows/dirent.h",
|
||||||
"src/windows/port.cc",
|
"src/windows/port.cc",
|
||||||
"src/windows/port.h",
|
"src/windows/port.h",
|
||||||
]
|
]
|
||||||
|
|
||||||
gflags_deps = ["@gflags//:gflags"] if with_gflags else []
|
gflags_deps = ["@com_github_gflags_gflags//:gflags"] if with_gflags else []
|
||||||
|
|
||||||
final_lib_defines = select({
|
final_lib_defines = select({
|
||||||
# GLOG_EXPORT is normally set by export.h, but that's not
|
# GLOG_EXPORT is normally set by export.h, but that's not
|
||||||
# generated for Bazel.
|
# generated for Bazel.
|
||||||
"@bazel_tools//src/conditions:windows": [
|
"@bazel_tools//src/conditions:windows": [
|
||||||
"GLOG_DEPRECATED=__declspec(deprecated)",
|
|
||||||
"GLOG_EXPORT=",
|
"GLOG_EXPORT=",
|
||||||
|
"GLOG_DEPRECATED=__declspec(deprecated)",
|
||||||
"GLOG_NO_ABBREVIATED_SEVERITIES",
|
"GLOG_NO_ABBREVIATED_SEVERITIES",
|
||||||
"GLOG_NO_EXPORT=",
|
|
||||||
],
|
],
|
||||||
"//conditions:default": [
|
"//conditions:default": [
|
||||||
"GLOG_DEPRECATED=__attribute__((deprecated))",
|
"GLOG_DEPRECATED=__attribute__((deprecated))",
|
||||||
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
"GLOG_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
||||||
"GLOG_NO_EXPORT=__attribute__((visibility(\\\"default\\\")))",
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -162,6 +162,7 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
name = "shared_headers",
|
name = "shared_headers",
|
||||||
srcs = [
|
srcs = [
|
||||||
"src/base/commandlineflags.h",
|
"src/base/commandlineflags.h",
|
||||||
|
"src/base/mutex.h",
|
||||||
"src/stacktrace.h",
|
"src/stacktrace.h",
|
||||||
"src/utilities.h",
|
"src/utilities.h",
|
||||||
]
|
]
|
||||||
@ -176,12 +177,9 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
"src/base/googleinit.h",
|
"src/base/googleinit.h",
|
||||||
"src/demangle.cc",
|
"src/demangle.cc",
|
||||||
"src/demangle.h",
|
"src/demangle.h",
|
||||||
"src/flags.cc",
|
|
||||||
"src/logging.cc",
|
"src/logging.cc",
|
||||||
"src/raw_logging.cc",
|
"src/raw_logging.cc",
|
||||||
"src/signalhandler.cc",
|
"src/signalhandler.cc",
|
||||||
"src/stacktrace.cc",
|
|
||||||
"src/stacktrace.h",
|
|
||||||
"src/stacktrace_generic-inl.h",
|
"src/stacktrace_generic-inl.h",
|
||||||
"src/stacktrace_libunwind-inl.h",
|
"src/stacktrace_libunwind-inl.h",
|
||||||
"src/stacktrace_powerpc-inl.h",
|
"src/stacktrace_powerpc-inl.h",
|
||||||
@ -191,21 +189,18 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
"src/symbolize.cc",
|
"src/symbolize.cc",
|
||||||
"src/symbolize.h",
|
"src/symbolize.h",
|
||||||
"src/utilities.cc",
|
"src/utilities.cc",
|
||||||
"src/utilities.h",
|
|
||||||
"src/vlog_is_on.cc",
|
"src/vlog_is_on.cc",
|
||||||
] + select({
|
] + select({
|
||||||
"@bazel_tools//src/conditions:windows": windows_only_srcs,
|
"@bazel_tools//src/conditions:windows": windows_only_srcs,
|
||||||
"//conditions:default": [],
|
"//conditions:default": [],
|
||||||
}),
|
}),
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"src/glog/flags.h",
|
|
||||||
"src/glog/log_severity.h",
|
"src/glog/log_severity.h",
|
||||||
"src/glog/logging.h",
|
|
||||||
"src/glog/platform.h",
|
"src/glog/platform.h",
|
||||||
"src/glog/raw_logging.h",
|
":logging_h",
|
||||||
"src/glog/stl_logging.h",
|
":raw_logging_h",
|
||||||
"src/glog/types.h",
|
":stl_logging_h",
|
||||||
"src/glog/vlog_is_on.h",
|
":vlog_is_on_h",
|
||||||
],
|
],
|
||||||
# https://github.com/google/glog/issues/837: Replacing
|
# https://github.com/google/glog/issues/837: Replacing
|
||||||
# `strip_include_prefix` with `includes` would avoid spamming
|
# `strip_include_prefix` with `includes` would avoid spamming
|
||||||
@ -222,10 +217,6 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
|
"@bazel_tools//src/conditions:windows": [":strip_include_prefix_hack"],
|
||||||
"//conditions:default": [],
|
"//conditions:default": [],
|
||||||
}),
|
}),
|
||||||
linkopts = select({
|
|
||||||
"@bazel_tools//src/conditions:windows": ["dbghelp.lib"],
|
|
||||||
"//conditions:default": [],
|
|
||||||
}),
|
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -261,7 +252,7 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
copts = final_lib_copts + test_only_copts,
|
copts = final_lib_copts + test_only_copts,
|
||||||
deps = gflags_deps + [
|
deps = gflags_deps + [
|
||||||
":glog",
|
":glog",
|
||||||
"@googletest//:gtest",
|
"@com_github_google_googletest//:gtest",
|
||||||
],
|
],
|
||||||
**kwargs
|
**kwargs
|
||||||
)
|
)
|
||||||
@ -271,14 +262,11 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
native.cc_library(
|
native.cc_library(
|
||||||
name = "strip_include_prefix_hack",
|
name = "strip_include_prefix_hack",
|
||||||
hdrs = [
|
hdrs = [
|
||||||
"src/glog/flags.h",
|
|
||||||
"src/glog/log_severity.h",
|
"src/glog/log_severity.h",
|
||||||
"src/glog/logging.h",
|
":logging_h",
|
||||||
"src/glog/platform.h",
|
":raw_logging_h",
|
||||||
"src/glog/raw_logging.h",
|
":stl_logging_h",
|
||||||
"src/glog/stl_logging.h",
|
":vlog_is_on_h",
|
||||||
"src/glog/types.h",
|
|
||||||
"src/glog/vlog_is_on.h",
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -288,3 +276,51 @@ def glog_library(with_gflags = 1, **kwargs):
|
|||||||
out = "glog_internal/config.h",
|
out = "glog_internal/config.h",
|
||||||
substitutions = {"#cmakedefine": "//cmakedefine"},
|
substitutions = {"#cmakedefine": "//cmakedefine"},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
common_config = {
|
||||||
|
"@ac_cv_have_u_int16_t@": "0",
|
||||||
|
"@ac_cv_have_glog_export@": "0",
|
||||||
|
"@ac_google_start_namespace@": "namespace google {",
|
||||||
|
"@ac_google_end_namespace@": "}",
|
||||||
|
"@ac_google_namespace@": "google",
|
||||||
|
}
|
||||||
|
|
||||||
|
posix_config = dict_union(common_config, {
|
||||||
|
"@ac_cv___attribute___noinline@": "__attribute__((noinline))",
|
||||||
|
"@ac_cv___attribute___printf_4_5@": "__attribute__((__format__(__printf__, 4, 5)))",
|
||||||
|
"@ac_cv_have___builtin_expect@": "1",
|
||||||
|
"@ac_cv_have_libgflags@": "1" if with_gflags else "0",
|
||||||
|
"@ac_cv_have_mode_t@": "1",
|
||||||
|
"@ac_cv_have_ssize_t@": "1",
|
||||||
|
"@ac_cv_have_systypes_h@": "1",
|
||||||
|
"@ac_cv_have_unistd_h@": "1",
|
||||||
|
})
|
||||||
|
|
||||||
|
windows_config = dict_union(common_config, {
|
||||||
|
"@ac_cv___attribute___noinline@": "",
|
||||||
|
"@ac_cv___attribute___printf_4_5@": "",
|
||||||
|
"@ac_cv_have___builtin_expect@": "0",
|
||||||
|
"@ac_cv_have_libgflags@": "0",
|
||||||
|
"@ac_cv_have_mode_t@": "0",
|
||||||
|
"@ac_cv_have_ssize_t@": "0",
|
||||||
|
"@ac_cv_have_systypes_h@": "0",
|
||||||
|
"@ac_cv_have_unistd_h@": "0",
|
||||||
|
})
|
||||||
|
|
||||||
|
[
|
||||||
|
expand_template(
|
||||||
|
name = "%s_h" % f,
|
||||||
|
template = "src/glog/%s.h.in" % f,
|
||||||
|
out = "src/glog/%s.h" % f,
|
||||||
|
substitutions = select({
|
||||||
|
"@bazel_tools//src/conditions:windows": windows_config,
|
||||||
|
"//conditions:default": posix_config,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
for f in [
|
||||||
|
"vlog_is_on",
|
||||||
|
"stl_logging",
|
||||||
|
"raw_logging",
|
||||||
|
"logging",
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|||||||
@ -7,20 +7,16 @@ foreach (iter RANGE 1 ${RUNS})
|
|||||||
if (NOT _RESULT EQUAL 0)
|
if (NOT _RESULT EQUAL 0)
|
||||||
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
||||||
endif (NOT _RESULT EQUAL 0)
|
endif (NOT _RESULT EQUAL 0)
|
||||||
|
|
||||||
|
# Ensure the log files to have different modification timestamps such that
|
||||||
|
# exactly one log file remains at the end. Otherwise all log files will be
|
||||||
|
# retained.
|
||||||
|
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
|
||||||
endforeach (iter)
|
endforeach (iter)
|
||||||
|
|
||||||
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
|
file (GLOB LOG_FILES ${TEST_DIR}/*.foobar)
|
||||||
list (LENGTH LOG_FILES NUM_FILES)
|
list (LENGTH LOG_FILES NUM_FILES)
|
||||||
|
|
||||||
if (WIN32)
|
if (NOT NUM_FILES EQUAL 1)
|
||||||
# On Windows open files cannot be removed and will result in a permission
|
message (SEND_ERROR "Expected 1 log file in log directory but found ${NUM_FILES}")
|
||||||
# denied error while unlinking such file. Therefore, the last file will be
|
endif (NOT NUM_FILES EQUAL 1)
|
||||||
# retained.
|
|
||||||
set (_expected 1)
|
|
||||||
else (WIN32)
|
|
||||||
set (_expected 0)
|
|
||||||
endif (WIN32)
|
|
||||||
|
|
||||||
if (NOT NUM_FILES EQUAL _expected)
|
|
||||||
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
|
|
||||||
endif (NOT NUM_FILES EQUAL _expected)
|
|
||||||
|
|||||||
@ -7,20 +7,16 @@ foreach (iter RANGE 1 ${RUNS})
|
|||||||
if (NOT _RESULT EQUAL 0)
|
if (NOT _RESULT EQUAL 0)
|
||||||
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
||||||
endif (NOT _RESULT EQUAL 0)
|
endif (NOT _RESULT EQUAL 0)
|
||||||
|
|
||||||
|
# Ensure the log files to have different modification timestamps such that
|
||||||
|
# exactly one log file remains at the end. Otherwise all log files will be
|
||||||
|
# retained.
|
||||||
|
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 1)
|
||||||
endforeach (iter)
|
endforeach (iter)
|
||||||
|
|
||||||
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
|
file (GLOB LOG_FILES ${TEST_DIR}/test_cleanup_*.barfoo)
|
||||||
list (LENGTH LOG_FILES NUM_FILES)
|
list (LENGTH LOG_FILES NUM_FILES)
|
||||||
|
|
||||||
if (WIN32)
|
if (NOT NUM_FILES EQUAL 1)
|
||||||
# On Windows open files cannot be removed and will result in a permission
|
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR} but found ${NUM_FILES}")
|
||||||
# denied error while unlinking such file. Therefore, the last file will be
|
endif (NOT NUM_FILES EQUAL 1)
|
||||||
# retained.
|
|
||||||
set (_expected 1)
|
|
||||||
else (WIN32)
|
|
||||||
set (_expected 0)
|
|
||||||
endif (WIN32)
|
|
||||||
|
|
||||||
if (NOT NUM_FILES EQUAL _expected)
|
|
||||||
message (SEND_ERROR "Expected ${_expected} log file in log directory but found ${NUM_FILES}")
|
|
||||||
endif (NOT NUM_FILES EQUAL _expected)
|
|
||||||
|
|||||||
@ -10,23 +10,19 @@ foreach (iter RANGE 1 ${RUNS})
|
|||||||
if (NOT _RESULT EQUAL 0)
|
if (NOT _RESULT EQUAL 0)
|
||||||
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
message (FATAL_ERROR "Failed to run logcleanup_unittest (error: ${_RESULT})")
|
||||||
endif (NOT _RESULT EQUAL 0)
|
endif (NOT _RESULT EQUAL 0)
|
||||||
|
|
||||||
|
# Ensure the log files to have different modification timestamps such that
|
||||||
|
# exactly one log file remains at the end. Otherwise all log files will be
|
||||||
|
# retained.
|
||||||
|
execute_process (COMMAND ${CMAKE_COMMAND} -E sleep 2)
|
||||||
endforeach (iter)
|
endforeach (iter)
|
||||||
|
|
||||||
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
|
file (GLOB LOG_FILES ${TEST_DIR}/${TEST_SUBDIR}/test_cleanup_*.relativefoo)
|
||||||
list (LENGTH LOG_FILES NUM_FILES)
|
list (LENGTH LOG_FILES NUM_FILES)
|
||||||
|
|
||||||
if (WIN32)
|
if (NOT NUM_FILES EQUAL 1)
|
||||||
# On Windows open files cannot be removed and will result in a permission
|
message (SEND_ERROR "Expected 1 log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
|
||||||
# denied error while unlinking such file. Therefore, the last file will be
|
endif (NOT NUM_FILES EQUAL 1)
|
||||||
# retained.
|
|
||||||
set (_expected 1)
|
|
||||||
else (WIN32)
|
|
||||||
set (_expected 0)
|
|
||||||
endif (WIN32)
|
|
||||||
|
|
||||||
if (NOT NUM_FILES EQUAL _expected)
|
|
||||||
message (SEND_ERROR "Expected ${_expected} log file in build directory ${TEST_DIR}${TEST_SUBDIR} but found ${NUM_FILES}")
|
|
||||||
endif (NOT NUM_FILES EQUAL _expected)
|
|
||||||
|
|
||||||
# Remove the subdirectory required by this unit test.
|
# Remove the subdirectory required by this unit test.
|
||||||
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})
|
file (REMOVE_RECURSE ${TEST_DIR}/${TEST_SUBDIR})
|
||||||
|
|||||||
@ -1,11 +1,4 @@
|
|||||||
comment:
|
|
||||||
layout: "diff, flags, files"
|
|
||||||
behavior: default
|
|
||||||
require_changes: false
|
|
||||||
require_base: false
|
|
||||||
require_head: true
|
|
||||||
ignore:
|
ignore:
|
||||||
- "**/*_unittest.cc"
|
- "**/*_unittest.cc"
|
||||||
- "src/*_unittest/**"
|
|
||||||
- "src/googletest.h"
|
- "src/googletest.h"
|
||||||
- "src/mock-log.h"
|
- "src/mock-log.h"
|
||||||
|
|||||||
@ -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).
|
|
||||||
@ -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).
|
|
||||||
@ -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.
|
|
||||||
|
|
||||||
@ -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 won’t 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";
|
|
||||||
```
|
|
||||||
@ -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.
|
|
||||||
@ -1,3 +0,0 @@
|
|||||||
# The 3-Clause BSD License
|
|
||||||
|
|
||||||
--8<-- "LICENSE.md"
|
|
||||||
@ -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();
|
|
||||||
```
|
|
||||||
@ -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.
|
|
||||||
|
|
||||||
424
docs/logging.md
424
docs/logging.md
@ -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) << "I’m printed when you run the program with --v=1 or higher";
|
|
||||||
VLOG(2) << "I’m 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 can’t 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))
|
|
||||||
<< "I’m printed when size is more than 1024 and when you run the "
|
|
||||||
"program with --v=1 or more";
|
|
||||||
VLOG_EVERY_N(1, 10)
|
|
||||||
<< "I’m 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)
|
|
||||||
<< "I’m 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.
|
|
||||||
@ -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 %}
|
|
||||||
@ -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.
|
|
||||||
@ -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
|
|
||||||
@ -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
|
|
||||||
```
|
|
||||||
@ -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.
|
|
||||||
@ -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.
|
|
||||||
@ -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 won’t 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).
|
|
||||||
@ -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";
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
exclude = src/.*_unittest\.cc
|
exclude = src/.*_unittest\.cc
|
||||||
exclude = src/googletest\.h
|
exclude = src/googletest\.h
|
||||||
exclude = src/mock-log\.h
|
exclude = src/mock-log\.h
|
||||||
exclude-directories = Tests/
|
|
||||||
exclude-throw-branches = yes
|
exclude-throw-branches = yes
|
||||||
exclude-unreachable-branches = yes
|
exclude-unreachable-branches = yes
|
||||||
filter = .*/glog/.*\.h
|
filter = .*/glog/.*\.h
|
||||||
|
|||||||
@ -7,8 +7,6 @@ endif (CMAKE_VERSION VERSION_LESS @glog_CMake_VERSION@)
|
|||||||
include (CMakeFindDependencyMacro)
|
include (CMakeFindDependencyMacro)
|
||||||
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
|
include (${CMAKE_CURRENT_LIST_DIR}/glog-modules.cmake)
|
||||||
|
|
||||||
find_dependency (Threads)
|
|
||||||
|
|
||||||
@gflags_DEPENDENCY@
|
@gflags_DEPENDENCY@
|
||||||
@Unwind_DEPENDENCY@
|
@Unwind_DEPENDENCY@
|
||||||
|
|
||||||
|
|||||||
123
mkdocs.yml
123
mkdocs.yml
@ -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 © 2024 Google Inc. & 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
|
|
||||||
@ -48,66 +48,67 @@
|
|||||||
#ifndef BASE_COMMANDLINEFLAGS_H__
|
#ifndef BASE_COMMANDLINEFLAGS_H__
|
||||||
#define BASE_COMMANDLINEFLAGS_H__
|
#define BASE_COMMANDLINEFLAGS_H__
|
||||||
|
|
||||||
#include <cstdlib> // for getenv
|
#include "config.h"
|
||||||
#include <cstring> // for memchr
|
#include <cstdlib> // for getenv
|
||||||
|
#include <cstring> // for memchr
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "config.h"
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#include <gflags/gflags.h>
|
||||||
|
|
||||||
# include <gflags/gflags.h>
|
|
||||||
|
|
||||||
#else
|
#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 { \
|
namespace fL##shorttype { \
|
||||||
extern GLOG_EXPORT type FLAGS_##name; \
|
extern GLOG_EXPORT type FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fL##shorttype::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 { \
|
namespace fL##shorttype { \
|
||||||
GLOG_EXPORT type FLAGS_##name(value); \
|
GLOG_EXPORT type FLAGS_##name(value); \
|
||||||
char FLAGS_no##name; \
|
char FLAGS_no##name; \
|
||||||
} \
|
} \
|
||||||
using fL##shorttype::FLAGS_##name
|
using fL##shorttype::FLAGS_##name
|
||||||
|
|
||||||
// bool specialization
|
// bool specialization
|
||||||
# define DECLARE_bool(name) DECLARE_VARIABLE(bool, B, name, bool)
|
#define DECLARE_bool(name) \
|
||||||
# define DEFINE_bool(name, value, meaning) \
|
DECLARE_VARIABLE(bool, B, name, bool)
|
||||||
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
#define DEFINE_bool(name, value, meaning) \
|
||||||
|
DEFINE_VARIABLE(bool, B, name, value, meaning, bool)
|
||||||
|
|
||||||
// int32 specialization
|
// int32 specialization
|
||||||
# define DECLARE_int32(name) DECLARE_VARIABLE(google::int32, I, name, int32)
|
#define DECLARE_int32(name) \
|
||||||
# define DEFINE_int32(name, value, meaning) \
|
DECLARE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, int32)
|
||||||
DEFINE_VARIABLE(google::int32, I, name, value, meaning, int32)
|
#define DEFINE_int32(name, value, meaning) \
|
||||||
|
DEFINE_VARIABLE(GOOGLE_NAMESPACE::int32, I, name, value, meaning, int32)
|
||||||
|
|
||||||
// uint32 specialization
|
// uint32 specialization
|
||||||
# ifndef DECLARE_uint32
|
#ifndef DECLARE_uint32
|
||||||
# define DECLARE_uint32(name) \
|
#define DECLARE_uint32(name) \
|
||||||
DECLARE_VARIABLE(google::uint32, U, name, uint32)
|
DECLARE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, uint32)
|
||||||
# endif // DECLARE_uint64
|
#endif // DECLARE_uint64
|
||||||
# define DEFINE_uint32(name, value, meaning) \
|
#define DEFINE_uint32(name, value, meaning) \
|
||||||
DEFINE_VARIABLE(google::uint32, U, name, value, meaning, uint32)
|
DEFINE_VARIABLE(GOOGLE_NAMESPACE::uint32, U, name, value, meaning, uint32)
|
||||||
|
|
||||||
// Special case for string, because we have to specify the namespace
|
// Special case for string, because we have to specify the namespace
|
||||||
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
// std::string, which doesn't play nicely with our FLAG__namespace hackery.
|
||||||
# define DECLARE_string(name) \
|
#define DECLARE_string(name) \
|
||||||
namespace fLS { \
|
namespace fLS { \
|
||||||
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
extern GLOG_EXPORT std::string& FLAGS_##name; \
|
||||||
} \
|
} \
|
||||||
using fLS::FLAGS_##name
|
using fLS::FLAGS_##name
|
||||||
# define DEFINE_string(name, value, meaning) \
|
#define DEFINE_string(name, value, meaning) \
|
||||||
namespace fLS { \
|
namespace fLS { \
|
||||||
std::string FLAGS_##name##_buf(value); \
|
std::string FLAGS_##name##_buf(value); \
|
||||||
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
|
GLOG_EXPORT std::string& FLAGS_##name = FLAGS_##name##_buf; \
|
||||||
char FLAGS_no##name; \
|
char FLAGS_no##name; \
|
||||||
} \
|
} \
|
||||||
using fLS::FLAGS_##name
|
using fLS::FLAGS_##name
|
||||||
|
|
||||||
#endif // GLOG_USE_GFLAGS
|
#endif // HAVE_LIB_GFLAGS
|
||||||
|
|
||||||
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
|
// Define GLOG_DEFINE_* using DEFINE_* . By using these macros, we
|
||||||
// have GLOG_* environ variables even if we have gflags installed.
|
// have GLOG_* environ variables even if we have gflags installed.
|
||||||
@ -131,7 +132,8 @@
|
|||||||
// These macros (could be functions, but I don't want to bother with a .cc
|
// These macros (could be functions, but I don't want to bother with a .cc
|
||||||
// file), make it easier to initialize flags from the environment.
|
// file), make it easier to initialize flags from the environment.
|
||||||
|
|
||||||
#define EnvToString(envname, dflt) (!getenv(envname) ? (dflt) : getenv(envname))
|
#define EnvToString(envname, dflt) \
|
||||||
|
(!getenv(envname) ? (dflt) : getenv(envname))
|
||||||
|
|
||||||
#define EnvToBool(envname, dflt) \
|
#define EnvToBool(envname, dflt) \
|
||||||
(!getenv(envname) ? (dflt) \
|
(!getenv(envname) ? (dflt) \
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
// Copyright (c) 2008, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
// modification, are permitted provided that the following conditions are
|
// modification, are permitted provided that the following conditions are
|
||||||
// met:
|
// met:
|
||||||
//
|
//
|
||||||
// * Redistributions of source code must retain the above copyright
|
// * Redistributions of source code must retain the above copyright
|
||||||
// notice, this list of conditions and the following disclaimer.
|
// notice, this list of conditions and the following disclaimer.
|
||||||
// * Redistributions in binary form must reproduce the above
|
// * Redistributions in binary form must reproduce the above
|
||||||
@ -14,7 +14,7 @@
|
|||||||
// * Neither the name of Google Inc. nor the names of its
|
// * Neither the name of Google Inc. nor the names of its
|
||||||
// contributors may be used to endorse or promote products derived from
|
// contributors may be used to endorse or promote products derived from
|
||||||
// this software without specific prior written permission.
|
// this software without specific prior written permission.
|
||||||
//
|
//
|
||||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||||
@ -36,14 +36,16 @@
|
|||||||
class GoogleInitializer {
|
class GoogleInitializer {
|
||||||
public:
|
public:
|
||||||
using void_function = void (*)();
|
using void_function = void (*)();
|
||||||
GoogleInitializer(const char*, void_function f) { f(); }
|
GoogleInitializer(const char*, void_function f) {
|
||||||
|
f();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
#define REGISTER_MODULE_INITIALIZER(name, body) \
|
||||||
namespace { \
|
namespace { \
|
||||||
static void google_init_module_##name() { body; } \
|
static void google_init_module_##name () { body; } \
|
||||||
GoogleInitializer google_initializer_module_##name( \
|
GoogleInitializer google_initializer_module_##name(#name, \
|
||||||
#name, google_init_module_##name); \
|
google_init_module_##name); \
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* _GOOGLEINIT_H */
|
#endif /* _GOOGLEINIT_H */
|
||||||
|
|||||||
333
src/base/mutex.h
Normal file
333
src/base/mutex.h
Normal 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__ */
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2021, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,17 +32,17 @@
|
|||||||
#include "glog/raw_logging.h"
|
#include "glog/raw_logging.h"
|
||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#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.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::AllOf;
|
using testing::AllOf;
|
||||||
using testing::AnyNumber;
|
using testing::AnyNumber;
|
||||||
@ -52,12 +52,11 @@ using testing::StrictMock;
|
|||||||
using testing::StrNe;
|
using testing::StrNe;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
TEST(CleanImmediately, logging) {
|
TEST(CleanImmediately, logging) {
|
||||||
using namespace std::chrono_literals;
|
|
||||||
google::SetLogFilenameExtension(".foobar");
|
google::SetLogFilenameExtension(".foobar");
|
||||||
google::EnableLogCleaner(0h);
|
google::EnableLogCleaner(0);
|
||||||
|
|
||||||
for (unsigned i = 0; i < 1000; ++i) {
|
for (unsigned i = 0; i < 1000; ++i) {
|
||||||
LOG(INFO) << "cleanup test";
|
LOG(INFO) << "cleanup test";
|
||||||
@ -66,10 +65,10 @@ TEST(CleanImmediately, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
#endif
|
||||||
// Make sure stderr is not buffered as stderr seems to be buffered
|
// Make sure stderr is not buffered as stderr seems to be buffered
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2021, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,17 +32,17 @@
|
|||||||
#include "glog/raw_logging.h"
|
#include "glog/raw_logging.h"
|
||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#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.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::AllOf;
|
using testing::AllOf;
|
||||||
using testing::AnyNumber;
|
using testing::AnyNumber;
|
||||||
@ -52,11 +52,10 @@ using testing::StrictMock;
|
|||||||
using testing::StrNe;
|
using testing::StrNe;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
|
TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
|
||||||
using namespace std::chrono_literals;
|
google::EnableLogCleaner(0);
|
||||||
google::EnableLogCleaner(0h);
|
|
||||||
google::SetLogFilenameExtension(".barfoo");
|
google::SetLogFilenameExtension(".barfoo");
|
||||||
google::SetLogDestination(GLOG_INFO, "test_cleanup_");
|
google::SetLogDestination(GLOG_INFO, "test_cleanup_");
|
||||||
|
|
||||||
@ -71,10 +70,10 @@ TEST(CleanImmediatelyWithAbsolutePrefix, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
#endif
|
||||||
// Make sure stderr is not buffered as stderr seems to be buffered
|
// Make sure stderr is not buffered as stderr seems to be buffered
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2021, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,17 +32,17 @@
|
|||||||
#include "glog/raw_logging.h"
|
#include "glog/raw_logging.h"
|
||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GMOCK
|
#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.
|
// Introduce several symbols from gmock.
|
||||||
using google::glog_testing::ScopedMockLog;
|
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::AllOf;
|
using testing::AllOf;
|
||||||
using testing::AnyNumber;
|
using testing::AnyNumber;
|
||||||
@ -52,11 +52,10 @@ using testing::StrictMock;
|
|||||||
using testing::StrNe;
|
using testing::StrNe;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
TEST(CleanImmediatelyWithRelativePrefix, logging) {
|
TEST(CleanImmediatelyWithRelativePrefix, logging) {
|
||||||
using namespace std::chrono_literals;
|
google::EnableLogCleaner(0);
|
||||||
google::EnableLogCleaner(0h);
|
|
||||||
google::SetLogFilenameExtension(".relativefoo");
|
google::SetLogFilenameExtension(".relativefoo");
|
||||||
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
|
google::SetLogDestination(GLOG_INFO, "test_subdir/test_cleanup_");
|
||||||
|
|
||||||
@ -67,10 +66,10 @@ TEST(CleanImmediatelyWithRelativePrefix, logging) {
|
|||||||
google::DisableLogCleaner();
|
google::DisableLogCleaner();
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
FLAGS_colorlogtostderr = false;
|
FLAGS_colorlogtostderr = false;
|
||||||
FLAGS_timestamp_in_logfile_name = true;
|
FLAGS_timestamp_in_logfile_name = true;
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
#endif
|
||||||
// Make sure stderr is not buffered as stderr seems to be buffered
|
// Make sure stderr is not buffered as stderr seems to be buffered
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
#ifndef GLOG_CONFIG_H
|
#ifndef GLOG_CONFIG_H
|
||||||
#define GLOG_CONFIG_H
|
#define GLOG_CONFIG_H
|
||||||
|
|
||||||
|
/* Namespace for Google classes */
|
||||||
|
#cmakedefine GOOGLE_NAMESPACE ${GOOGLE_NAMESPACE}
|
||||||
|
|
||||||
/* Define if you have the `dladdr' function */
|
/* Define if you have the `dladdr' function */
|
||||||
#cmakedefine HAVE_DLADDR
|
#cmakedefine HAVE_DLADDR
|
||||||
|
|
||||||
|
/* Define if you have the `snprintf' function */
|
||||||
|
#cmakedefine HAVE_SNPRINTF
|
||||||
|
|
||||||
/* Define to 1 if you have the <dlfcn.h> header file. */
|
/* Define to 1 if you have the <dlfcn.h> header file. */
|
||||||
#cmakedefine HAVE_DLFCN_H
|
#cmakedefine HAVE_DLFCN_H
|
||||||
|
|
||||||
@ -19,6 +25,12 @@
|
|||||||
/* Define to 1 if you have the <glob.h> header file. */
|
/* Define to 1 if you have the <glob.h> header file. */
|
||||||
#cmakedefine HAVE_GLOB_H
|
#cmakedefine HAVE_GLOB_H
|
||||||
|
|
||||||
|
/* Define to 1 if you have the `pthread' library (-lpthread). */
|
||||||
|
#cmakedefine HAVE_LIBPTHREAD
|
||||||
|
|
||||||
|
/* define if you have google gflags library */
|
||||||
|
#cmakedefine HAVE_LIB_GFLAGS
|
||||||
|
|
||||||
/* define if you have google gmock library */
|
/* define if you have google gmock library */
|
||||||
#cmakedefine HAVE_LIB_GMOCK
|
#cmakedefine HAVE_LIB_GMOCK
|
||||||
|
|
||||||
@ -28,11 +40,20 @@
|
|||||||
/* define if you have dbghelp library */
|
/* define if you have dbghelp library */
|
||||||
#cmakedefine HAVE_DBGHELP
|
#cmakedefine HAVE_DBGHELP
|
||||||
|
|
||||||
|
/* define if you have libunwind */
|
||||||
|
#cmakedefine HAVE_LIB_UNWIND
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <memory.h> header file. */
|
||||||
|
#cmakedefine HAVE_MEMORY_H
|
||||||
|
|
||||||
|
/* define to disable multithreading support. */
|
||||||
|
#cmakedefine NO_THREADS
|
||||||
|
|
||||||
/* Define if you have the 'pread' function */
|
/* Define if you have the 'pread' function */
|
||||||
#cmakedefine HAVE_PREAD
|
#cmakedefine HAVE_PREAD
|
||||||
|
|
||||||
/* Define if you have the 'posix_fadvise' function in <fcntl.h> */
|
/* Define if you have POSIX threads libraries and header files. */
|
||||||
#cmakedefine HAVE_POSIX_FADVISE
|
#cmakedefine HAVE_PTHREAD
|
||||||
|
|
||||||
/* Define to 1 if you have the <pwd.h> header file. */
|
/* Define to 1 if you have the <pwd.h> header file. */
|
||||||
#cmakedefine HAVE_PWD_H
|
#cmakedefine HAVE_PWD_H
|
||||||
@ -40,26 +61,26 @@
|
|||||||
/* Define if you have the 'pwrite' function */
|
/* Define if you have the 'pwrite' function */
|
||||||
#cmakedefine HAVE_PWRITE
|
#cmakedefine HAVE_PWRITE
|
||||||
|
|
||||||
|
/* define if the compiler implements pthread_rwlock_* */
|
||||||
|
#cmakedefine HAVE_RWLOCK
|
||||||
|
|
||||||
/* Define if you have the 'sigaction' function */
|
/* Define if you have the 'sigaction' function */
|
||||||
#cmakedefine HAVE_SIGACTION
|
#cmakedefine HAVE_SIGACTION
|
||||||
|
|
||||||
/* Define if you have the `sigaltstack' function */
|
/* Define if you have the `sigaltstack' function */
|
||||||
#cmakedefine HAVE_SIGALTSTACK
|
#cmakedefine HAVE_SIGALTSTACK
|
||||||
|
|
||||||
|
/* Define to 1 if you have the <strings.h> header file. */
|
||||||
|
#cmakedefine HAVE_STRINGS_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <syscall.h> header file. */
|
/* Define to 1 if you have the <syscall.h> header file. */
|
||||||
#cmakedefine HAVE_SYSCALL_H
|
#cmakedefine HAVE_SYSCALL_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <syslog.h> header file. */
|
/* Define to 1 if you have the <syslog.h> header file. */
|
||||||
#cmakedefine HAVE_SYSLOG_H
|
#cmakedefine HAVE_SYSLOG_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <elf.h> header file. */
|
/* Define to 1 if you have the <sys/stat.h> header file. */
|
||||||
#cmakedefine HAVE_ELF_H
|
#cmakedefine HAVE_SYS_STAT_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/exec_elf.h> header file. */
|
|
||||||
#cmakedefine HAVE_SYS_EXEC_ELF_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <link.h> header file. */
|
|
||||||
#cmakedefine HAVE_LINK_H
|
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
/* Define to 1 if you have the <sys/syscall.h> header file. */
|
||||||
#cmakedefine HAVE_SYS_SYSCALL_H
|
#cmakedefine HAVE_SYS_SYSCALL_H
|
||||||
@ -68,7 +89,7 @@
|
|||||||
#cmakedefine HAVE_SYS_TIME_H
|
#cmakedefine HAVE_SYS_TIME_H
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/types.h> header file. */
|
/* Define to 1 if you have the <sys/types.h> header file. */
|
||||||
#cmakedefine HAVE_SYS_TYPES_H
|
#cmakedefine HAVE_SYS_TYPES_H ${HAVE_SYS_TYPES_H}
|
||||||
|
|
||||||
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
/* Define to 1 if you have the <sys/ucontext.h> header file. */
|
||||||
#cmakedefine HAVE_SYS_UCONTEXT_H
|
#cmakedefine HAVE_SYS_UCONTEXT_H
|
||||||
@ -85,11 +106,20 @@
|
|||||||
/* Define to 1 if you have the <unistd.h> header file. */
|
/* Define to 1 if you have the <unistd.h> header file. */
|
||||||
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
|
#cmakedefine HAVE_UNISTD_H ${HAVE_UNISTD_H}
|
||||||
|
|
||||||
/* define if you have unwind */
|
/* Define if you linking to _Unwind_Backtrace is possible. */
|
||||||
#cmakedefine HAVE_UNWIND
|
#cmakedefine HAVE__UNWIND_BACKTRACE
|
||||||
|
|
||||||
/* define if you have libunwind */
|
/* Define if you linking to _Unwind_GetIP is possible. */
|
||||||
#cmakedefine HAVE_LIBUNWIND
|
#cmakedefine HAVE__UNWIND_GETIP
|
||||||
|
|
||||||
|
/* define if your compiler has __attribute__ */
|
||||||
|
#cmakedefine HAVE___ATTRIBUTE__
|
||||||
|
|
||||||
|
/* define if your compiler has __builtin_expect */
|
||||||
|
#cmakedefine HAVE___BUILTIN_EXPECT ${HAVE___BUILTIN_EXPECT}
|
||||||
|
|
||||||
|
/* define if your compiler has __sync_val_compare_and_swap */
|
||||||
|
#cmakedefine HAVE___SYNC_VAL_COMPARE_AND_SWAP
|
||||||
|
|
||||||
/* define if symbolize support is available */
|
/* define if symbolize support is available */
|
||||||
#cmakedefine HAVE_SYMBOLIZE
|
#cmakedefine HAVE_SYMBOLIZE
|
||||||
@ -103,11 +133,9 @@
|
|||||||
/* define if _chsize_s is available in io.h */
|
/* define if _chsize_s is available in io.h */
|
||||||
#cmakedefine HAVE__CHSIZE_S
|
#cmakedefine HAVE__CHSIZE_S
|
||||||
|
|
||||||
/* define if ssize_t is defined */
|
/* Define to the sub-directory in which libtool stores uninstalled libraries.
|
||||||
#cmakedefine HAVE_SSIZE_T
|
*/
|
||||||
|
#cmakedefine LT_OBJDIR
|
||||||
/* define if mode_t is defined */
|
|
||||||
#cmakedefine HAVE_MODE_T
|
|
||||||
|
|
||||||
/* How to access the PC from a struct ucontext */
|
/* How to access the PC from a struct ucontext */
|
||||||
#cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}
|
#cmakedefine PC_FROM_UCONTEXT ${PC_FROM_UCONTEXT}
|
||||||
@ -115,6 +143,10 @@
|
|||||||
/* define if we should print file offsets in traces instead of symbolizing. */
|
/* define if we should print file offsets in traces instead of symbolizing. */
|
||||||
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
|
#cmakedefine PRINT_UNSYMBOLIZED_STACK_TRACES
|
||||||
|
|
||||||
|
/* Define to necessary symbol if this constant uses a non-standard name on
|
||||||
|
your system. */
|
||||||
|
#cmakedefine PTHREAD_CREATE_JOINABLE
|
||||||
|
|
||||||
/* The size of `void *', as computed by sizeof. */
|
/* The size of `void *', as computed by sizeof. */
|
||||||
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
|
#cmakedefine SIZEOF_VOID_P ${SIZEOF_VOID_P}
|
||||||
|
|
||||||
@ -124,19 +156,25 @@
|
|||||||
/* Define if thread-local storage is enabled. */
|
/* Define if thread-local storage is enabled. */
|
||||||
#cmakedefine GLOG_THREAD_LOCAL_STORAGE
|
#cmakedefine GLOG_THREAD_LOCAL_STORAGE
|
||||||
|
|
||||||
/* define if abi::__cxa_demangle is available in cxxabi.h */
|
#ifdef GLOG_BAZEL_BUILD
|
||||||
#cmakedefine HAVE___CXA_DEMANGLE
|
|
||||||
|
|
||||||
/* define if __argv is available in cstdlib */
|
/* TODO(rodrigoq): remove this workaround once bazel#3979 is resolved:
|
||||||
#cmakedefine HAVE___ARGV
|
* https://github.com/bazelbuild/bazel/issues/3979 */
|
||||||
|
#define _START_GOOGLE_NAMESPACE_ namespace GOOGLE_NAMESPACE {
|
||||||
|
|
||||||
/* define if __progname is available */
|
#define _END_GOOGLE_NAMESPACE_ }
|
||||||
#cmakedefine HAVE___PROGNAME
|
|
||||||
|
|
||||||
/* define if getprogname is available in cstdlib */
|
#else
|
||||||
#cmakedefine HAVE_GETPROGNAME
|
|
||||||
|
|
||||||
/* define if program_invocation_short_name is available in cerrno */
|
/* Stops putting the code inside the Google namespace */
|
||||||
#cmakedefine HAVE_PROGRAM_INVOCATION_SHORT_NAME
|
#cmakedefine _END_GOOGLE_NAMESPACE_ ${_END_GOOGLE_NAMESPACE_}
|
||||||
|
|
||||||
|
/* Puts following code inside the Google namespace */
|
||||||
|
#cmakedefine _START_GOOGLE_NAMESPACE_ ${_START_GOOGLE_NAMESPACE_}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Replacement for deprecated syscall(SYS_gettid) on macOS. */
|
||||||
|
#cmakedefine HAVE_PTHREAD_THREADID_NP ${HAVE_PTHREAD_THREADID_NP}
|
||||||
|
|
||||||
#endif // GLOG_CONFIG_H
|
#endif // GLOG_CONFIG_H
|
||||||
|
|||||||
@ -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)
|
|
||||||
@ -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";
|
|
||||||
}
|
|
||||||
445
src/demangle.cc
445
src/demangle.cc
File diff suppressed because it is too large
Load Diff
@ -67,28 +67,19 @@
|
|||||||
// C++ ABI in the future.
|
// C++ ABI in the future.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GLOG_INTERNAL_DEMANGLE_H
|
#ifndef BASE_DEMANGLE_H_
|
||||||
#define GLOG_INTERNAL_DEMANGLE_H
|
#define BASE_DEMANGLE_H_
|
||||||
|
|
||||||
#include <cstddef>
|
#include "config.h"
|
||||||
|
#include "glog/logging.h"
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
_START_GOOGLE_NAMESPACE_
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_NO_EXPORT)
|
|
||||||
# error "demangle.h" was not included correctly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace google {
|
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Demangle "mangled". On success, return true and write the
|
// Demangle "mangled". On success, return true and write the
|
||||||
// demangled symbol name to "out". Otherwise, return false.
|
// demangled symbol name to "out". Otherwise, return false.
|
||||||
// "out" is modified even if demangling is unsuccessful.
|
// "out" is modified even if demangling is unsuccessful.
|
||||||
bool GLOG_NO_EXPORT Demangle(const char* mangled, char* out, size_t out_size);
|
bool GLOG_EXPORT Demangle(const char *mangled, char *out, size_t out_size);
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // GLOG_INTERNAL_DEMANGLE_H
|
#endif // BASE_DEMANGLE_H_
|
||||||
|
|||||||
@ -42,8 +42,8 @@
|
|||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -51,10 +51,10 @@ GLOG_DEFINE_bool(demangle_filter, false,
|
|||||||
"Run demangle_unittest in filter mode");
|
"Run demangle_unittest in filter mode");
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
// A wrapper function for Demangle() to make the unit test simple.
|
// A wrapper function for Demangle() to make the unit test simple.
|
||||||
static const char* DemangleIt(const char* const mangled) {
|
static const char *DemangleIt(const char * const mangled) {
|
||||||
static char demangled[4096];
|
static char demangled[4096];
|
||||||
if (Demangle(mangled, demangled, sizeof(demangled))) {
|
if (Demangle(mangled, demangled, sizeof(demangled))) {
|
||||||
return demangled;
|
return demangled;
|
||||||
@ -65,25 +65,28 @@ static const char* DemangleIt(const char* const mangled) {
|
|||||||
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
|
|
||||||
# if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
#if defined(HAVE_DBGHELP) && !defined(NDEBUG)
|
||||||
TEST(Demangle, Windows) {
|
TEST(Demangle, Windows) {
|
||||||
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
EXPECT_STREQ(
|
||||||
DemangleIt("?func@Foo@@SAXH@Z"));
|
"public: static void __cdecl Foo::func(int)",
|
||||||
EXPECT_STREQ("public: static void __cdecl Foo::func(int)",
|
DemangleIt("?func@Foo@@SAXH@Z"));
|
||||||
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
EXPECT_STREQ(
|
||||||
EXPECT_STREQ("int __cdecl foobarArray(int * const)",
|
"public: static void __cdecl Foo::func(int)",
|
||||||
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
DemangleIt("@ILT+1105(?func@Foo@@SAXH@Z)"));
|
||||||
|
EXPECT_STREQ(
|
||||||
|
"int __cdecl foobarArray(int * const)",
|
||||||
|
DemangleIt("?foobarArray@@YAHQAH@Z"));
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Test corner cases of boundary conditions.
|
// Test corner cases of boundary conditions.
|
||||||
TEST(Demangle, CornerCases) {
|
TEST(Demangle, CornerCases) {
|
||||||
const size_t size = 10;
|
const size_t size = 10;
|
||||||
char tmp[size] = {0};
|
char tmp[size] = { 0 };
|
||||||
const char* demangled = "foobar()";
|
const char *demangled = "foobar()";
|
||||||
const char* mangled = "_Z6foobarv";
|
const char *mangled = "_Z6foobarv";
|
||||||
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
|
EXPECT_TRUE(Demangle(mangled, tmp, sizeof(tmp)));
|
||||||
// sizeof("foobar()") == size - 1
|
// sizeof("foobar()") == size - 1
|
||||||
EXPECT_STREQ(demangled, tmp);
|
EXPECT_STREQ(demangled, tmp);
|
||||||
@ -144,11 +147,11 @@ TEST(Demangle, FromFile) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
InitGoogleTest(&argc, argv);
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
#ifdef GLOG_USE_GFLAGS
|
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
#endif
|
#endif
|
||||||
|
InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
|
|||||||
@ -143,10 +143,3 @@ _Zrm1XS_ operator%()
|
|||||||
# Template argument packs can start with I or J.
|
# Template argument packs can start with I or J.
|
||||||
_Z3addIIiEEvDpT_ add<>()
|
_Z3addIIiEEvDpT_ add<>()
|
||||||
_Z3addIJiEEvDpT_ add<>()
|
_Z3addIJiEEvDpT_ add<>()
|
||||||
|
|
||||||
# Nested templates with pack expansion
|
|
||||||
_ZSt13__invoke_implIvPFvPiEJDnEET_St14__invoke_otherOT0_DpOT1_ std::__invoke_impl<>()
|
|
||||||
_ZSt8__invokeIPFvPiEJDnEENSt15__invoke_resultIT_JDpT0_EE4typeEOS4_DpOS5_ std::__invoke<>()
|
|
||||||
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEE9_M_invokeIJLm0ELm1EEEEvSt12_Index_tupleIJXspT_EEE std::thread::_Invoker<>::_M_invoke<>()
|
|
||||||
_ZNSt6thread8_InvokerISt5tupleIJPFvPiEDnEEEclEv std::thread::_Invoker<>::operator()()
|
|
||||||
_ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJPFvPiEDnEEEEE6_M_runEv std::thread::_State_impl<>::_M_run()
|
|
||||||
|
|||||||
158
src/flags.cc
158
src/flags.cc
@ -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");
|
|
||||||
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "demangle.h"
|
#include "demangle.h"
|
||||||
|
|
||||||
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* Data,
|
extern "C" int LLVMFuzzerTestOneInput(const unsigned char *Data,
|
||||||
unsigned Size) {
|
unsigned Size) {
|
||||||
if (Size >= 4095) {
|
if (Size >= 4095) {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
191
src/glog/flags.h
191
src/glog/flags.h
@ -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
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2023, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -30,16 +30,6 @@
|
|||||||
#ifndef BASE_LOG_SEVERITY_H__
|
#ifndef BASE_LOG_SEVERITY_H__
|
||||||
#define BASE_LOG_SEVERITY_H__
|
#define BASE_LOG_SEVERITY_H__
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_EXPORT)
|
|
||||||
# error <glog/log_severity.h> was not included correctly. See the documentation for how to consume the library.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace google {
|
|
||||||
|
|
||||||
// The recommended semantics of the log levels are as follows:
|
// The recommended semantics of the log levels are as follows:
|
||||||
//
|
//
|
||||||
// INFO:
|
// INFO:
|
||||||
@ -58,43 +48,27 @@ namespace google {
|
|||||||
// Variables of type LogSeverity are widely taken to lie in the range
|
// Variables of type LogSeverity are widely taken to lie in the range
|
||||||
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
|
// [0, NUM_SEVERITIES-1]. Be careful to preserve this assumption if
|
||||||
// you ever need to change their values or add a new severity.
|
// you ever need to change their values or add a new severity.
|
||||||
|
using LogSeverity = int;
|
||||||
|
|
||||||
enum LogSeverity {
|
const int GLOG_INFO = 0, GLOG_WARNING = 1, GLOG_ERROR = 2, GLOG_FATAL = 3,
|
||||||
GLOG_INFO = 0,
|
NUM_SEVERITIES = 4;
|
||||||
GLOG_WARNING = 1,
|
|
||||||
GLOG_ERROR = 2,
|
|
||||||
GLOG_FATAL = 3,
|
|
||||||
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
|
#ifndef GLOG_NO_ABBREVIATED_SEVERITIES
|
||||||
# ifdef ERROR
|
# ifdef ERROR
|
||||||
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
# error ERROR macro is defined. Define GLOG_NO_ABBREVIATED_SEVERITIES before including logging.h. See the document for detail.
|
||||||
# endif
|
# endif
|
||||||
INFO = GLOG_INFO,
|
const int INFO = GLOG_INFO, WARNING = GLOG_WARNING,
|
||||||
WARNING = GLOG_WARNING,
|
ERROR = GLOG_ERROR, FATAL = GLOG_FATAL;
|
||||||
ERROR = GLOG_ERROR,
|
|
||||||
FATAL = GLOG_FATAL
|
|
||||||
#endif
|
#endif
|
||||||
};
|
|
||||||
|
|
||||||
#if defined(__cpp_inline_variables)
|
|
||||||
# if (__cpp_inline_variables >= 201606L)
|
|
||||||
# define GLOG_INLINE_VARIABLE inline
|
|
||||||
# endif // (__cpp_inline_variables >= 201606L)
|
|
||||||
#endif // defined(__cpp_inline_variables)
|
|
||||||
|
|
||||||
#if !defined(GLOG_INLINE_VARIABLE)
|
|
||||||
# define GLOG_INLINE_VARIABLE
|
|
||||||
#endif // !defined(GLOG_INLINE_VARIABLE)
|
|
||||||
|
|
||||||
GLOG_INLINE_VARIABLE
|
|
||||||
constexpr int NUM_SEVERITIES = 4;
|
|
||||||
|
|
||||||
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
// DFATAL is FATAL in debug mode, ERROR in normal mode
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
# define DFATAL_LEVEL ERROR
|
#define DFATAL_LEVEL ERROR
|
||||||
#else
|
#else
|
||||||
# define DFATAL_LEVEL FATAL
|
#define DFATAL_LEVEL FATAL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
extern GLOG_EXPORT const char* const LogSeverityNames[NUM_SEVERITIES];
|
||||||
|
|
||||||
// NDEBUG usage helpers related to (RAW_)DCHECK:
|
// NDEBUG usage helpers related to (RAW_)DCHECK:
|
||||||
//
|
//
|
||||||
// DEBUG_MODE is for small !NDEBUG uses like
|
// DEBUG_MODE is for small !NDEBUG uses like
|
||||||
@ -115,12 +89,10 @@ constexpr int NUM_SEVERITIES = 4;
|
|||||||
//
|
//
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
enum { DEBUG_MODE = 0 };
|
enum { DEBUG_MODE = 0 };
|
||||||
# define IF_DEBUG_MODE(x)
|
#define IF_DEBUG_MODE(x)
|
||||||
#else
|
#else
|
||||||
enum { DEBUG_MODE = 1 };
|
enum { DEBUG_MODE = 1 };
|
||||||
# define IF_DEBUG_MODE(x) x
|
#define IF_DEBUG_MODE(x) x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // BASE_LOG_SEVERITY_H__
|
#endif // BASE_LOG_SEVERITY_H__
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -35,27 +35,26 @@
|
|||||||
#define GLOG_PLATFORM_H
|
#define GLOG_PLATFORM_H
|
||||||
|
|
||||||
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
|
||||||
# define GLOG_OS_WINDOWS
|
#define GLOG_OS_WINDOWS
|
||||||
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
|
#elif defined(__CYGWIN__) || defined(__CYGWIN32__)
|
||||||
# define GLOG_OS_CYGWIN
|
#define GLOG_OS_CYGWIN
|
||||||
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
#elif defined(linux) || defined(__linux) || defined(__linux__)
|
||||||
# define GLOG_OS_LINUX
|
#ifndef GLOG_OS_LINUX
|
||||||
# if defined(__ANDROID__)
|
#define GLOG_OS_LINUX
|
||||||
# define GLOG_OS_ANDROID
|
#endif
|
||||||
# endif
|
|
||||||
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
#elif defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
|
||||||
# define GLOG_OS_MACOSX
|
#define GLOG_OS_MACOSX
|
||||||
#elif defined(__FreeBSD__)
|
#elif defined(__FreeBSD__)
|
||||||
# define GLOG_OS_FREEBSD
|
#define GLOG_OS_FREEBSD
|
||||||
#elif defined(__NetBSD__)
|
#elif defined(__NetBSD__)
|
||||||
# define GLOG_OS_NETBSD
|
#define GLOG_OS_NETBSD
|
||||||
#elif defined(__OpenBSD__)
|
#elif defined(__OpenBSD__)
|
||||||
# define GLOG_OS_OPENBSD
|
#define GLOG_OS_OPENBSD
|
||||||
#elif defined(__EMSCRIPTEN__)
|
#elif defined(__EMSCRIPTEN__)
|
||||||
# define GLOG_OS_EMSCRIPTEN
|
#define GLOG_OS_EMSCRIPTEN
|
||||||
#else
|
#else
|
||||||
// TODO(hamaji): Add other platforms.
|
// TODO(hamaji): Add other platforms.
|
||||||
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
|
#error Platform not supported by glog. Please consider to contribute platform information by submitting a pull request on Github.
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif // GLOG_PLATFORM_H
|
#endif // GLOG_PLATFORM_H
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -36,18 +36,17 @@
|
|||||||
#ifndef GLOG_RAW_LOGGING_H
|
#ifndef GLOG_RAW_LOGGING_H
|
||||||
#define GLOG_RAW_LOGGING_H
|
#define GLOG_RAW_LOGGING_H
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
#include <ctime>
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_EXPORT)
|
|
||||||
# error <glog/raw_logging.h> was not included correctly. See the documentation for how to consume the library.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
@ac_google_start_namespace@
|
||||||
#include "glog/log_severity.h"
|
#include "glog/log_severity.h"
|
||||||
|
#include "glog/logging.h"
|
||||||
#include "glog/vlog_is_on.h"
|
#include "glog/vlog_is_on.h"
|
||||||
|
|
||||||
namespace google {
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wvariadic-macros"
|
||||||
|
#endif
|
||||||
|
|
||||||
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
|
// This is similar to LOG(severity) << format... and VLOG(level) << format..,
|
||||||
// but
|
// but
|
||||||
@ -63,101 +62,108 @@ namespace google {
|
|||||||
// These will print an almost standard log lines like this to stderr only:
|
// These will print an almost standard log lines like this to stderr only:
|
||||||
// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
|
// E20200821 211317 file.cc:123] RAW: Failed foo with 22: bad_file
|
||||||
// I20200821 211317 file.cc:142] RAW: status is 20
|
// I20200821 211317 file.cc:142] RAW: status is 20
|
||||||
#define RAW_LOG(severity, ...) \
|
#define RAW_LOG(severity, ...) \
|
||||||
do { \
|
do { \
|
||||||
switch (google::GLOG_##severity) { \
|
switch (@ac_google_namespace@::GLOG_ ## severity) { \
|
||||||
case 0: \
|
case 0: \
|
||||||
RAW_LOG_INFO(__VA_ARGS__); \
|
RAW_LOG_INFO(__VA_ARGS__); \
|
||||||
break; \
|
break; \
|
||||||
case 1: \
|
case 1: \
|
||||||
RAW_LOG_WARNING(__VA_ARGS__); \
|
RAW_LOG_WARNING(__VA_ARGS__); \
|
||||||
break; \
|
break; \
|
||||||
case 2: \
|
case 2: \
|
||||||
RAW_LOG_ERROR(__VA_ARGS__); \
|
RAW_LOG_ERROR(__VA_ARGS__); \
|
||||||
break; \
|
break; \
|
||||||
case 3: \
|
case 3: \
|
||||||
RAW_LOG_FATAL(__VA_ARGS__); \
|
RAW_LOG_FATAL(__VA_ARGS__); \
|
||||||
break; \
|
break; \
|
||||||
default: \
|
default: \
|
||||||
break; \
|
break; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// The following STRIP_LOG testing is performed in the header file so that it's
|
// 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.
|
// possible to completely compile out the logging code and the log messages.
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
||||||
# define RAW_VLOG(verboselevel, ...) \
|
#define RAW_VLOG(verboselevel, ...) \
|
||||||
do { \
|
do { \
|
||||||
if (VLOG_IS_ON(verboselevel)) { \
|
if (VLOG_IS_ON(verboselevel)) { \
|
||||||
RAW_LOG_INFO(__VA_ARGS__); \
|
RAW_LOG_INFO(__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
# define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
|
#define RAW_VLOG(verboselevel, ...) RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG == 0
|
#endif // STRIP_LOG == 0
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
#if !defined(STRIP_LOG) || STRIP_LOG == 0
|
||||||
# define RAW_LOG_INFO(...) \
|
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_INFO, \
|
||||||
google::RawLog__(google::GLOG_INFO, __FILE__, __LINE__, __VA_ARGS__)
|
__FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define RAW_LOG_INFO(...) google::RawLogStub__(0, __VA_ARGS__)
|
#define RAW_LOG_INFO(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG == 0
|
#endif // STRIP_LOG == 0
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 1
|
||||||
# define RAW_LOG_WARNING(...) \
|
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_WARNING, \
|
||||||
google::RawLog__(google::GLOG_WARNING, __FILE__, __LINE__, __VA_ARGS__)
|
__FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define RAW_LOG_WARNING(...) google::RawLogStub__(0, __VA_ARGS__)
|
#define RAW_LOG_WARNING(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG <= 1
|
#endif // STRIP_LOG <= 1
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 2
|
||||||
# define RAW_LOG_ERROR(...) \
|
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_ERROR, \
|
||||||
google::RawLog__(google::GLOG_ERROR, __FILE__, __LINE__, __VA_ARGS__)
|
__FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define RAW_LOG_ERROR(...) google::RawLogStub__(0, __VA_ARGS__)
|
#define RAW_LOG_ERROR(...) @ac_google_namespace@::RawLogStub__(0, __VA_ARGS__)
|
||||||
#endif // STRIP_LOG <= 2
|
#endif // STRIP_LOG <= 2
|
||||||
|
|
||||||
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
|
#if !defined(STRIP_LOG) || STRIP_LOG <= 3
|
||||||
# define RAW_LOG_FATAL(...) \
|
#define RAW_LOG_FATAL(...) @ac_google_namespace@::RawLog__(@ac_google_namespace@::GLOG_FATAL, \
|
||||||
google::RawLog__(google::GLOG_FATAL, __FILE__, __LINE__, __VA_ARGS__)
|
__FILE__, __LINE__, __VA_ARGS__)
|
||||||
#else
|
#else
|
||||||
# define RAW_LOG_FATAL(...) \
|
#define RAW_LOG_FATAL(...) \
|
||||||
do { \
|
do { \
|
||||||
google::RawLogStub__(0, __VA_ARGS__); \
|
@ac_google_namespace@::RawLogStub__(0, __VA_ARGS__); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif // STRIP_LOG <= 3
|
#endif // STRIP_LOG <= 3
|
||||||
|
|
||||||
// Similar to CHECK(condition) << message,
|
// Similar to CHECK(condition) << message,
|
||||||
// but for low-level modules: we use only RAW_LOG that does not allocate memory.
|
// but for low-level modules: we use only RAW_LOG that does not allocate memory.
|
||||||
// We do not want to provide args list here to encourage this usage:
|
// We do not want to provide args list here to encourage this usage:
|
||||||
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
|
// if (!cond) RAW_LOG(FATAL, "foo ...", hard_to_compute_args);
|
||||||
// so that the args are not computed when not needed.
|
// so that the args are not computed when not needed.
|
||||||
#define RAW_CHECK(condition, message) \
|
#define RAW_CHECK(condition, message) \
|
||||||
do { \
|
do { \
|
||||||
if (!(condition)) { \
|
if (!(condition)) { \
|
||||||
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
|
RAW_LOG(FATAL, "Check %s failed: %s", #condition, message); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
// Debug versions of RAW_LOG and RAW_CHECK
|
// Debug versions of RAW_LOG and RAW_CHECK
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
|
|
||||||
# define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
|
#define RAW_DLOG(severity, ...) RAW_LOG(severity, __VA_ARGS__)
|
||||||
# define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
|
#define RAW_DCHECK(condition, message) RAW_CHECK(condition, message)
|
||||||
|
|
||||||
#else // NDEBUG
|
#else // NDEBUG
|
||||||
|
|
||||||
# define RAW_DLOG(severity, ...) \
|
#define RAW_DLOG(severity, ...) \
|
||||||
while (false) RAW_LOG(severity, __VA_ARGS__)
|
while (false) \
|
||||||
# define RAW_DCHECK(condition, message) \
|
RAW_LOG(severity, __VA_ARGS__)
|
||||||
while (false) RAW_CHECK(condition, message)
|
#define RAW_DCHECK(condition, message) \
|
||||||
|
while (false) \
|
||||||
|
RAW_CHECK(condition, message)
|
||||||
|
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
// Stub log function used to work around for unused variable warnings when
|
// Stub log function used to work around for unused variable warnings when
|
||||||
// building with STRIP_LOG > 0.
|
// building with STRIP_LOG > 0.
|
||||||
static inline void RawLogStub__(int /* ignored */, ...) {}
|
static inline void RawLogStub__(int /* ignored */, ...) {
|
||||||
|
}
|
||||||
|
|
||||||
// Helper function to implement RAW_LOG and RAW_VLOG
|
// Helper function to implement RAW_LOG and RAW_VLOG
|
||||||
// Logs format... at "severity" level, reporting it
|
// Logs format... at "severity" level, reporting it
|
||||||
@ -165,12 +171,8 @@ static inline void RawLogStub__(int /* ignored */, ...) {}
|
|||||||
// This does not allocate memory or acquire locks.
|
// This does not allocate memory or acquire locks.
|
||||||
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
|
GLOG_EXPORT void RawLog__(LogSeverity severity, const char* file, int line,
|
||||||
const char* format, ...)
|
const char* format, ...)
|
||||||
#if defined(__has_attribute)
|
@ac_cv___attribute___printf_4_5@;
|
||||||
# if __has_attribute(used)
|
|
||||||
__attribute__((__format__(__printf__, 4, 5)))
|
@ac_google_end_namespace@
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // GLOG_RAW_LOGGING_H
|
#endif // GLOG_RAW_LOGGING_H
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2023, Google Inc.
|
// Copyright (c) 2003, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -35,9 +35,17 @@
|
|||||||
// vector<int> v1, v2;
|
// vector<int> v1, v2;
|
||||||
// CHECK_EQ(v1, v2);
|
// CHECK_EQ(v1, v2);
|
||||||
//
|
//
|
||||||
|
// If you want to use this header file with hash maps or slist, you
|
||||||
|
// need to define macros before including this file:
|
||||||
|
//
|
||||||
|
// - GLOG_STL_LOGGING_FOR_UNORDERED - <unordered_map> and <unordered_set>
|
||||||
|
// - GLOG_STL_LOGGING_FOR_TR1_UNORDERED - <tr1/unordered_(map|set)>
|
||||||
|
// - GLOG_STL_LOGGING_FOR_EXT_HASH - <ext/hash_(map|set)>
|
||||||
|
// - GLOG_STL_LOGGING_FOR_EXT_SLIST - <ext/slist>
|
||||||
|
//
|
||||||
|
|
||||||
#ifndef GLOG_STL_LOGGING_H
|
#ifndef UTIL_GTL_STL_LOGGING_INL_H_
|
||||||
#define GLOG_STL_LOGGING_H
|
#define UTIL_GTL_STL_LOGGING_INL_H_
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <list>
|
#include <list>
|
||||||
@ -52,78 +60,81 @@
|
|||||||
// Forward declare these two, and define them after all the container streams
|
// Forward declare these two, and define them after all the container streams
|
||||||
// operators so that we can recurse from pair -> container -> container -> pair
|
// operators so that we can recurse from pair -> container -> container -> pair
|
||||||
// properly.
|
// properly.
|
||||||
template <class First, class Second>
|
template<class First, class Second>
|
||||||
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
|
std::ostream& operator<<(std::ostream& out, const std::pair<First, Second>& p);
|
||||||
|
|
||||||
namespace google {
|
@ac_google_start_namespace@
|
||||||
|
|
||||||
template <class Iter>
|
template<class Iter>
|
||||||
void PrintSequence(std::ostream& out, Iter begin, Iter end);
|
void PrintSequence(std::ostream& out, Iter begin, Iter end);
|
||||||
|
|
||||||
|
@ac_google_end_namespace@
|
||||||
|
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
|
||||||
|
template<class T1, class T2> \
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, \
|
||||||
|
const Sequence<T1, T2>& seq) { \
|
||||||
|
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
|
||||||
|
return out; \
|
||||||
}
|
}
|
||||||
#define OUTPUT_TWO_ARG_CONTAINER(Sequence) \
|
|
||||||
template <class T1, class T2> \
|
|
||||||
inline std::ostream& operator<<(std::ostream& out, \
|
|
||||||
const Sequence<T1, T2>& seq) { \
|
|
||||||
google::PrintSequence(out, seq.begin(), seq.end()); \
|
|
||||||
return out; \
|
|
||||||
}
|
|
||||||
|
|
||||||
OUTPUT_TWO_ARG_CONTAINER(std::vector)
|
OUTPUT_TWO_ARG_CONTAINER(std::vector) OUTPUT_TWO_ARG_CONTAINER(std::deque)
|
||||||
OUTPUT_TWO_ARG_CONTAINER(std::deque)
|
OUTPUT_TWO_ARG_CONTAINER(std::list)
|
||||||
OUTPUT_TWO_ARG_CONTAINER(std::list)
|
|
||||||
#undef OUTPUT_TWO_ARG_CONTAINER
|
#undef OUTPUT_TWO_ARG_CONTAINER
|
||||||
|
|
||||||
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
|
#define OUTPUT_THREE_ARG_CONTAINER(Sequence) \
|
||||||
template <class T1, class T2, class T3> \
|
template<class T1, class T2, class T3> \
|
||||||
inline std::ostream& operator<<(std::ostream& out, \
|
inline std::ostream& operator<<(std::ostream& out, \
|
||||||
const Sequence<T1, T2, T3>& seq) { \
|
const Sequence<T1, T2, T3>& seq) { \
|
||||||
google::PrintSequence(out, seq.begin(), seq.end()); \
|
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
|
||||||
return out; \
|
return out; \
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTPUT_THREE_ARG_CONTAINER(std::set)
|
OUTPUT_THREE_ARG_CONTAINER(std::set) OUTPUT_THREE_ARG_CONTAINER(
|
||||||
OUTPUT_THREE_ARG_CONTAINER(std::multiset)
|
std::multiset)
|
||||||
|
|
||||||
#undef OUTPUT_THREE_ARG_CONTAINER
|
#undef OUTPUT_THREE_ARG_CONTAINER
|
||||||
|
|
||||||
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
|
#define OUTPUT_FOUR_ARG_CONTAINER(Sequence) \
|
||||||
template <class T1, class T2, class T3, class T4> \
|
template<class T1, class T2, class T3, class T4> \
|
||||||
inline std::ostream& operator<<(std::ostream& out, \
|
inline std::ostream& operator<<(std::ostream& out, \
|
||||||
const Sequence<T1, T2, T3, T4>& seq) { \
|
const Sequence<T1, T2, T3, T4>& seq) { \
|
||||||
google::PrintSequence(out, seq.begin(), seq.end()); \
|
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
|
||||||
return out; \
|
return out; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OUTPUT_FOUR_ARG_CONTAINER(std::map) OUTPUT_FOUR_ARG_CONTAINER(
|
||||||
|
std::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
|
#undef OUTPUT_FOUR_ARG_CONTAINER
|
||||||
|
|
||||||
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
|
#define OUTPUT_FIVE_ARG_CONTAINER(Sequence) \
|
||||||
template <class T1, class T2, class T3, class T4, class T5> \
|
template<class T1, class T2, class T3, class T4, class T5> \
|
||||||
inline std::ostream& operator<<(std::ostream& out, \
|
inline std::ostream& operator<<(std::ostream& out, \
|
||||||
const Sequence<T1, T2, T3, T4, T5>& seq) { \
|
const Sequence<T1, T2, T3, T4, T5>& seq) { \
|
||||||
google::PrintSequence(out, seq.begin(), seq.end()); \
|
@ac_google_namespace@::PrintSequence(out, seq.begin(), seq.end()); \
|
||||||
return out; \
|
return out; \
|
||||||
}
|
}
|
||||||
|
|
||||||
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
|
#if defined(GLOG_STL_LOGGING_FOR_UNORDERED) && __cplusplus >= 201103L
|
||||||
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
|
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_map)
|
||||||
|
OUTPUT_FIVE_ARG_CONTAINER(std::unordered_multimap)
|
||||||
|
#endif
|
||||||
|
|
||||||
#undef OUTPUT_FIVE_ARG_CONTAINER
|
#undef OUTPUT_FIVE_ARG_CONTAINER
|
||||||
|
|
||||||
template <class First, class Second>
|
template <class First, class Second>
|
||||||
inline std::ostream& operator<<(std::ostream& out,
|
inline std::ostream& operator<<(
|
||||||
const std::pair<First, Second>& p) {
|
std::ostream& out,
|
||||||
|
const std::pair<First, Second>& p) {
|
||||||
out << '(' << p.first << ", " << p.second << ')';
|
out << '(' << p.first << ", " << p.second << ')';
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace google {
|
@ac_google_start_namespace@
|
||||||
|
|
||||||
template <class Iter>
|
template<class Iter>
|
||||||
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
||||||
// Output at most 100 elements -- appropriate if used for logging.
|
// Output at most 100 elements -- appropriate if used for logging.
|
||||||
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
|
for (int i = 0; begin != end && i < 100; ++i, ++begin) {
|
||||||
@ -135,7 +146,7 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
@ac_google_end_namespace@
|
||||||
|
|
||||||
// Note that this is technically undefined behavior! We are adding things into
|
// Note that this is technically undefined behavior! We are adding things into
|
||||||
// the std namespace for a reason though -- we are providing new operations on
|
// the std namespace for a reason though -- we are providing new operations on
|
||||||
@ -161,8 +172,6 @@ inline void PrintSequence(std::ostream& out, Iter begin, Iter end) {
|
|||||||
// move all of the *definitions* into namespace std, bet we need to ensure no
|
// move all of the *definitions* into namespace std, bet we need to ensure no
|
||||||
// one references them first. This lets us take that step. We cannot define them
|
// one references them first. This lets us take that step. We cannot define them
|
||||||
// in both because that would create ambiguous overloads when both are found.
|
// in both because that would create ambiguous overloads when both are found.
|
||||||
namespace std {
|
namespace std { using ::operator<<; }
|
||||||
using ::operator<<;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // GLOG_STL_LOGGING_H
|
#endif // UTIL_GTL_STL_LOGGING_INL_H_
|
||||||
@ -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
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2023, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -58,21 +58,12 @@
|
|||||||
// CAVEAT: --vmodule functionality is not available in non gcc compilers.
|
// CAVEAT: --vmodule functionality is not available in non gcc compilers.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef GLOG_VLOG_IS_ON_H
|
#ifndef BASE_VLOG_IS_ON_H_
|
||||||
#define GLOG_VLOG_IS_ON_H
|
#define BASE_VLOG_IS_ON_H_
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
#include "glog/log_severity.h"
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_EXPORT)
|
|
||||||
# error <glog/vlog_is_on.h> was not included correctly. See the documentation for how to consume the library.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "glog/flags.h"
|
|
||||||
#include "glog/types.h"
|
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
|
// We emit an anonymous static int* variable at every VLOG_IS_ON(n) site.
|
||||||
@ -81,25 +72,21 @@
|
|||||||
// it's either FLAGS_v or an appropriate internal variable
|
// it's either FLAGS_v or an appropriate internal variable
|
||||||
// matching the current source file that represents results of
|
// matching the current source file that represents results of
|
||||||
// parsing of --vmodule flag and/or SetVLOGLevel calls.
|
// parsing of --vmodule flag and/or SetVLOGLevel calls.
|
||||||
# define VLOG_IS_ON(verboselevel) \
|
#define VLOG_IS_ON(verboselevel) \
|
||||||
__extension__({ \
|
__extension__ \
|
||||||
static google::SiteFlag vlocal__ = {nullptr, nullptr, 0, nullptr}; \
|
({ static @ac_google_namespace@::SiteFlag vlocal__ = {NULL, NULL, 0, NULL}; \
|
||||||
GLOG_IFDEF_THREAD_SANITIZER(AnnotateBenignRaceSized( \
|
GLOG_IFDEF_THREAD_SANITIZER( \
|
||||||
__FILE__, __LINE__, &vlocal__, sizeof(google::SiteFlag), "")); \
|
AnnotateBenignRaceSized(__FILE__, __LINE__, &vlocal__, sizeof(@ac_google_namespace@::SiteFlag), "")); \
|
||||||
google::int32 verbose_level__ = (verboselevel); \
|
@ac_google_namespace@::int32 verbose_level__ = (verboselevel); \
|
||||||
(vlocal__.level == nullptr \
|
(vlocal__.level == NULL ? @ac_google_namespace@::InitVLOG3__(&vlocal__, &FLAGS_v, \
|
||||||
? google::InitVLOG3__(&vlocal__, &FLAGS_v, __FILE__, \
|
__FILE__, verbose_level__) : *vlocal__.level >= verbose_level__); \
|
||||||
verbose_level__) \
|
})
|
||||||
: *vlocal__.level >= verbose_level__); \
|
|
||||||
})
|
|
||||||
#else
|
#else
|
||||||
// GNU extensions not available, so we do not support --vmodule.
|
// GNU extensions not available, so we do not support --vmodule.
|
||||||
// Dynamic value of FLAGS_v always controls the logging level.
|
// 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
|
#endif
|
||||||
|
|
||||||
namespace google {
|
|
||||||
|
|
||||||
// Set VLOG(_IS_ON) level for module_pattern to log_level.
|
// Set VLOG(_IS_ON) level for module_pattern to log_level.
|
||||||
// This lets us dynamically control what is normally set by the --vmodule flag.
|
// This lets us dynamically control what is normally set by the --vmodule flag.
|
||||||
// Returns the level that previously applied to module_pattern.
|
// Returns the level that previously applied to module_pattern.
|
||||||
@ -113,7 +100,7 @@ extern GLOG_EXPORT int SetVLOGLevel(const char* module_pattern, int log_level);
|
|||||||
// Various declarations needed for VLOG_IS_ON above: =========================
|
// Various declarations needed for VLOG_IS_ON above: =========================
|
||||||
|
|
||||||
struct SiteFlag {
|
struct SiteFlag {
|
||||||
int32* level;
|
@ac_google_namespace@::int32* level;
|
||||||
const char* base_name;
|
const char* base_name;
|
||||||
std::size_t base_len;
|
std::size_t base_len;
|
||||||
SiteFlag* next;
|
SiteFlag* next;
|
||||||
@ -127,10 +114,9 @@ struct SiteFlag {
|
|||||||
// verbose_level is the argument to VLOG_IS_ON
|
// verbose_level is the argument to VLOG_IS_ON
|
||||||
// We will return the return value for VLOG_IS_ON
|
// We will return the return value for VLOG_IS_ON
|
||||||
// and if possible set *site_flag appropriately.
|
// and if possible set *site_flag appropriately.
|
||||||
extern GLOG_EXPORT bool InitVLOG3__(SiteFlag* site_flag,
|
extern GLOG_EXPORT bool InitVLOG3__(
|
||||||
int32* site_default,
|
@ac_google_namespace@::SiteFlag* site_flag,
|
||||||
const char* fname,
|
@ac_google_namespace@::int32* site_default, const char* fname,
|
||||||
int32 verbose_level);
|
@ac_google_namespace@::int32 verbose_level);
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // GLOG_VLOG_IS_ON_H
|
#endif // BASE_VLOG_IS_ON_H_
|
||||||
415
src/googletest.h
415
src/googletest.h
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2009, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -31,7 +31,7 @@
|
|||||||
// (based on googletest: http://code.google.com/p/googletest/)
|
// (based on googletest: http://code.google.com/p/googletest/)
|
||||||
|
|
||||||
#ifdef GOOGLETEST_H__
|
#ifdef GOOGLETEST_H__
|
||||||
# error You must not include this file twice.
|
#error You must not include this file twice.
|
||||||
#endif
|
#endif
|
||||||
#define GOOGLETEST_H__
|
#define GOOGLETEST_H__
|
||||||
|
|
||||||
@ -51,40 +51,35 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "config.h"
|
#include "utilities.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h>
|
# include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(GLOG_USE_WINDOWS_PORT)
|
|
||||||
# include "port.h"
|
|
||||||
#endif // defined(GLOG_USE_WINDOWS_PORT)
|
|
||||||
#include "base/commandlineflags.h"
|
#include "base/commandlineflags.h"
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
#if __cplusplus < 201103L && !defined(_MSC_VER)
|
#if __cplusplus < 201103L && !defined(_MSC_VER)
|
||||||
# define GOOGLE_GLOG_THROW_BAD_ALLOC throw(std::bad_alloc)
|
#define GOOGLE_GLOG_THROW_BAD_ALLOC throw (std::bad_alloc)
|
||||||
#else
|
#else
|
||||||
# define GOOGLE_GLOG_THROW_BAD_ALLOC
|
#define GOOGLE_GLOG_THROW_BAD_ALLOC
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using std::map;
|
using std::map;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
extern void (*g_logging_fail_func)();
|
|
||||||
extern void GetExistingTempDirectories(std::vector<std::string>& list);
|
extern GLOG_EXPORT void (*g_logging_fail_func)();
|
||||||
extern int posix_strerror_r(int err, char* buf, size_t len);
|
|
||||||
extern std::string StrError(int err);
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#undef GLOG_EXPORT
|
#undef GLOG_EXPORT
|
||||||
#define GLOG_EXPORT
|
#define GLOG_EXPORT
|
||||||
|
|
||||||
static inline string GetTempDir() {
|
static inline string GetTempDir() {
|
||||||
vector<string> temp_directories_list;
|
vector<string> temp_directories_list;
|
||||||
google::GetExistingTempDirectories(temp_directories_list);
|
google::GetExistingTempDirectories(&temp_directories_list);
|
||||||
|
|
||||||
if (temp_directories_list.empty()) {
|
if (temp_directories_list.empty()) {
|
||||||
fprintf(stderr, "No temporary directory found\n");
|
fprintf(stderr, "No temporary directory found\n");
|
||||||
@ -100,7 +95,7 @@ static inline string GetTempDir() {
|
|||||||
// (e.g., glog/vsproject/logging_unittest).
|
// (e.g., glog/vsproject/logging_unittest).
|
||||||
static const char TEST_SRC_DIR[] = "../..";
|
static const char TEST_SRC_DIR[] = "../..";
|
||||||
#elif !defined(TEST_SRC_DIR)
|
#elif !defined(TEST_SRC_DIR)
|
||||||
# warning TEST_SRC_DIR should be defined in config.h
|
# warning TEST_SRC_DIR should be defined in config.h
|
||||||
static const char TEST_SRC_DIR[] = ".";
|
static const char TEST_SRC_DIR[] = ".";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -117,14 +112,14 @@ DEFINE_int32(benchmark_iters, 100000, "Number of iterations per benchmark");
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_LIB_GTEST
|
#ifdef HAVE_LIB_GTEST
|
||||||
# include <gtest/gtest.h>
|
# include <gtest/gtest.h>
|
||||||
// Use our ASSERT_DEATH implementation.
|
// Use our ASSERT_DEATH implementation.
|
||||||
# undef ASSERT_DEATH
|
# undef ASSERT_DEATH
|
||||||
# undef ASSERT_DEBUG_DEATH
|
# undef ASSERT_DEBUG_DEATH
|
||||||
using testing::InitGoogleTest;
|
using testing::InitGoogleTest;
|
||||||
#else
|
#else
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
void InitGoogleTest(int*, char**);
|
void InitGoogleTest(int*, char**);
|
||||||
|
|
||||||
@ -132,94 +127,81 @@ void InitGoogleTest(int*, char**) {}
|
|||||||
|
|
||||||
// The following is some bare-bones testing infrastructure
|
// The following is some bare-bones testing infrastructure
|
||||||
|
|
||||||
# define EXPECT_NEAR(val1, val2, abs_error) \
|
#define EXPECT_NEAR(val1, val2, abs_error) \
|
||||||
do { \
|
do { \
|
||||||
if (abs(val1 - val2) > abs_error) { \
|
if (abs(val1 - val2) > abs_error) { \
|
||||||
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, \
|
fprintf(stderr, "Check failed: %s within %s of %s\n", #val1, #abs_error, \
|
||||||
#abs_error, #val2); \
|
#val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_TRUE(cond) \
|
#define EXPECT_TRUE(cond) \
|
||||||
do { \
|
do { \
|
||||||
if (!(cond)) { \
|
if (!(cond)) { \
|
||||||
fprintf(stderr, "Check failed: %s\n", #cond); \
|
fprintf(stderr, "Check failed: %s\n", #cond); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} 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 { \
|
do { \
|
||||||
if (!((val1)op(val2))) { \
|
if (!((val1) op (val2))) { \
|
||||||
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
fprintf(stderr, "Check failed: %s %s %s\n", #val1, #op, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_EQ(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_NE(val1, val2) EXPECT_OP(!=, val1, val2)
|
||||||
# define EXPECT_GT(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_LT(val1, val2) EXPECT_OP(<, val1, val2)
|
||||||
|
|
||||||
# define EXPECT_NAN(arg) \
|
#define EXPECT_NAN(arg) \
|
||||||
do { \
|
do { \
|
||||||
if (!isnan(arg)) { \
|
if (!isnan(arg)) { \
|
||||||
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
fprintf(stderr, "Check failed: isnan(%s)\n", #arg); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_INF(arg) \
|
#define EXPECT_INF(arg) \
|
||||||
do { \
|
do { \
|
||||||
if (!isinf(arg)) { \
|
if (!isinf(arg)) { \
|
||||||
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
fprintf(stderr, "Check failed: isinf(%s)\n", #arg); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_DOUBLE_EQ(val1, val2) \
|
#define EXPECT_DOUBLE_EQ(val1, val2) \
|
||||||
do { \
|
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); \
|
fprintf(stderr, "Check failed: %s == %s\n", #val1, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_STREQ(val1, val2) \
|
#define EXPECT_STREQ(val1, val2) \
|
||||||
do { \
|
do { \
|
||||||
if (strcmp((val1), (val2)) != 0) { \
|
if (strcmp((val1), (val2)) != 0) { \
|
||||||
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
fprintf(stderr, "Check failed: streq(%s, %s)\n", #val1, #val2); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
# define EXPECT_THROW(statement, exception) \
|
|
||||||
do { \
|
|
||||||
try { \
|
|
||||||
statement; \
|
|
||||||
} catch (const exception&) { \
|
|
||||||
printf("ok\n"); \
|
|
||||||
} catch (...) { \
|
|
||||||
fprintf(stderr, "%s\n", "Unexpected exception thrown"); \
|
|
||||||
exit(EXIT_FAILURE); \
|
|
||||||
} \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
vector<void (*)()> g_testlist; // the tests to run
|
vector<void (*)()> g_testlist; // the tests to run
|
||||||
# define TEST(a, b) \
|
|
||||||
struct Test_##a##_##b { \
|
#define TEST(a, b) \
|
||||||
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
struct Test_##a##_##b { \
|
||||||
static void Run() { \
|
Test_##a##_##b() { g_testlist.push_back(&Run); } \
|
||||||
FlagSaver fs; \
|
static void Run() { FlagSaver fs; RunTest(); } \
|
||||||
RunTest(); \
|
static void RunTest(); \
|
||||||
} \
|
}; \
|
||||||
static void RunTest(); \
|
static Test_##a##_##b g_test_##a##_##b; \
|
||||||
}; \
|
void Test_##a##_##b::RunTest()
|
||||||
static Test_##a##_##b g_test_##a##_##b; \
|
|
||||||
void Test_##a##_##b::RunTest()
|
|
||||||
|
|
||||||
static inline int RUN_ALL_TESTS() {
|
static inline int RUN_ALL_TESTS() {
|
||||||
vector<void (*)()>::const_iterator it;
|
vector<void (*)()>::const_iterator it;
|
||||||
@ -231,11 +213,11 @@ static inline int RUN_ALL_TESTS() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
#endif // ! HAVE_LIB_GTEST
|
#endif // ! HAVE_LIB_GTEST
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
static bool g_called_abort;
|
static bool g_called_abort;
|
||||||
static jmp_buf g_jmp_buf;
|
static jmp_buf g_jmp_buf;
|
||||||
@ -246,33 +228,33 @@ static inline void CalledAbort() {
|
|||||||
|
|
||||||
#ifdef GLOG_OS_WINDOWS
|
#ifdef GLOG_OS_WINDOWS
|
||||||
// TODO(hamaji): Death test somehow doesn't work in Windows.
|
// TODO(hamaji): Death test somehow doesn't work in Windows.
|
||||||
# define ASSERT_DEATH(fn, msg)
|
#define ASSERT_DEATH(fn, msg)
|
||||||
#else
|
#else
|
||||||
# define ASSERT_DEATH(fn, msg) \
|
#define ASSERT_DEATH(fn, msg) \
|
||||||
do { \
|
do { \
|
||||||
g_called_abort = false; \
|
g_called_abort = false; \
|
||||||
/* in logging.cc */ \
|
/* in logging.cc */ \
|
||||||
void (*original_logging_fail_func)() = g_logging_fail_func; \
|
void (*original_logging_fail_func)() = g_logging_fail_func; \
|
||||||
g_logging_fail_func = &CalledAbort; \
|
g_logging_fail_func = &CalledAbort; \
|
||||||
if (!setjmp(g_jmp_buf)) fn; \
|
if (!setjmp(g_jmp_buf)) fn; \
|
||||||
/* set back to their default */ \
|
/* set back to their default */ \
|
||||||
g_logging_fail_func = original_logging_fail_func; \
|
g_logging_fail_func = original_logging_fail_func; \
|
||||||
if (!g_called_abort) { \
|
if (!g_called_abort) { \
|
||||||
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
fprintf(stderr, "Function didn't die (%s): %s\n", msg, #fn); \
|
||||||
exit(EXIT_FAILURE); \
|
exit(EXIT_FAILURE); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
# define ASSERT_DEBUG_DEATH(fn, msg)
|
#define ASSERT_DEBUG_DEATH(fn, msg)
|
||||||
#else
|
#else
|
||||||
# define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
|
#define ASSERT_DEBUG_DEATH(fn, msg) ASSERT_DEATH(fn, msg)
|
||||||
#endif // NDEBUG
|
#endif // NDEBUG
|
||||||
|
|
||||||
// Benchmark tools.
|
// 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
|
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) /
|
double elapsed_ns = (static_cast<double>(clock()) - start) /
|
||||||
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
|
CLOCKS_PER_SEC * 1000 * 1000 * 1000;
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
# pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
# pragma GCC diagnostic ignored "-Wformat="
|
#pragma GCC diagnostic ignored "-Wformat="
|
||||||
#endif
|
#endif
|
||||||
printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
|
printf("%s\t%8.2lf\t%10d\n", iter.first.c_str(), elapsed_ns / iter_cnt,
|
||||||
iter_cnt);
|
iter_cnt);
|
||||||
#if defined(__GNUC__) && !defined(__clang__)
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
# pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
puts("");
|
puts("");
|
||||||
@ -315,69 +297,77 @@ static inline void RunSpecifiedBenchmarks() {
|
|||||||
class CapturedStream {
|
class CapturedStream {
|
||||||
public:
|
public:
|
||||||
CapturedStream(int fd, string filename)
|
CapturedStream(int fd, string filename)
|
||||||
: fd_(fd), filename_(std::move(filename)) {
|
: fd_(fd),
|
||||||
|
|
||||||
|
filename_(std::move(filename)) {
|
||||||
Capture();
|
Capture();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~CapturedStream() {
|
||||||
|
if (uncaptured_fd_ != -1) {
|
||||||
|
CHECK(close(uncaptured_fd_) != -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start redirecting output to a file
|
// Start redirecting output to a file
|
||||||
void Capture() {
|
void Capture() {
|
||||||
// Keep original stream for later
|
// Keep original stream for later
|
||||||
CHECK(!uncaptured_fd_) << ", Stream " << fd_ << " already captured!";
|
CHECK(uncaptured_fd_ == -1) << ", Stream " << fd_ << " already captured!";
|
||||||
uncaptured_fd_.reset(dup(fd_));
|
uncaptured_fd_ = dup(fd_);
|
||||||
CHECK(uncaptured_fd_);
|
CHECK(uncaptured_fd_ != -1);
|
||||||
|
|
||||||
// Open file to save stream to
|
// Open file to save stream to
|
||||||
FileDescriptor cap_fd{open(filename_.c_str(), O_CREAT | O_TRUNC | O_WRONLY,
|
int cap_fd = open(filename_.c_str(),
|
||||||
S_IRUSR | S_IWUSR)};
|
O_CREAT | O_TRUNC | O_WRONLY,
|
||||||
CHECK(cap_fd);
|
S_IRUSR | S_IWUSR);
|
||||||
|
CHECK(cap_fd != -1);
|
||||||
|
|
||||||
// Send stdout/stderr to this file
|
// Send stdout/stderr to this file
|
||||||
fflush(nullptr);
|
fflush(nullptr);
|
||||||
CHECK(dup2(cap_fd.get(), fd_) != -1);
|
CHECK(dup2(cap_fd, fd_) != -1);
|
||||||
CHECK(cap_fd.close() != -1);
|
CHECK(close(cap_fd) != -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove output redirection
|
// Remove output redirection
|
||||||
void StopCapture() {
|
void StopCapture() {
|
||||||
// Restore original stream
|
// Restore original stream
|
||||||
if (uncaptured_fd_) {
|
if (uncaptured_fd_ != -1) {
|
||||||
fflush(nullptr);
|
fflush(nullptr);
|
||||||
CHECK(dup2(uncaptured_fd_.get(), fd_) != -1);
|
CHECK(dup2(uncaptured_fd_, fd_) != -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const string& filename() const { return filename_; }
|
const string & filename() const { return filename_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int fd_; // file descriptor being captured
|
int fd_; // file descriptor being captured
|
||||||
FileDescriptor
|
int uncaptured_fd_{-1}; // where the stream was originally being sent to
|
||||||
uncaptured_fd_; // where the stream was originally being sent to
|
|
||||||
string filename_; // file where stream is being saved
|
string filename_; // file where stream is being saved
|
||||||
};
|
};
|
||||||
static std::map<int, std::unique_ptr<CapturedStream>> s_captured_streams;
|
static CapturedStream * s_captured_streams[STDERR_FILENO+1];
|
||||||
// Redirect a file descriptor to a file.
|
// Redirect a file descriptor to a file.
|
||||||
// fd - Should be stdout or stderr
|
// fd - Should be STDOUT_FILENO or STDERR_FILENO
|
||||||
// filename - File where output should be stored
|
// filename - File where output should be stored
|
||||||
static inline void CaptureTestOutput(int fd, const string& filename) {
|
static inline void CaptureTestOutput(int fd, const string & filename) {
|
||||||
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
|
CHECK((fd == STDOUT_FILENO) || (fd == STDERR_FILENO));
|
||||||
CHECK(s_captured_streams.find(fd) == s_captured_streams.end());
|
CHECK(s_captured_streams[fd] == nullptr);
|
||||||
s_captured_streams[fd] = std::make_unique<CapturedStream>(fd, filename);
|
s_captured_streams[fd] = new CapturedStream(fd, filename);
|
||||||
}
|
}
|
||||||
static inline void CaptureTestStdout() {
|
static inline void CaptureTestStdout() {
|
||||||
CaptureTestOutput(fileno(stdout), FLAGS_test_tmpdir + "/captured.out");
|
CaptureTestOutput(STDOUT_FILENO, FLAGS_test_tmpdir + "/captured.out");
|
||||||
}
|
}
|
||||||
static inline void CaptureTestStderr() {
|
static inline void CaptureTestStderr() {
|
||||||
CaptureTestOutput(fileno(stderr), FLAGS_test_tmpdir + "/captured.err");
|
CaptureTestOutput(STDERR_FILENO, FLAGS_test_tmpdir + "/captured.err");
|
||||||
}
|
}
|
||||||
// Return the size (in bytes) of a file
|
// Return the size (in bytes) of a file
|
||||||
static inline size_t GetFileSize(FILE* file) {
|
static inline size_t GetFileSize(FILE * file) {
|
||||||
fseek(file, 0, SEEK_END);
|
fseek(file, 0, SEEK_END);
|
||||||
return static_cast<size_t>(ftell(file));
|
return static_cast<size_t>(ftell(file));
|
||||||
}
|
}
|
||||||
// Read the entire content of a file as a string
|
// Read the entire content of a file as a string
|
||||||
static inline string ReadEntireFile(FILE* file) {
|
static inline string ReadEntireFile(FILE * file) {
|
||||||
const size_t file_size = GetFileSize(file);
|
const size_t file_size = GetFileSize(file);
|
||||||
std::vector<char> content(file_size);
|
char * const buffer = new char[file_size];
|
||||||
|
|
||||||
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
||||||
size_t bytes_read = 0; // # of bytes read so far
|
size_t bytes_read = 0; // # of bytes read so far
|
||||||
@ -387,33 +377,39 @@ static inline string ReadEntireFile(FILE* file) {
|
|||||||
// Keep reading the file until we cannot read further or the
|
// Keep reading the file until we cannot read further or the
|
||||||
// pre-determined file size is reached.
|
// pre-determined file size is reached.
|
||||||
do {
|
do {
|
||||||
bytes_last_read =
|
bytes_last_read = fread(buffer+bytes_read, 1, file_size-bytes_read, file);
|
||||||
fread(content.data() + bytes_read, 1, file_size - bytes_read, file);
|
|
||||||
bytes_read += bytes_last_read;
|
bytes_read += bytes_last_read;
|
||||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||||
|
|
||||||
return std::string(content.data(), bytes_read);
|
const string content = string(buffer, buffer+bytes_read);
|
||||||
|
delete[] buffer;
|
||||||
|
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
// Get the captured stdout or stderr as a string
|
// Get the captured stdout (when fd is STDOUT_FILENO) or stderr (when
|
||||||
|
// fd is STDERR_FILENO) as a string
|
||||||
static inline string GetCapturedTestOutput(int fd) {
|
static inline string GetCapturedTestOutput(int fd) {
|
||||||
CHECK((fd == fileno(stdout)) || (fd == fileno(stderr)));
|
CHECK(fd == STDOUT_FILENO || fd == STDERR_FILENO);
|
||||||
std::unique_ptr<CapturedStream> cap = std::move(s_captured_streams.at(fd));
|
CapturedStream * const cap = s_captured_streams[fd];
|
||||||
s_captured_streams.erase(fd);
|
CHECK(cap)
|
||||||
CHECK(cap) << ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
<< ": did you forget CaptureTestStdout() or CaptureTestStderr()?";
|
||||||
|
|
||||||
// Make sure everything is flushed.
|
// Make sure everything is flushed.
|
||||||
cap->StopCapture();
|
cap->StopCapture();
|
||||||
|
|
||||||
// Read the captured file.
|
// Read the captured file.
|
||||||
std::unique_ptr<FILE> file{fopen(cap->filename().c_str(), "r")};
|
FILE * const file = fopen(cap->filename().c_str(), "r");
|
||||||
const string content = ReadEntireFile(file.get());
|
const string content = ReadEntireFile(file);
|
||||||
file.reset();
|
fclose(file);
|
||||||
|
|
||||||
|
delete cap;
|
||||||
|
s_captured_streams[fd] = nullptr;
|
||||||
|
|
||||||
return content;
|
return content;
|
||||||
}
|
}
|
||||||
// Get the captured stderr of a test as a string.
|
// Get the captured stderr of a test as a string.
|
||||||
static inline string GetCapturedTestStderr() {
|
static inline string GetCapturedTestStderr() {
|
||||||
return GetCapturedTestOutput(fileno(stderr));
|
return GetCapturedTestOutput(STDERR_FILENO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const std::size_t kLoggingPrefixLength = 9;
|
static const std::size_t kLoggingPrefixLength = 9;
|
||||||
@ -425,7 +421,7 @@ static inline bool IsLoggingPrefix(const string& s) {
|
|||||||
}
|
}
|
||||||
if (!strchr("IWEF", s[0])) return false;
|
if (!strchr("IWEF", s[0])) return false;
|
||||||
for (size_t i = 1; i <= 8; ++i) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -465,15 +461,16 @@ static inline string MungeLine(const string& line) {
|
|||||||
}
|
}
|
||||||
size_t index = thread_lineinfo.find(':');
|
size_t index = thread_lineinfo.find(':');
|
||||||
CHECK_NE(string::npos, index);
|
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;
|
string rest;
|
||||||
std::getline(iss, rest);
|
std::getline(iss, rest);
|
||||||
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
|
return (before + logcode_date[0] + "YEARDATE TIME__ " + thread_lineinfo +
|
||||||
MungeLine(rest));
|
MungeLine(rest));
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void StringReplace(string* str, const string& oldsub,
|
static inline void StringReplace(string* str,
|
||||||
const string& newsub) {
|
const string& oldsub,
|
||||||
|
const string& newsub) {
|
||||||
size_t pos = str->find(oldsub);
|
size_t pos = str->find(oldsub);
|
||||||
if (pos != string::npos) {
|
if (pos != string::npos) {
|
||||||
str->replace(pos, oldsub.size(), newsub);
|
str->replace(pos, oldsub.size(), newsub);
|
||||||
@ -481,18 +478,17 @@ static inline void StringReplace(string* str, const string& oldsub,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline string Munge(const string& filename) {
|
static inline string Munge(const string& filename) {
|
||||||
std::unique_ptr<FILE> fp{fopen(filename.c_str(), "rb")};
|
FILE* fp = fopen(filename.c_str(), "rb");
|
||||||
CHECK(fp != nullptr) << filename << ": couldn't open";
|
CHECK(fp != nullptr) << filename << ": couldn't open";
|
||||||
char buf[4096];
|
char buf[4096];
|
||||||
string result;
|
string result;
|
||||||
while (fgets(buf, 4095, fp.get())) {
|
while (fgets(buf, 4095, fp)) {
|
||||||
string line = MungeLine(buf);
|
string line = MungeLine(buf);
|
||||||
const size_t str_size = 256;
|
const size_t str_size = 256;
|
||||||
char null_str[str_size];
|
char null_str[str_size];
|
||||||
char ptr_str[str_size];
|
char ptr_str[str_size];
|
||||||
std::snprintf(null_str, str_size, "%p", static_cast<void*>(nullptr));
|
snprintf(null_str, str_size, "%p", static_cast<void*>(nullptr));
|
||||||
std::snprintf(ptr_str, str_size, "%p",
|
snprintf(ptr_str, str_size, "%p", reinterpret_cast<void*>(PTR_TEST_VALUE));
|
||||||
reinterpret_cast<void*>(PTR_TEST_VALUE));
|
|
||||||
|
|
||||||
StringReplace(&line, "__NULLP__", null_str);
|
StringReplace(&line, "__NULLP__", null_str);
|
||||||
StringReplace(&line, "__PTRTEST__", ptr_str);
|
StringReplace(&line, "__PTRTEST__", ptr_str);
|
||||||
@ -504,19 +500,19 @@ static inline string Munge(const string& filename) {
|
|||||||
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
|
StringReplace(&line, "__ENOEXEC__", StrError(ENOEXEC));
|
||||||
result += line + "\n";
|
result += line + "\n";
|
||||||
}
|
}
|
||||||
|
fclose(fp);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void WriteToFile(const string& body, const string& file) {
|
static inline void WriteToFile(const string& body, const string& file) {
|
||||||
std::unique_ptr<FILE> fp{fopen(file.c_str(), "wb")};
|
FILE* fp = fopen(file.c_str(), "wb");
|
||||||
fwrite(body.data(), 1, body.size(), fp.get());
|
fwrite(body.data(), 1, body.size(), fp);
|
||||||
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool MungeAndDiffTest(const string& golden_filename,
|
static inline bool MungeAndDiffTest(const string& golden_filename,
|
||||||
CapturedStream* cap) {
|
CapturedStream* cap) {
|
||||||
auto pos = s_captured_streams.find(fileno(stdout));
|
if (cap == s_captured_streams[STDOUT_FILENO]) {
|
||||||
|
|
||||||
if (pos != s_captured_streams.end() && cap == pos->second.get()) {
|
|
||||||
CHECK(cap) << ": did you forget CaptureTestStdout()?";
|
CHECK(cap) << ": did you forget CaptureTestStdout()?";
|
||||||
} else {
|
} else {
|
||||||
CHECK(cap) << ": did you forget CaptureTestStderr()?";
|
CHECK(cap) << ": did you forget CaptureTestStderr()?";
|
||||||
@ -551,17 +547,15 @@ static inline bool MungeAndDiffTest(const string& golden_filename,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
|
static inline bool MungeAndDiffTestStderr(const string& golden_filename) {
|
||||||
return MungeAndDiffTest(golden_filename,
|
return MungeAndDiffTest(golden_filename, s_captured_streams[STDERR_FILENO]);
|
||||||
s_captured_streams.at(fileno(stderr)).get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
|
static inline bool MungeAndDiffTestStdout(const string& golden_filename) {
|
||||||
return MungeAndDiffTest(golden_filename,
|
return MungeAndDiffTest(golden_filename, s_captured_streams[STDOUT_FILENO]);
|
||||||
s_captured_streams.at(fileno(stdout)).get());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save flags used from logging_unittest.cc.
|
// Save flags used from logging_unittest.cc.
|
||||||
#ifndef GLOG_USE_GFLAGS
|
#ifndef HAVE_LIB_GFLAGS
|
||||||
struct FlagSaver {
|
struct FlagSaver {
|
||||||
FlagSaver()
|
FlagSaver()
|
||||||
: v_(FLAGS_v),
|
: v_(FLAGS_v),
|
||||||
@ -584,15 +578,70 @@ struct FlagSaver {
|
|||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
class Thread {
|
||||||
|
public:
|
||||||
|
virtual ~Thread() = default;
|
||||||
|
|
||||||
|
void SetJoinable(bool) {}
|
||||||
|
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
|
||||||
|
void Start() {
|
||||||
|
handle_ = CreateThread(nullptr, 0, &Thread::InvokeThreadW, this, 0, &th_);
|
||||||
|
CHECK(handle_) << "CreateThread";
|
||||||
|
}
|
||||||
|
void Join() {
|
||||||
|
WaitForSingleObject(handle_, INFINITE);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_PTHREAD)
|
||||||
|
void Start() { pthread_create(&th_, nullptr, &Thread::InvokeThread, this); }
|
||||||
|
void Join() { pthread_join(th_, nullptr); }
|
||||||
|
#else
|
||||||
|
void Start() {}
|
||||||
|
void Join() {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void Run() = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void* InvokeThread(void* self) {
|
||||||
|
(static_cast<Thread*>(self))->Run();
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(GLOG_OS_WINDOWS) && !defined(GLOG_OS_CYGWIN)
|
||||||
|
static DWORD __stdcall InvokeThreadW(LPVOID self) {
|
||||||
|
InvokeThread(self);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
HANDLE handle_;
|
||||||
|
DWORD th_;
|
||||||
|
#elif defined(HAVE_PTHREAD)
|
||||||
|
pthread_t th_;
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void SleepForMilliseconds(unsigned t) {
|
||||||
|
#ifndef GLOG_OS_WINDOWS
|
||||||
|
# if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
|
||||||
|
const struct timespec req = {0, t * 1000 * 1000};
|
||||||
|
nanosleep(&req, nullptr);
|
||||||
|
# else
|
||||||
|
usleep(t * 1000);
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
Sleep(t);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// Add hook for operator new to ensure there are no memory allocation.
|
// Add hook for operator new to ensure there are no memory allocation.
|
||||||
|
|
||||||
void (*g_new_hook)() = nullptr;
|
void (*g_new_hook)() = nullptr;
|
||||||
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
void* operator new(size_t size, const std::nothrow_t&) noexcept {
|
void* operator new(size_t size, const std::nothrow_t&) noexcept {
|
||||||
if (google::g_new_hook) {
|
if (GOOGLE_NAMESPACE::g_new_hook) {
|
||||||
google::g_new_hook();
|
GOOGLE_NAMESPACE::g_new_hook();
|
||||||
}
|
}
|
||||||
return malloc(size);
|
return malloc(size);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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)
|
|
||||||
@ -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";
|
|
||||||
}
|
|
||||||
@ -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");
|
|
||||||
}
|
|
||||||
@ -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)
|
|
||||||
@ -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";
|
|
||||||
}
|
|
||||||
@ -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};
|
|
||||||
}
|
|
||||||
1766
src/logging.cc
1766
src/logging.cc
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
|||||||
#! /bin/sh
|
#! /bin/sh
|
||||||
#
|
#
|
||||||
# Copyright (c) 2023, Google Inc.
|
# Copyright (c) 2007, Google Inc.
|
||||||
# All rights reserved.
|
# All rights reserved.
|
||||||
#
|
#
|
||||||
# Redistribution and use in source and binary forms, with or without
|
# Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,15 +32,15 @@
|
|||||||
# Author: Sergey Ioffe
|
# Author: Sergey Ioffe
|
||||||
|
|
||||||
get_strings () {
|
get_strings () {
|
||||||
if test -e "$1"; then
|
if test -e ".libs/$1"; then
|
||||||
binary="$1"
|
binary=".libs/$1"
|
||||||
elif test -e "$1.exe"; then
|
elif test -e "$1.exe"; then
|
||||||
binary="$1.exe"
|
binary="$1.exe"
|
||||||
else
|
else
|
||||||
echo "We coundn't find $1 binary."
|
echo "We coundn't find $1 binary."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}'
|
strings -n 10 $binary | sort | awk '/TESTMESSAGE/ {printf "%s ", $2}'
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -60,21 +60,20 @@ die () {
|
|||||||
# Check that the string literals are appropriately stripped. This will
|
# Check that the string literals are appropriately stripped. This will
|
||||||
# not be the case in debug mode.
|
# not be the case in debug mode.
|
||||||
|
|
||||||
mode=`GLOG_check_mode=1 ./striplog0_unittest 2> /dev/null`
|
mode=`GLOG_check_mode=1 ./logging_striptest0 2> /dev/null`
|
||||||
echo $mode
|
|
||||||
if [ "$mode" = "opt" ];
|
if [ "$mode" = "opt" ];
|
||||||
then
|
then
|
||||||
echo "In OPT mode"
|
echo "In OPT mode"
|
||||||
check_eq "`get_strings striplog0_unittest`" "COND ERROR FATAL INFO WARNING "
|
check_eq "`get_strings logging_striptest0`" "COND ERROR FATAL INFO USAGE WARNING "
|
||||||
check_eq "`get_strings striplog2_unittest`" "COND ERROR FATAL "
|
check_eq "`get_strings logging_striptest2`" "COND ERROR FATAL USAGE "
|
||||||
check_eq "`get_strings striplog10_unittest`" ""
|
check_eq "`get_strings logging_striptest10`" ""
|
||||||
else
|
else
|
||||||
echo "In DBG mode; not checking strings"
|
echo "In DBG mode; not checking strings"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check that LOG(FATAL) aborts even for large STRIP_LOG
|
# Check that LOG(FATAL) aborts even for large STRIP_LOG
|
||||||
|
|
||||||
./striplog2_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=2"
|
./logging_striptest2 2>/dev/null && die "Did not abort for STRIP_LOG=2"
|
||||||
./striplog10_unittest 2>/dev/null && die "Did not abort for STRIP_LOG=10"
|
./logging_striptest10 2>/dev/null && die "Did not abort for STRIP_LOG=10"
|
||||||
|
|
||||||
echo "PASS"
|
echo "PASS"
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2007, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -27,8 +27,9 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Author: Sergiu Deitsch
|
// Author: Sergey Ioffe
|
||||||
|
|
||||||
#include <glog/vlog_is_on.h>
|
#define GOOGLE_STRIP_LOG 10
|
||||||
|
|
||||||
int main() { VLOG_IS_ON(0); }
|
// Include the actual test.
|
||||||
|
#include "logging_striptest_main.cc"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2007, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -27,8 +27,9 @@
|
|||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
//
|
//
|
||||||
// Author: Sergiu Deitsch
|
// Author: Sergey Ioffe
|
||||||
|
|
||||||
#include <glog/stl_logging.h>
|
#define GOOGLE_STRIP_LOG 2
|
||||||
|
|
||||||
int main() {}
|
// Include the actual test.
|
||||||
|
#include "logging_striptest_main.cc"
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2023, Google Inc.
|
// Copyright (c) 2007, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -31,9 +31,7 @@
|
|||||||
|
|
||||||
// The common part of the striplog tests.
|
// The common part of the striplog tests.
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
@ -41,36 +39,25 @@
|
|||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
|
DECLARE_bool(logtostderr);
|
||||||
GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'");
|
GLOG_DEFINE_bool(check_mode, false, "Prints 'opt' or 'dbg'");
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
int CheckNoReturn(bool b) {
|
int CheckNoReturn(bool b) {
|
||||||
string s;
|
string s;
|
||||||
if (b) {
|
if (b) {
|
||||||
LOG(FATAL) << "Fatal";
|
LOG(FATAL) << "Fatal";
|
||||||
return 0; // Workaround for MSVC warning C4715
|
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct A {};
|
struct A { };
|
||||||
std::ostream& operator<<(std::ostream& str, const A&) { return str; }
|
std::ostream &operator<<(std::ostream &str, const A&) {return str;}
|
||||||
|
|
||||||
namespace {
|
|
||||||
void handle_abort(int /*code*/) { std::exit(EXIT_FAILURE); }
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
int main(int, char* argv[]) {
|
int main(int, char* argv[]) {
|
||||||
#if defined(_MSC_VER)
|
|
||||||
// Avoid presenting an interactive dialog that will cause the test to time
|
|
||||||
// out.
|
|
||||||
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
|
||||||
#endif // defined(_MSC_VER)
|
|
||||||
std::signal(SIGABRT, handle_abort);
|
|
||||||
|
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
if (FLAGS_check_mode) {
|
if (FLAGS_check_mode) {
|
||||||
@ -78,8 +65,8 @@ int main(int, char* argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
LOG(INFO) << "TESTMESSAGE INFO";
|
LOG(INFO) << "TESTMESSAGE INFO";
|
||||||
LOG(WARNING) << 2 << "something"
|
LOG(WARNING) << 2 << "something" << "TESTMESSAGE WARNING"
|
||||||
<< "TESTMESSAGE WARNING" << 1 << 'c' << A() << std::endl;
|
<< 1 << 'c' << A() << std::endl;
|
||||||
LOG(ERROR) << "TESTMESSAGE ERROR";
|
LOG(ERROR) << "TESTMESSAGE ERROR";
|
||||||
bool flag = true;
|
bool flag = true;
|
||||||
(flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND";
|
(flag ? LOG(INFO) : LOG(ERROR)) << "TESTMESSAGE COND";
|
||||||
File diff suppressed because it is too large
Load Diff
@ -35,7 +35,7 @@
|
|||||||
#ifndef GLOG_SRC_MOCK_LOG_H_
|
#ifndef GLOG_SRC_MOCK_LOG_H_
|
||||||
#define GLOG_SRC_MOCK_LOG_H_
|
#define GLOG_SRC_MOCK_LOG_H_
|
||||||
|
|
||||||
// For google. This must go first so we get _XOPEN_SOURCE.
|
// For GOOGLE_NAMESPACE. This must go first so we get _XOPEN_SOURCE.
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -43,7 +43,7 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
namespace glog_testing {
|
namespace glog_testing {
|
||||||
|
|
||||||
// A ScopedMockLog object intercepts LOG() messages issued during its
|
// A ScopedMockLog object intercepts LOG() messages issued during its
|
||||||
@ -64,7 +64,7 @@ namespace glog_testing {
|
|||||||
//
|
//
|
||||||
// Foo(); // Exercises the code under test.
|
// Foo(); // Exercises the code under test.
|
||||||
// }
|
// }
|
||||||
class ScopedMockLog : public google::LogSink {
|
class ScopedMockLog : public GOOGLE_NAMESPACE::LogSink {
|
||||||
public:
|
public:
|
||||||
// When a ScopedMockLog object is constructed, it starts to
|
// When a ScopedMockLog object is constructed, it starts to
|
||||||
// intercept logs.
|
// intercept logs.
|
||||||
@ -86,9 +86,9 @@ class ScopedMockLog : public google::LogSink {
|
|||||||
// for messages from different threads. In fact, if the same or multiple
|
// for messages from different threads. In fact, if the same or multiple
|
||||||
// expectations are matched on two threads concurrently, their actions will
|
// expectations are matched on two threads concurrently, their actions will
|
||||||
// be executed concurrently as well and may interleave.
|
// be executed concurrently as well and may interleave.
|
||||||
MOCK_METHOD3(Log,
|
MOCK_METHOD3(Log, void(GOOGLE_NAMESPACE::LogSeverity severity,
|
||||||
void(google::LogSeverity severity, const std::string& file_path,
|
const std::string& file_path,
|
||||||
const std::string& message));
|
const std::string& message));
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Implements the send() virtual function in class LogSink.
|
// Implements the send() virtual function in class LogSink.
|
||||||
@ -112,7 +112,7 @@ class ScopedMockLog : public google::LogSink {
|
|||||||
// be running simultaneously, we ensure thread-safety of the exchange between
|
// be running simultaneously, we ensure thread-safety of the exchange between
|
||||||
// send() and WaitTillSent(), and that for each message, LOG(), send(),
|
// send() and WaitTillSent(), and that for each message, LOG(), send(),
|
||||||
// WaitTillSent() and Log() are executed in the same thread.
|
// WaitTillSent() and Log() are executed in the same thread.
|
||||||
void send(google::LogSeverity severity, const char* full_filename,
|
void send(GOOGLE_NAMESPACE::LogSeverity severity, const char* full_filename,
|
||||||
const char* /*base_filename*/, int /*line*/,
|
const char* /*base_filename*/, int /*line*/,
|
||||||
const LogMessageTime& /*logmsgtime*/, const char* message,
|
const LogMessageTime& /*logmsgtime*/, const char* message,
|
||||||
size_t message_len) override {
|
size_t message_len) override {
|
||||||
@ -141,7 +141,7 @@ class ScopedMockLog : public google::LogSink {
|
|||||||
// All relevant information about a logged message that needs to be passed
|
// All relevant information about a logged message that needs to be passed
|
||||||
// from send() to WaitTillSent().
|
// from send() to WaitTillSent().
|
||||||
struct MessageInfo {
|
struct MessageInfo {
|
||||||
google::LogSeverity severity;
|
GOOGLE_NAMESPACE::LogSeverity severity;
|
||||||
std::string file_path;
|
std::string file_path;
|
||||||
std::string message;
|
std::string message;
|
||||||
};
|
};
|
||||||
@ -149,6 +149,6 @@ class ScopedMockLog : public google::LogSink {
|
|||||||
};
|
};
|
||||||
|
|
||||||
} // namespace glog_testing
|
} // namespace glog_testing
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
#endif // GLOG_SRC_MOCK_LOG_H_
|
#endif // GLOG_SRC_MOCK_LOG_H_
|
||||||
|
|||||||
@ -33,17 +33,17 @@
|
|||||||
|
|
||||||
#include "mock-log.h"
|
#include "mock-log.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
#include <gmock/gmock.h>
|
#include <gmock/gmock.h>
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
using google::GLOG_ERROR;
|
using GOOGLE_NAMESPACE::GLOG_ERROR;
|
||||||
using google::GLOG_INFO;
|
using GOOGLE_NAMESPACE::GLOG_INFO;
|
||||||
using google::GLOG_WARNING;
|
using GOOGLE_NAMESPACE::GLOG_WARNING;
|
||||||
using google::glog_testing::ScopedMockLog;
|
using GOOGLE_NAMESPACE::glog_testing::ScopedMockLog;
|
||||||
using std::string;
|
using std::string;
|
||||||
using testing::_;
|
using testing::_;
|
||||||
using testing::EndsWith;
|
using testing::EndsWith;
|
||||||
@ -57,7 +57,8 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
InSequence s;
|
InSequence s;
|
||||||
EXPECT_CALL(log,
|
EXPECT_CALL(log,
|
||||||
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
Log(GLOG_WARNING, EndsWith("mock-log_unittest.cc"), "Fishy."));
|
||||||
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working...")).Times(2);
|
EXPECT_CALL(log, Log(GLOG_INFO, _, "Working..."))
|
||||||
|
.Times(2);
|
||||||
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
EXPECT_CALL(log, Log(GLOG_ERROR, _, "Bad!!"));
|
||||||
|
|
||||||
LOG(WARNING) << "Fishy.";
|
LOG(WARNING) << "Fishy.";
|
||||||
@ -66,9 +67,13 @@ TEST(ScopedMockLogTest, InterceptsLog) {
|
|||||||
LOG(ERROR) << "Bad!!";
|
LOG(ERROR) << "Bad!!";
|
||||||
}
|
}
|
||||||
|
|
||||||
void LogBranch() { LOG(INFO) << "Logging a branch..."; }
|
void LogBranch() {
|
||||||
|
LOG(INFO) << "Logging a branch...";
|
||||||
|
}
|
||||||
|
|
||||||
void LogTree() { LOG(INFO) << "Logging the whole tree..."; }
|
void LogTree() {
|
||||||
|
LOG(INFO) << "Logging the whole tree...";
|
||||||
|
}
|
||||||
|
|
||||||
void LogForest() {
|
void LogForest() {
|
||||||
LOG(INFO) << "Logging the entire forest.";
|
LOG(INFO) << "Logging the entire forest.";
|
||||||
@ -94,8 +99,8 @@ TEST(ScopedMockLogTest, LogDuringIntercept) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
google::InitGoogleLogging(argv[0]);
|
GOOGLE_NAMESPACE::InitGoogleLogging(argv[0]);
|
||||||
testing::InitGoogleTest(&argc, argv);
|
testing::InitGoogleTest(&argc, argv);
|
||||||
testing::InitGoogleMock(&argc, argv);
|
testing::InitGoogleMock(&argc, argv);
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,6 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
|
|
||||||
int main(int /*argc*/, char** argv) { google::InitGoogleLogging(argv[0]); }
|
int main(int /*argc*/, char** argv)
|
||||||
|
{
|
||||||
|
google::InitGoogleLogging(argv[0]);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -31,60 +31,61 @@
|
|||||||
//
|
//
|
||||||
// logging_unittest.cc covers the functionality herein
|
// logging_unittest.cc covers the functionality herein
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <mutex>
|
|
||||||
#include <ostream>
|
|
||||||
#include <streambuf>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h> // for close() and write()
|
# include <unistd.h> // for close() and write()
|
||||||
#endif
|
|
||||||
#if defined(HAVE_SYSCALL_H)
|
|
||||||
# include <syscall.h> // for syscall()
|
|
||||||
#elif defined(HAVE_SYS_SYSCALL_H)
|
|
||||||
# include <sys/syscall.h> // for syscall()
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_UNISTD_H
|
|
||||||
# include <unistd.h>
|
|
||||||
#endif
|
#endif
|
||||||
#include <fcntl.h> // for open()
|
#include <fcntl.h> // for open()
|
||||||
|
|
||||||
#include "glog/logging.h"
|
#include <ctime>
|
||||||
#include "glog/raw_logging.h"
|
|
||||||
#include "stacktrace.h"
|
|
||||||
#include "utilities.h"
|
|
||||||
|
|
||||||
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
|
#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()
|
||||||
|
#elif defined(HAVE_SYS_SYSCALL_H)
|
||||||
|
#include <sys/syscall.h> // for syscall()
|
||||||
|
#endif
|
||||||
|
#ifdef HAVE_UNISTD_H
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(HAVE_SYSCALL_H) || defined(HAVE_SYS_SYSCALL_H)) && \
|
||||||
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
|
(!(defined(GLOG_OS_MACOSX)) && !(defined(GLOG_OS_OPENBSD))) && \
|
||||||
!defined(GLOG_OS_EMSCRIPTEN)
|
!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
|
#else
|
||||||
// Not so safe, but what can you do?
|
// 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
|
#endif
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
|
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck) \
|
||||||
__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)))
|
__attribute__((format_arg(stringIndex)))
|
||||||
#else
|
#else
|
||||||
# define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
|
#define GLOG_ATTRIBUTE_FORMAT(archetype, stringIndex, firstToCheck)
|
||||||
# define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
|
#define GLOG_ATTRIBUTE_FORMAT_ARG(stringIndex)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// CAVEAT: std::vsnprintf called from *DoRawLog below has some (exotic) code
|
// CAVEAT: vsnprintf called from *DoRawLog below has some (exotic) code paths
|
||||||
// paths that invoke malloc() and getenv() that might acquire some locks. If
|
// that invoke malloc() and getenv() that might acquire some locks.
|
||||||
// this becomes a problem we should reimplement a subset of std::vsnprintf that
|
// If this becomes a problem we should reimplement a subset of vsnprintf
|
||||||
// does not need locks and malloc.
|
// that does not need locks and malloc.
|
||||||
|
|
||||||
// Helper for RawLog__ below.
|
// Helper for RawLog__ below.
|
||||||
// *DoRawLog writes to *buf of *size and move them past the written portion.
|
// *DoRawLog writes to *buf of *size and move them past the written portion.
|
||||||
@ -93,7 +94,7 @@ GLOG_ATTRIBUTE_FORMAT(printf, 3, 4)
|
|||||||
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
|
static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
int n = std::vsnprintf(*buf, *size, format, ap);
|
int n = vsnprintf(*buf, *size, format, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
||||||
*size -= static_cast<size_t>(n);
|
*size -= static_cast<size_t>(n);
|
||||||
@ -102,15 +103,15 @@ static bool DoRawLog(char** buf, size_t* size, const char* format, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for RawLog__ below.
|
// Helper for RawLog__ below.
|
||||||
inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
|
inline static bool VADoRawLog(char** buf, size_t* size,
|
||||||
va_list ap) {
|
const char* format, va_list ap) {
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
# pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
|
||||||
#endif
|
#endif
|
||||||
int n = std::vsnprintf(*buf, *size, format, ap);
|
int n = vsnprintf(*buf, *size, format, ap);
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
# pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
if (n < 0 || static_cast<size_t>(n) > *size) return false;
|
||||||
*size -= static_cast<size_t>(n);
|
*size -= static_cast<size_t>(n);
|
||||||
@ -119,29 +120,9 @@ inline static bool VADoRawLog(char** buf, size_t* size, const char* format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const int kLogBufSize = 3000;
|
static const int kLogBufSize = 3000;
|
||||||
static std::once_flag crashed;
|
static bool crashed = false;
|
||||||
static logging::internal::CrashReason crash_reason;
|
static CrashReason crash_reason;
|
||||||
static char crash_buf[kLogBufSize + 1] = {0}; // Will end in '\0'
|
static char crash_buf[kLogBufSize + 1] = { 0 }; // Will end in '\0'
|
||||||
|
|
||||||
namespace {
|
|
||||||
template <std::size_t N>
|
|
||||||
class StaticStringBuf : public std::streambuf {
|
|
||||||
public:
|
|
||||||
StaticStringBuf() {
|
|
||||||
setp(std::begin(data_), std::end(data_));
|
|
||||||
setg(std::begin(data_), std::begin(data_), std::end(data_));
|
|
||||||
}
|
|
||||||
const char* data() noexcept {
|
|
||||||
if (pptr() != pbase() && pptr() != epptr() && *(pptr() - 1) != '\0') {
|
|
||||||
sputc('\0');
|
|
||||||
}
|
|
||||||
return data_;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
char data_[N];
|
|
||||||
};
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
|
GLOG_ATTRIBUTE_FORMAT(printf, 4, 5)
|
||||||
void RawLog__(LogSeverity severity, const char* file, int line,
|
void RawLog__(LogSeverity severity, const char* file, int line,
|
||||||
@ -151,25 +132,16 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
|||||||
!IsGoogleLoggingInitialized())) {
|
!IsGoogleLoggingInitialized())) {
|
||||||
return; // this stderr log message is suppressed
|
return; // this stderr log message is suppressed
|
||||||
}
|
}
|
||||||
|
|
||||||
// We do not have any any option other that string streams to obtain the
|
|
||||||
// thread identifier as the corresponding value is not convertible to an
|
|
||||||
// integer. Use a statically allocated buffer to avoid dynamic memory
|
|
||||||
// allocations.
|
|
||||||
StaticStringBuf<kLogBufSize> sbuf;
|
|
||||||
std::ostream oss(&sbuf);
|
|
||||||
|
|
||||||
oss << std::setw(5) << std::this_thread::get_id();
|
|
||||||
|
|
||||||
// can't call localtime_r here: it can allocate
|
// can't call localtime_r here: it can allocate
|
||||||
char buffer[kLogBufSize];
|
char buffer[kLogBufSize];
|
||||||
char* buf = buffer;
|
char* buf = buffer;
|
||||||
size_t size = sizeof(buffer);
|
size_t size = sizeof(buffer);
|
||||||
|
|
||||||
// NOTE: this format should match the specification in base/logging.h
|
// NOTE: this format should match the specification in base/logging.h
|
||||||
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %s %s:%d] RAW: ",
|
DoRawLog(&buf, &size, "%c00000000 00:00:00.000000 %5u %s:%d] RAW: ",
|
||||||
GetLogSeverityName(severity)[0], sbuf.data(),
|
LogSeverityNames[severity][0],
|
||||||
const_basename(const_cast<char*>(file)), line);
|
static_cast<unsigned int>(GetTID()),
|
||||||
|
const_basename(const_cast<char *>(file)), line);
|
||||||
|
|
||||||
// Record the position and size of the buffer after the prefix
|
// Record the position and size of the buffer after the prefix
|
||||||
const char* msg_start = buf;
|
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
|
// avoiding FILE buffering (to avoid invoking malloc()), and bypassing
|
||||||
// libc (to side-step any libc interception).
|
// libc (to side-step any libc interception).
|
||||||
// We write just once to avoid races with other invocations of RawLog__.
|
// We write just once to avoid races with other invocations of RawLog__.
|
||||||
safe_write(fileno(stderr), buffer, strlen(buffer));
|
safe_write(STDERR_FILENO, buffer, strlen(buffer));
|
||||||
if (severity == GLOG_FATAL) {
|
if (severity == GLOG_FATAL) {
|
||||||
std::call_once(crashed, [file, line, msg_start, msg_size] {
|
if (!sync_val_compare_and_swap(&crashed, false, true)) {
|
||||||
crash_reason.filename = file;
|
crash_reason.filename = file;
|
||||||
crash_reason.line_number = line;
|
crash_reason.line_number = line;
|
||||||
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
|
memcpy(crash_buf, msg_start, msg_size); // Don't include prefix
|
||||||
@ -202,9 +174,9 @@ void RawLog__(LogSeverity severity, const char* file, int line,
|
|||||||
crash_reason.depth = 0;
|
crash_reason.depth = 0;
|
||||||
#endif
|
#endif
|
||||||
SetCrashReason(&crash_reason);
|
SetCrashReason(&crash_reason);
|
||||||
});
|
}
|
||||||
LogMessage::Fail(); // abort()
|
LogMessage::Fail(); // abort()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -31,36 +31,22 @@
|
|||||||
//
|
//
|
||||||
// Implementation of InstallFailureSignalHandler().
|
// Implementation of InstallFailureSignalHandler().
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstring>
|
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <mutex>
|
|
||||||
#include <sstream>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "glog/platform.h"
|
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
#include "symbolize.h"
|
#include "symbolize.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef HAVE_UCONTEXT_H
|
#ifdef HAVE_UCONTEXT_H
|
||||||
# include <ucontext.h>
|
# include <ucontext.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYS_UCONTEXT_H
|
#ifdef HAVE_SYS_UCONTEXT_H
|
||||||
# include <sys/ucontext.h>
|
# include <sys/ucontext.h>
|
||||||
#endif
|
|
||||||
#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
|
#endif
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -71,14 +57,16 @@ namespace {
|
|||||||
// The list should be synced with the comment in signalhandler.h.
|
// The list should be synced with the comment in signalhandler.h.
|
||||||
const struct {
|
const struct {
|
||||||
int number;
|
int number;
|
||||||
const char* name;
|
const char *name;
|
||||||
} kFailureSignals[] = {
|
} kFailureSignals[] = {
|
||||||
{SIGSEGV, "SIGSEGV"}, {SIGILL, "SIGILL"},
|
{ SIGSEGV, "SIGSEGV" },
|
||||||
{SIGFPE, "SIGFPE"}, {SIGABRT, "SIGABRT"},
|
{ SIGILL, "SIGILL" },
|
||||||
|
{ SIGFPE, "SIGFPE" },
|
||||||
|
{ SIGABRT, "SIGABRT" },
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
{SIGBUS, "SIGBUS"},
|
{ SIGBUS, "SIGBUS" },
|
||||||
#endif
|
#endif
|
||||||
{SIGTERM, "SIGTERM"},
|
{ SIGTERM, "SIGTERM" },
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool kFailureSignalHandlerInstalled = false;
|
static bool kFailureSignalHandlerInstalled = false;
|
||||||
@ -86,15 +74,14 @@ static bool kFailureSignalHandlerInstalled = false;
|
|||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
// Returns the program counter from signal context, nullptr if unknown.
|
// Returns the program counter from signal context, nullptr if unknown.
|
||||||
void* GetPC(void* ucontext_in_void) {
|
void* GetPC(void* ucontext_in_void) {
|
||||||
# if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && \
|
#if (defined(HAVE_UCONTEXT_H) || defined(HAVE_SYS_UCONTEXT_H)) && defined(PC_FROM_UCONTEXT)
|
||||||
defined(PC_FROM_UCONTEXT)
|
|
||||||
if (ucontext_in_void != nullptr) {
|
if (ucontext_in_void != nullptr) {
|
||||||
ucontext_t* context = reinterpret_cast<ucontext_t*>(ucontext_in_void);
|
ucontext_t *context = reinterpret_cast<ucontext_t *>(ucontext_in_void);
|
||||||
return (void*)context->PC_FROM_UCONTEXT;
|
return (void*)context->PC_FROM_UCONTEXT;
|
||||||
}
|
}
|
||||||
# else
|
#else
|
||||||
(void)ucontext_in_void;
|
(void)ucontext_in_void;
|
||||||
# endif
|
#endif
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -103,13 +90,14 @@ void* GetPC(void* ucontext_in_void) {
|
|||||||
// as it's not async signal safe.
|
// as it's not async signal safe.
|
||||||
class MinimalFormatter {
|
class MinimalFormatter {
|
||||||
public:
|
public:
|
||||||
MinimalFormatter(char* buffer, size_t size)
|
MinimalFormatter(char *buffer, size_t size)
|
||||||
: buffer_(buffer), cursor_(buffer), end_(buffer + size) {}
|
: buffer_(buffer),
|
||||||
|
cursor_(buffer),
|
||||||
|
end_(buffer + size) {
|
||||||
|
}
|
||||||
|
|
||||||
// Returns the number of bytes written in the buffer.
|
// Returns the number of bytes written in the buffer.
|
||||||
std::size_t num_bytes_written() const {
|
std::size_t num_bytes_written() const { return static_cast<std::size_t>(cursor_ - buffer_); }
|
||||||
return static_cast<std::size_t>(cursor_ - buffer_);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Appends string from "str" and updates the internal cursor.
|
// Appends string from "str" and updates the internal cursor.
|
||||||
void AppendString(const char* str) {
|
void AppendString(const char* str) {
|
||||||
@ -155,14 +143,14 @@ class MinimalFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
char* buffer_;
|
char *buffer_;
|
||||||
char* cursor_;
|
char *cursor_;
|
||||||
const char* const end_;
|
const char * const end_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Writes the given data with the size to the standard error.
|
// Writes the given data with the size to the standard error.
|
||||||
void WriteToStderr(const char* data, size_t size) {
|
void WriteToStderr(const char* data, size_t size) {
|
||||||
if (write(fileno(stderr), data, size) < 0) {
|
if (write(STDERR_FILENO, data, size) < 0) {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -189,7 +177,7 @@ void DumpTimeInfo() {
|
|||||||
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
|
#if defined(HAVE_STACKTRACE) && defined(HAVE_SIGACTION)
|
||||||
|
|
||||||
// Dumps information about the signal to STDERR.
|
// 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.
|
// Get the signal name.
|
||||||
const char* signal_name = nullptr;
|
const char* signal_name = nullptr;
|
||||||
for (auto kFailureSignal : kFailureSignals) {
|
for (auto kFailureSignal : kFailureSignals) {
|
||||||
@ -215,25 +203,21 @@ void DumpSignalInfo(int signal_number, siginfo_t* siginfo) {
|
|||||||
formatter.AppendString(")");
|
formatter.AppendString(")");
|
||||||
formatter.AppendString(" received by PID ");
|
formatter.AppendString(" received by PID ");
|
||||||
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
|
formatter.AppendUint64(static_cast<uint64>(getpid()), 10);
|
||||||
formatter.AppendString(" (TID ");
|
formatter.AppendString(" (TID 0x");
|
||||||
|
// We assume pthread_t is an integral number or a pointer, rather
|
||||||
std::ostringstream oss;
|
// than a complex struct. In some environments, pthread_self()
|
||||||
oss << std::showbase << std::hex << std::this_thread::get_id();
|
// returns an uint64 but in some other environments pthread_self()
|
||||||
formatter.AppendString(oss.str().c_str());
|
// returns a pointer.
|
||||||
# if defined(GLOG_OS_LINUX) && defined(HAVE_SYS_SYSCALL_H) && \
|
pthread_t id = pthread_self();
|
||||||
defined(HAVE_SYS_TYPES_H)
|
formatter.AppendUint64(
|
||||||
pid_t tid = syscall(SYS_gettid);
|
reinterpret_cast<uint64>(reinterpret_cast<const char*>(id)), 16);
|
||||||
formatter.AppendString(" LWP ");
|
|
||||||
formatter.AppendUint64(static_cast<uint64>(tid), 10);
|
|
||||||
# endif
|
|
||||||
formatter.AppendString(") ");
|
formatter.AppendString(") ");
|
||||||
|
|
||||||
// Only linux has the PID of the signal sender in si_pid.
|
// Only linux has the PID of the signal sender in si_pid.
|
||||||
# ifdef GLOG_OS_LINUX
|
#ifdef GLOG_OS_LINUX
|
||||||
formatter.AppendString("from PID ");
|
formatter.AppendString("from PID ");
|
||||||
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
|
formatter.AppendUint64(static_cast<uint64>(siginfo->si_pid), 10);
|
||||||
formatter.AppendString("; ");
|
formatter.AppendString("; ");
|
||||||
# endif
|
#endif
|
||||||
formatter.AppendString("stack trace: ***\n");
|
formatter.AppendString("stack trace: ***\n");
|
||||||
g_failure_writer(buf, formatter.num_bytes_written());
|
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.
|
// Dumps information about the stack frame to STDERR.
|
||||||
void DumpStackFrameInfo(const char* prefix, void* pc) {
|
void DumpStackFrameInfo(const char* prefix, void* pc) {
|
||||||
// Get the symbol name.
|
// Get the symbol name.
|
||||||
const char* symbol = "(unknown)";
|
const char *symbol = "(unknown)";
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
|
||||||
char symbolized[1024]; // Big enough for a sane symbol.
|
char symbolized[1024]; // Big enough for a sane symbol.
|
||||||
// Symbolizes the previous address of pc because pc may be in the
|
// Symbolizes the previous address of pc because pc may be in the
|
||||||
// next function.
|
// next function.
|
||||||
if (Symbolize(reinterpret_cast<char*>(pc) - 1, symbolized,
|
if (Symbolize(reinterpret_cast<char *>(pc) - 1,
|
||||||
sizeof(symbolized))) {
|
symbolized, sizeof(symbolized))) {
|
||||||
symbol = symbolized;
|
symbol = symbolized;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
# pragma message( \
|
|
||||||
"Symbolize functionality is not available for target platform: stack dump will contain empty frames.")
|
|
||||||
#endif // defined(HAVE_SYMBOLIZE)
|
|
||||||
|
|
||||||
char buf[1024]; // Big enough for stack frame info.
|
char buf[1024]; // Big enough for stack frame info.
|
||||||
MinimalFormatter formatter(buf, sizeof(buf));
|
MinimalFormatter formatter(buf, sizeof(buf));
|
||||||
@ -285,19 +264,52 @@ void InvokeDefaultSignalHandler(int signal_number) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// This variable is used for protecting FailureSignalHandler() from dumping
|
// This variable is used for protecting FailureSignalHandler() from
|
||||||
// stuff while another thread is doing it. Our policy is to let the first
|
// dumping stuff while another thread is doing it. Our policy is to let
|
||||||
// thread dump stuff and let other threads do nothing.
|
// the first thread dump stuff and let other threads wait.
|
||||||
// See also comments in FailureSignalHandler().
|
// See also comments in FailureSignalHandler().
|
||||||
static std::once_flag signaled;
|
static pthread_t* g_entered_thread_id_pointer = nullptr;
|
||||||
|
|
||||||
static void HandleSignal(int signal_number
|
// Dumps signal and stack frame information, and invokes the default
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
// signal handler once our job is done.
|
||||||
,
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
siginfo_t* signal_info, void* ucontext
|
void FailureSignalHandler(int signal_number)
|
||||||
|
#else
|
||||||
|
void FailureSignalHandler(int signal_number,
|
||||||
|
siginfo_t *signal_info,
|
||||||
|
void *ucontext)
|
||||||
#endif
|
#endif
|
||||||
) {
|
{
|
||||||
|
// First check if we've already entered the function. We use an atomic
|
||||||
|
// compare and swap operation for platforms that support it. For other
|
||||||
|
// platforms, we use a naive method that could lead to a subtle race.
|
||||||
|
|
||||||
|
// We assume pthread_self() is async signal safe, though it's not
|
||||||
|
// officially guaranteed.
|
||||||
|
pthread_t my_thread_id = pthread_self();
|
||||||
|
// NOTE: We could simply use pthread_t rather than pthread_t* for this,
|
||||||
|
// if pthread_self() is guaranteed to return non-zero value for thread
|
||||||
|
// ids, but there is no such guarantee. We need to distinguish if the
|
||||||
|
// old value (value returned from __sync_val_compare_and_swap) is
|
||||||
|
// different from the original value (in this case nullptr).
|
||||||
|
pthread_t* old_thread_id_pointer =
|
||||||
|
glog_internal_namespace_::sync_val_compare_and_swap(
|
||||||
|
&g_entered_thread_id_pointer, static_cast<pthread_t*>(nullptr),
|
||||||
|
&my_thread_id);
|
||||||
|
if (old_thread_id_pointer != nullptr) {
|
||||||
|
// We've already entered the signal handler. What should we do?
|
||||||
|
if (pthread_equal(my_thread_id, *g_entered_thread_id_pointer)) {
|
||||||
|
// It looks the current thread is reentering the signal handler.
|
||||||
|
// Something must be going wrong (maybe we are reentering by another
|
||||||
|
// type of signal?). Kill ourself by the default signal handler.
|
||||||
|
InvokeDefaultSignalHandler(signal_number);
|
||||||
|
}
|
||||||
|
// Another thread is dumping stuff. Let's wait until that thread
|
||||||
|
// finishes the job and kills the process.
|
||||||
|
while (true) {
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
// This is the first time we enter the signal handler. We are going to
|
// This is the first time we enter the signal handler. We are going to
|
||||||
// do some interesting stuff from here.
|
// do some interesting stuff from here.
|
||||||
// TODO(satorux): We might want to set timeout here using alarm(), but
|
// TODO(satorux): We might want to set timeout here using alarm(), but
|
||||||
@ -308,20 +320,20 @@ static void HandleSignal(int signal_number
|
|||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
// Get the program counter from ucontext.
|
// Get the program counter from ucontext.
|
||||||
void* pc = GetPC(ucontext);
|
void *pc = GetPC(ucontext);
|
||||||
DumpStackFrameInfo("PC: ", pc);
|
DumpStackFrameInfo("PC: ", pc);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
// Get the stack traces.
|
// Get the stack traces.
|
||||||
void* stack[32];
|
void *stack[32];
|
||||||
// +1 to exclude this function.
|
// +1 to exclude this function.
|
||||||
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
|
const int depth = GetStackTrace(stack, ARRAYSIZE(stack), 1);
|
||||||
# ifdef HAVE_SIGACTION
|
# ifdef HAVE_SIGACTION
|
||||||
DumpSignalInfo(signal_number, signal_info);
|
DumpSignalInfo(signal_number, signal_info);
|
||||||
# elif !defined(GLOG_OS_WINDOWS)
|
#elif !defined(GLOG_OS_WINDOWS)
|
||||||
(void)signal_info;
|
(void)signal_info;
|
||||||
# endif
|
# endif
|
||||||
// Dump the stack traces.
|
// Dump the stack traces.
|
||||||
for (int i = 0; i < depth; ++i) {
|
for (int i = 0; i < depth; ++i) {
|
||||||
DumpStackFrameInfo(" ", stack[i]);
|
DumpStackFrameInfo(" ", stack[i]);
|
||||||
@ -341,31 +353,16 @@ static void HandleSignal(int signal_number
|
|||||||
|
|
||||||
// Flush the logs before we do anything in case 'anything'
|
// Flush the logs before we do anything in case 'anything'
|
||||||
// causes problems.
|
// causes problems.
|
||||||
FlushLogFilesUnsafe(GLOG_INFO);
|
FlushLogFilesUnsafe(0);
|
||||||
|
|
||||||
// Kill ourself by the default signal handler.
|
// Kill ourself by the default signal handler.
|
||||||
InvokeDefaultSignalHandler(signal_number);
|
InvokeDefaultSignalHandler(signal_number);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dumps signal and stack frame information, and invokes the default
|
|
||||||
// signal handler once our job is done.
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
|
||||||
void FailureSignalHandler(int signal_number)
|
|
||||||
#else
|
|
||||||
void FailureSignalHandler(int signal_number, siginfo_t* signal_info,
|
|
||||||
void* ucontext)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
std::call_once(signaled, &HandleSignal, signal_number
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
|
||||||
,
|
|
||||||
signal_info, ucontext
|
|
||||||
#endif
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
namespace glog_internal_namespace_ {
|
||||||
|
|
||||||
bool IsFailureSignalHandlerInstalled() {
|
bool IsFailureSignalHandlerInstalled() {
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
|
// TODO(andschwa): Return kFailureSignalHandlerInstalled?
|
||||||
@ -382,6 +379,8 @@ bool IsFailureSignalHandlerInstalled() {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} // namespace glog_internal_namespace_
|
||||||
|
|
||||||
void InstallFailureSignalHandler() {
|
void InstallFailureSignalHandler() {
|
||||||
#ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
// Build the sigaction struct.
|
// Build the sigaction struct.
|
||||||
@ -397,7 +396,8 @@ void InstallFailureSignalHandler() {
|
|||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#elif defined(GLOG_OS_WINDOWS)
|
#elif defined(GLOG_OS_WINDOWS)
|
||||||
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
for (size_t i = 0; i < ARRAYSIZE(kFailureSignals); ++i) {
|
||||||
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler), SIG_ERR);
|
CHECK_NE(signal(kFailureSignals[i].number, &FailureSignalHandler),
|
||||||
|
SIG_ERR);
|
||||||
}
|
}
|
||||||
kFailureSignalHandlerInstalled = true;
|
kFailureSignalHandlerInstalled = true;
|
||||||
#endif // HAVE_SIGACTION
|
#endif // HAVE_SIGACTION
|
||||||
@ -409,4 +409,4 @@ void InstallFailureWriter(void (*writer)(const char* data, size_t size)) {
|
|||||||
#endif // HAVE_SIGACTION
|
#endif // HAVE_SIGACTION
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -32,52 +32,52 @@
|
|||||||
// This is a helper binary for testing signalhandler.cc. The actual test
|
// This is a helper binary for testing signalhandler.cc. The actual test
|
||||||
// is done in signalhandler_unittest.sh.
|
// is done in signalhandler_unittest.sh.
|
||||||
|
|
||||||
|
#include "utilities.h"
|
||||||
|
|
||||||
|
#if defined(HAVE_PTHREAD)
|
||||||
|
# include <pthread.h>
|
||||||
|
#endif
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <sstream>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "stacktrace.h"
|
|
||||||
#include "symbolize.h"
|
|
||||||
|
|
||||||
#if defined(HAVE_UNISTD_H)
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <unistd.h>
|
#include <gflags/gflags.h>
|
||||||
#endif
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
|
||||||
# include <gflags/gflags.h>
|
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
#if defined(_MSC_VER)
|
|
||||||
# include <io.h> // write
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
static void DieInThread(int* a) {
|
static void* DieInThread(void*) {
|
||||||
std::ostringstream oss;
|
// We assume pthread_t is an integral number or a pointer, rather
|
||||||
oss << std::showbase << std::hex << std::this_thread::get_id();
|
// than a complex struct. In some environments, pthread_self()
|
||||||
|
// returns an uint64 but in some other environments pthread_self()
|
||||||
fprintf(stderr, "%s is dying\n", oss.str().c_str());
|
// returns a pointer.
|
||||||
int b = 1 / *a;
|
fprintf(
|
||||||
|
stderr, "0x%px is dying\n",
|
||||||
|
static_cast<const void*>(reinterpret_cast<const char*>(pthread_self())));
|
||||||
|
// Use volatile to prevent from these to be optimized away.
|
||||||
|
volatile int a = 0;
|
||||||
|
volatile int b = 1 / a;
|
||||||
fprintf(stderr, "We should have died: b=%d\n", b);
|
fprintf(stderr, "We should have died: b=%d\n", b);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void WriteToStdout(const char* data, size_t size) {
|
static void WriteToStdout(const char* data, size_t size) {
|
||||||
if (write(fileno(stdout), data, size) < 0) {
|
if (write(STDOUT_FILENO, data, size) < 0) {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_STACKTRACE) && defined(HAVE_SYMBOLIZE)
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
# ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
ParseCommandLineFlags(&argc, &argv, true);
|
ParseCommandLineFlags(&argc, &argv, true);
|
||||||
# endif
|
#endif
|
||||||
InstallFailureSignalHandler();
|
InstallFailureSignalHandler();
|
||||||
const std::string command = argc > 1 ? argv[1] : "none";
|
const std::string command = argc > 1 ? argv[1] : "none";
|
||||||
if (command == "segv") {
|
if (command == "segv") {
|
||||||
@ -85,21 +85,26 @@ int main(int argc, char** argv) {
|
|||||||
LOG(INFO) << "create the log file";
|
LOG(INFO) << "create the log file";
|
||||||
LOG(INFO) << "a message before segv";
|
LOG(INFO) << "a message before segv";
|
||||||
// We assume 0xDEAD is not writable.
|
// We assume 0xDEAD is not writable.
|
||||||
int* a = (int*)0xDEAD;
|
int *a = (int*)0xDEAD;
|
||||||
*a = 0;
|
*a = 0;
|
||||||
} else if (command == "loop") {
|
} else if (command == "loop") {
|
||||||
fprintf(stderr, "looping\n");
|
fprintf(stderr, "looping\n");
|
||||||
while (true)
|
while (true);
|
||||||
;
|
|
||||||
} else if (command == "die_in_thread") {
|
} else if (command == "die_in_thread") {
|
||||||
std::thread t{&DieInThread, nullptr};
|
#if defined(HAVE_PTHREAD)
|
||||||
t.join();
|
pthread_t thread;
|
||||||
|
pthread_create(&thread, nullptr, &DieInThread, nullptr);
|
||||||
|
pthread_join(thread, nullptr);
|
||||||
|
#else
|
||||||
|
fprintf(stderr, "no pthread\n");
|
||||||
|
return 1;
|
||||||
|
#endif
|
||||||
} else if (command == "dump_to_stdout") {
|
} else if (command == "dump_to_stdout") {
|
||||||
InstallFailureWriter(WriteToStdout);
|
InstallFailureWriter(WriteToStdout);
|
||||||
abort();
|
abort();
|
||||||
} else if (command == "installed") {
|
} else if (command == "installed") {
|
||||||
fprintf(stderr, "signal handler installed: %s\n",
|
fprintf(stderr, "signal handler installed: %s\n",
|
||||||
IsFailureSignalHandlerInstalled() ? "true" : "false");
|
IsFailureSignalHandlerInstalled() ? "true" : "false");
|
||||||
} else {
|
} else {
|
||||||
// Tell the shell script
|
// Tell the shell script
|
||||||
puts("OK");
|
puts("OK");
|
||||||
|
|||||||
@ -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
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2000 - 2007, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -30,46 +30,13 @@
|
|||||||
// Routines to extract the current stack trace. These functions are
|
// Routines to extract the current stack trace. These functions are
|
||||||
// thread-safe.
|
// thread-safe.
|
||||||
|
|
||||||
#ifndef GLOG_INTERNAL_STACKTRACE_H
|
#ifndef BASE_STACKTRACE_H_
|
||||||
#define GLOG_INTERNAL_STACKTRACE_H
|
#define BASE_STACKTRACE_H_
|
||||||
|
|
||||||
#include "glog/platform.h"
|
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_NO_EXPORT)
|
|
||||||
# error "stacktrace.h" was not included correctly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#if defined(HAVE_LIBUNWIND)
|
#include "glog/logging.h"
|
||||||
# define STACKTRACE_H "stacktrace_libunwind-inl.h"
|
|
||||||
#elif defined(HAVE_UNWIND)
|
|
||||||
# define STACKTRACE_H "stacktrace_unwind-inl.h"
|
|
||||||
#elif !defined(NO_FRAME_POINTER)
|
|
||||||
# if defined(__i386__) && __GNUC__ >= 2
|
|
||||||
# define STACKTRACE_H "stacktrace_x86-inl.h"
|
|
||||||
# elif (defined(__ppc__) || defined(__PPC__)) && __GNUC__ >= 2
|
|
||||||
# define STACKTRACE_H "stacktrace_powerpc-inl.h"
|
|
||||||
# elif defined(GLOG_OS_WINDOWS)
|
|
||||||
# define STACKTRACE_H "stacktrace_windows-inl.h"
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(STACKTRACE_H) && defined(HAVE_EXECINFO_BACKTRACE)
|
_START_GOOGLE_NAMESPACE_
|
||||||
# define STACKTRACE_H "stacktrace_generic-inl.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(STACKTRACE_H)
|
|
||||||
# define HAVE_STACKTRACE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace google {
|
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
#if defined(HAVE_STACKTRACE)
|
|
||||||
|
|
||||||
// This is similar to the GetStackFrames routine, except that it returns
|
// This is similar to the GetStackFrames routine, except that it returns
|
||||||
// the stack trace only, and not the stack frame sizes as well.
|
// the stack trace only, and not the stack frame sizes as well.
|
||||||
@ -87,11 +54,8 @@ inline namespace glog_internal_namespace_ {
|
|||||||
// .... ...
|
// .... ...
|
||||||
//
|
//
|
||||||
// "result" must not be nullptr.
|
// "result" must not be nullptr.
|
||||||
GLOG_NO_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
|
GLOG_EXPORT int GetStackTrace(void** result, int max_depth, int skip_count);
|
||||||
|
|
||||||
#endif // defined(HAVE_STACKTRACE)
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
#endif // BASE_STACKTRACE_H_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // GLOG_INTERNAL_STACKTRACE_H
|
|
||||||
|
|||||||
@ -37,13 +37,12 @@
|
|||||||
|
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
static const int kStackLength = 64;
|
static const int kStackLength = 64;
|
||||||
void* stack[kStackLength];
|
void * stack[kStackLength];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
size = backtrace(stack, kStackLength);
|
size = backtrace(stack, kStackLength);
|
||||||
@ -62,5 +61,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
return result_count;
|
return result_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|||||||
@ -40,8 +40,7 @@ extern "C" {
|
|||||||
#include "glog/raw_logging.h"
|
#include "glog/raw_logging.h"
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Sometimes, we can try to get a stack trace from within a stack
|
// Sometimes, we can try to get a stack trace from within a stack
|
||||||
// trace, because libunwind can call mmap (maybe indirectly via an
|
// trace, because libunwind can call mmap (maybe indirectly via an
|
||||||
@ -52,11 +51,11 @@ inline namespace glog_internal_namespace_ {
|
|||||||
// cases, we return 0 to indicate the situation.
|
// cases, we return 0 to indicate the situation.
|
||||||
// We can use the GCC __thread syntax here since libunwind is not supported on
|
// We can use the GCC __thread syntax here since libunwind is not supported on
|
||||||
// Windows.
|
// Windows.
|
||||||
static __thread bool g_tl_entered; // Initialized to false.
|
static __thread bool g_tl_entered; // Initialized to false.
|
||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void* ip;
|
void *ip;
|
||||||
int n = 0;
|
int n = 0;
|
||||||
unw_cursor_t cursor;
|
unw_cursor_t cursor;
|
||||||
unw_context_t uc;
|
unw_context_t uc;
|
||||||
@ -68,11 +67,11 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
|
|
||||||
unw_getcontext(&uc);
|
unw_getcontext(&uc);
|
||||||
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
|
RAW_CHECK(unw_init_local(&cursor, &uc) >= 0, "unw_init_local failed");
|
||||||
skip_count++; // Do not include the "GetStackTrace" frame
|
skip_count++; // Do not include the "GetStackTrace" frame
|
||||||
|
|
||||||
while (n < max_depth) {
|
while (n < max_depth) {
|
||||||
int ret =
|
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) {
|
if (ret < 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -91,5 +90,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|||||||
@ -40,16 +40,15 @@
|
|||||||
|
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Given a pointer to a stack frame, locate and return the calling
|
// Given a pointer to a stack frame, locate and return the calling
|
||||||
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
||||||
// checks (the strictness of which is controlled by the boolean parameter
|
// checks (the strictness of which is controlled by the boolean parameter
|
||||||
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
||||||
template <bool STRICT_UNWINDING>
|
template<bool STRICT_UNWINDING>
|
||||||
static void** NextStackFrame(void** old_sp) {
|
static void **NextStackFrame(void **old_sp) {
|
||||||
void** new_sp = static_cast<void**>(*old_sp);
|
void **new_sp = static_cast<void **>(*old_sp);
|
||||||
|
|
||||||
// Check that the transition from frame pointer old_sp to frame
|
// Check that the transition from frame pointer old_sp to frame
|
||||||
// pointer new_sp isn't clearly bogus
|
// pointer new_sp isn't clearly bogus
|
||||||
@ -69,7 +68,7 @@ static void** NextStackFrame(void** old_sp) {
|
|||||||
return nullptr;
|
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;
|
return new_sp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,15 +78,15 @@ void StacktracePowerPCDummyFunction() { __asm__ volatile(""); }
|
|||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void** sp;
|
void **sp;
|
||||||
// Apple OS X uses an old version of gnu as -- both Darwin 7.9.0 (Panther)
|
// 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
|
// 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
|
// 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__.
|
// systems using the old as from the new one; I've gone with __APPLE__.
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
__asm__ volatile("mr %0,r1" : "=r"(sp));
|
__asm__ volatile ("mr %0,r1" : "=r" (sp));
|
||||||
#else
|
#else
|
||||||
__asm__ volatile("mr %0,1" : "=r"(sp));
|
__asm__ volatile ("mr %0,1" : "=r" (sp));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On PowerPC, the "Link Register" or "Link Record" (LR), is a stack
|
// 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),
|
// linux ppc64), it's in sp[2]. For SYSV (used by linux ppc),
|
||||||
// it's in sp[1].
|
// it's in sp[1].
|
||||||
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
|
#if defined(_CALL_AIX) || defined(_CALL_DARWIN)
|
||||||
result[n++] = *(sp + 2);
|
result[n++] = *(sp+2);
|
||||||
#elif defined(_CALL_SYSV)
|
#elif defined(_CALL_SYSV)
|
||||||
result[n++] = *(sp + 1);
|
result[n++] = *(sp+1);
|
||||||
#elif defined(__APPLE__) || \
|
#elif defined(__APPLE__) || ((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
||||||
((defined(__linux) || defined(__linux__)) && defined(__PPC64__))
|
|
||||||
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
// This check is in case the compiler doesn't define _CALL_AIX/etc.
|
||||||
result[n++] = *(sp + 2);
|
result[n++] = *(sp+2);
|
||||||
#elif defined(__linux) || defined(__OpenBSD__)
|
#elif defined(__linux) || defined(__OpenBSD__)
|
||||||
// This check is in case the compiler doesn't define _CALL_SYSV.
|
// This check is in case the compiler doesn't define _CALL_SYSV.
|
||||||
result[n++] = *(sp + 1);
|
result[n++] = *(sp+1);
|
||||||
#else
|
#else
|
||||||
# error Need to specify the PPC ABI for your architecture.
|
#error Need to specify the PPC ABI for your architecture.
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
// Use strict unwinding rules.
|
// Use strict unwinding rules.
|
||||||
@ -132,5 +130,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|||||||
@ -38,9 +38,11 @@
|
|||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
||||||
# include <execinfo.h>
|
# include <execinfo.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
|
|
||||||
// Obtain a backtrace, verify that the expected callers are present in the
|
// Obtain a backtrace, verify that the expected callers are present in the
|
||||||
@ -57,87 +59,81 @@ struct AddressRange {
|
|||||||
// Expected function [start,end] range.
|
// Expected function [start,end] range.
|
||||||
AddressRange expected_range[BACKTRACE_STEPS];
|
AddressRange expected_range[BACKTRACE_STEPS];
|
||||||
|
|
||||||
# if __GNUC__
|
#if __GNUC__
|
||||||
// Using GCC extension: address of a label can be taken with '&&label'.
|
// Using GCC extension: address of a label can be taken with '&&label'.
|
||||||
// Start should be a label somewhere before recursive call, end somewhere
|
// Start should be a label somewhere before recursive call, end somewhere
|
||||||
// after it.
|
// after it.
|
||||||
# define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
#define INIT_ADDRESS_RANGE(fn, start_label, end_label, prange) \
|
||||||
do { \
|
do { \
|
||||||
(prange)->start = &&start_label; \
|
(prange)->start = &&start_label; \
|
||||||
(prange)->end = &&end_label; \
|
(prange)->end = &&end_label; \
|
||||||
CHECK_LT((prange)->start, (prange)->end); \
|
CHECK_LT((prange)->start, (prange)->end); \
|
||||||
} while (0)
|
} while (0)
|
||||||
// This macro expands into "unmovable" code (opaque to GCC), and that
|
// This macro expands into "unmovable" code (opaque to GCC), and that
|
||||||
// prevents GCC from moving a_label up or down in the code.
|
// prevents GCC from moving a_label up or down in the code.
|
||||||
// Without it, there is no code following the 'end' label, and GCC
|
// 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
|
// (4.3.1, 4.4.0) thinks it safe to assign &&end an address that is before
|
||||||
// the recursive call.
|
// the recursive call.
|
||||||
# define DECLARE_ADDRESS_LABEL(a_label) \
|
#define DECLARE_ADDRESS_LABEL(a_label) \
|
||||||
a_label: \
|
a_label: do { __asm__ __volatile__(""); } while (0)
|
||||||
do { \
|
|
||||||
__asm__ __volatile__(""); \
|
|
||||||
} while (0)
|
|
||||||
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
// Gcc 4.4.0 may split function into multiple chunks, and the chunk
|
||||||
// performing recursive call may end up later in the code then the return
|
// performing recursive call may end up later in the code then the return
|
||||||
// instruction (this actually happens with FDO).
|
// instruction (this actually happens with FDO).
|
||||||
// Adjust function range from __builtin_return_address.
|
// Adjust function range from __builtin_return_address.
|
||||||
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
||||||
do { \
|
do { \
|
||||||
void* ra = __builtin_return_address(0); \
|
void *ra = __builtin_return_address(0); \
|
||||||
CHECK_LT((prange)->start, ra); \
|
CHECK_LT((prange)->start, ra); \
|
||||||
if (ra > (prange)->end) { \
|
if (ra > (prange)->end) { \
|
||||||
printf("Adjusting range from %p..%p to %p..%p\n", (prange)->start, \
|
printf("Adjusting range from %p..%p to %p..%p\n", \
|
||||||
(prange)->end, (prange)->start, ra); \
|
(prange)->start, (prange)->end, \
|
||||||
(prange)->end = ra; \
|
(prange)->start, ra); \
|
||||||
} \
|
(prange)->end = ra; \
|
||||||
} while (0)
|
} \
|
||||||
# else
|
} while (0)
|
||||||
|
#else
|
||||||
// Assume the Check* functions below are not longer than 256 bytes.
|
// 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 { \
|
do { \
|
||||||
(prange)->start = reinterpret_cast<const void*>(&fn); \
|
(prange)->start = reinterpret_cast<const void *>(&fn); \
|
||||||
(prange)->end = reinterpret_cast<const char*>(&fn) + 256; \
|
(prange)->end = reinterpret_cast<const char *>(&fn) + 256; \
|
||||||
} while (0)
|
} while (0)
|
||||||
# define DECLARE_ADDRESS_LABEL(a_label) \
|
#define DECLARE_ADDRESS_LABEL(a_label) do { } while (0)
|
||||||
do { \
|
#define ADJUST_ADDRESS_RANGE_FROM_RA(prange) do { } while (0)
|
||||||
} while (0)
|
#endif // __GNUC__
|
||||||
# define ADJUST_ADDRESS_RANGE_FROM_RA(prange) \
|
|
||||||
do { \
|
|
||||||
} while (0)
|
|
||||||
# endif // __GNUC__
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
static void CheckRetAddrIsInFunction(void* ret_addr,
|
static void CheckRetAddrIsInFunction(void *ret_addr, const AddressRange &range)
|
||||||
const AddressRange& range) {
|
{
|
||||||
CHECK_GE(ret_addr, range.start);
|
CHECK_GE(ret_addr, range.start);
|
||||||
CHECK_LE(ret_addr, range.end);
|
CHECK_LE(ret_addr, range.end);
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
# if defined(__clang__)
|
#if defined(__clang__)
|
||||||
# pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
# pragma clang diagnostic ignored "-Wgnu-label-as-value"
|
#pragma clang diagnostic ignored "-Wgnu-label-as-value"
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
|
void ATTRIBUTE_NOINLINE CheckStackTrace(int);
|
||||||
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
static void ATTRIBUTE_NOINLINE CheckStackTraceLeaf() {
|
||||||
const int STACK_LEN = 10;
|
const int STACK_LEN = 10;
|
||||||
void* stack[STACK_LEN];
|
void *stack[STACK_LEN];
|
||||||
int size;
|
int size;
|
||||||
|
|
||||||
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
|
ADJUST_ADDRESS_RANGE_FROM_RA(&expected_range[1]);
|
||||||
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
|
INIT_ADDRESS_RANGE(CheckStackTraceLeaf, start, end, &expected_range[0]);
|
||||||
DECLARE_ADDRESS_LABEL(start);
|
DECLARE_ADDRESS_LABEL(start);
|
||||||
size = google::GetStackTrace(stack, STACK_LEN, 0);
|
size = GetStackTrace(stack, STACK_LEN, 0);
|
||||||
printf("Obtained %d stack frames.\n", size);
|
printf("Obtained %d stack frames.\n", size);
|
||||||
CHECK_GE(size, 1);
|
CHECK_GE(size, 1);
|
||||||
CHECK_LE(size, STACK_LEN);
|
CHECK_LE(size, STACK_LEN);
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
# ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
#ifdef HAVE_EXECINFO_BACKTRACE_SYMBOLS
|
||||||
char** strings = backtrace_symbols(stack, size);
|
char **strings = backtrace_symbols(stack, size);
|
||||||
printf("Obtained %d stack frames.\n", size);
|
printf("Obtained %d stack frames.\n", size);
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
printf("%s %p\n", strings[i], stack[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);
|
printf("CheckStackTrace() addr: %p\n", p.p2);
|
||||||
free(strings);
|
free(strings);
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
for (int i = 0; i < BACKTRACE_STEPS; i++) {
|
||||||
printf("Backtrace %d: expected: %p..%p actual: %p ... ", i,
|
printf("Backtrace %d: expected: %p..%p actual: %p ... ",
|
||||||
expected_range[i].start, expected_range[i].end, stack[i]);
|
i, expected_range[i].start, expected_range[i].end, stack[i]);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
CheckRetAddrIsInFunction(stack[i], expected_range[i]);
|
||||||
printf("OK\n");
|
printf("OK\n");
|
||||||
@ -202,7 +198,7 @@ static void ATTRIBUTE_NOINLINE CheckStackTrace1(int i) {
|
|||||||
DECLARE_ADDRESS_LABEL(end);
|
DECLARE_ADDRESS_LABEL(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifndef __GNUC__
|
#ifndef __GNUC__
|
||||||
// On non-GNU environment, we use the address of `CheckStackTrace` to
|
// On non-GNU environment, we use the address of `CheckStackTrace` to
|
||||||
// guess the address range of this function. This guess is wrong for
|
// guess the address range of this function. This guess is wrong for
|
||||||
// non-static function on Windows. This is probably because
|
// 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`.
|
// not the actual address of `CheckStackTrace`.
|
||||||
// See https://github.com/google/glog/issues/421 for the detail.
|
// See https://github.com/google/glog/issues/421 for the detail.
|
||||||
static
|
static
|
||||||
# endif
|
#endif
|
||||||
void ATTRIBUTE_NOINLINE
|
void ATTRIBUTE_NOINLINE CheckStackTrace(int i) {
|
||||||
CheckStackTrace(int i) {
|
|
||||||
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
INIT_ADDRESS_RANGE(CheckStackTrace, start, end, &expected_range[5]);
|
||||||
DECLARE_ADDRESS_LABEL(start);
|
DECLARE_ADDRESS_LABEL(start);
|
||||||
for (int j = i; j >= 0; j--) {
|
for (int j = i; j >= 0; j--) {
|
||||||
@ -221,15 +216,15 @@ static
|
|||||||
DECLARE_ADDRESS_LABEL(end);
|
DECLARE_ADDRESS_LABEL(end);
|
||||||
}
|
}
|
||||||
|
|
||||||
# if defined(__clang__)
|
#if defined(__clang__)
|
||||||
# pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
//-----------------------------------------------------------------------//
|
//-----------------------------------------------------------------------//
|
||||||
|
|
||||||
int main(int, char** argv) {
|
int main(int, char ** argv) {
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
google::InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
|
|
||||||
CheckStackTrace(0);
|
CheckStackTrace(0);
|
||||||
|
|
||||||
@ -240,12 +235,12 @@ int main(int, char** argv) {
|
|||||||
#else
|
#else
|
||||||
int main() {
|
int main() {
|
||||||
|
|
||||||
# ifdef GLOG_BAZEL_BUILD
|
#ifdef GLOG_BAZEL_BUILD
|
||||||
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
|
printf("HAVE_STACKTRACE is expected to be defined in Bazel tests\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
# endif // GLOG_BAZEL_BUILD
|
#endif // GLOG_BAZEL_BUILD
|
||||||
|
|
||||||
printf("PASS (no stacktrace support)\n");
|
printf("PASS (no stacktrace support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
#endif // HAVE_STACKTRACE
|
#endif // HAVE_STACKTRACE
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2023, Google Inc.
|
// Copyright (c) 2005 - 2007, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -33,47 +33,48 @@
|
|||||||
|
|
||||||
#include <unwind.h> // ABI defined unwinder
|
#include <unwind.h> // ABI defined unwinder
|
||||||
|
|
||||||
|
#include <cstdlib> // for nullptr
|
||||||
|
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
struct trace_arg_t {
|
struct trace_arg_t {
|
||||||
void** result;
|
void **result;
|
||||||
int max_depth;
|
int max_depth;
|
||||||
int skip_count;
|
int skip_count;
|
||||||
int count;
|
int count;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
// Workaround for the malloc() in _Unwind_Backtrace() issue.
|
||||||
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context* /*uc*/,
|
static _Unwind_Reason_Code nop_backtrace(struct _Unwind_Context */*uc*/, void */*opq*/) {
|
||||||
void* /*opq*/) {
|
|
||||||
return _URC_NO_REASON;
|
return _URC_NO_REASON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// This code is not considered ready to run until
|
// This code is not considered ready to run until
|
||||||
// static initializers run so that we are guaranteed
|
// static initializers run so that we are guaranteed
|
||||||
// that any malloc-related initialization is done.
|
// that any malloc-related initialization is done.
|
||||||
static bool ready_to_run = false;
|
static bool ready_to_run = false;
|
||||||
class StackTraceInit {
|
class StackTraceInit {
|
||||||
public:
|
public:
|
||||||
StackTraceInit() {
|
StackTraceInit() {
|
||||||
// Extra call to force initialization
|
// Extra call to force initialization
|
||||||
_Unwind_Backtrace(nop_backtrace, nullptr);
|
_Unwind_Backtrace(nop_backtrace, nullptr);
|
||||||
ready_to_run = true;
|
ready_to_run = true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static StackTraceInit module_initializer; // Force initialization
|
static StackTraceInit module_initializer; // Force initialization
|
||||||
|
|
||||||
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context* uc, void* opq) {
|
static _Unwind_Reason_Code GetOneFrame(struct _Unwind_Context *uc, void *opq) {
|
||||||
auto* targ = static_cast<trace_arg_t*>(opq);
|
auto *targ = static_cast<trace_arg_t *>(opq);
|
||||||
|
|
||||||
if (targ->skip_count > 0) {
|
if (targ->skip_count > 0) {
|
||||||
targ->skip_count--;
|
targ->skip_count--;
|
||||||
} else {
|
} 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) {
|
if (targ->count == targ->max_depth) {
|
||||||
return _URC_END_OF_STACK;
|
return _URC_END_OF_STACK;
|
||||||
@ -90,7 +91,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
|
|
||||||
trace_arg_t targ;
|
trace_arg_t targ;
|
||||||
|
|
||||||
skip_count += 1; // Do not include the "GetStackTrace" frame
|
skip_count += 1; // Do not include the "GetStackTrace" frame
|
||||||
|
|
||||||
targ.result = result;
|
targ.result = result;
|
||||||
targ.max_depth = max_depth;
|
targ.max_depth = max_depth;
|
||||||
@ -102,5 +103,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
return targ.count;
|
return targ.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|||||||
@ -31,13 +31,12 @@
|
|||||||
//
|
//
|
||||||
// Windows implementation - just use CaptureStackBackTrace
|
// Windows implementation - just use CaptureStackBackTrace
|
||||||
|
|
||||||
// clang-format off
|
#include "config.h"
|
||||||
#include <windows.h> // Must come before <dbghelp.h>
|
#include "port.h"
|
||||||
|
#include "stacktrace.h"
|
||||||
#include <dbghelp.h>
|
#include <dbghelp.h>
|
||||||
// clang-format on
|
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
if (max_depth > 64) {
|
if (max_depth > 64) {
|
||||||
@ -49,5 +48,4 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
static_cast<DWORD>(max_depth), result, nullptr);
|
static_cast<DWORD>(max_depth), result, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|||||||
@ -31,27 +31,26 @@
|
|||||||
|
|
||||||
#include <cstdint> // for uintptr_t
|
#include <cstdint> // for uintptr_t
|
||||||
|
|
||||||
#include "utilities.h" // for OS_* macros
|
#include "utilities.h" // for OS_* macros
|
||||||
|
|
||||||
#if !defined(GLOG_OS_WINDOWS)
|
#if !defined(GLOG_OS_WINDOWS)
|
||||||
# include <sys/mman.h>
|
#include <unistd.h>
|
||||||
# include <unistd.h>
|
#include <sys/mman.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <cstdio> // for nullptr
|
#include <cstdio> // for nullptr
|
||||||
|
|
||||||
#include "stacktrace.h"
|
#include "stacktrace.h"
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Given a pointer to a stack frame, locate and return the calling
|
// Given a pointer to a stack frame, locate and return the calling
|
||||||
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
// stackframe, or return nullptr if no stackframe can be found. Perform sanity
|
||||||
// checks (the strictness of which is controlled by the boolean parameter
|
// checks (the strictness of which is controlled by the boolean parameter
|
||||||
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
// "STRICT_UNWINDING") to reduce the chance that a bad pointer is returned.
|
||||||
template <bool STRICT_UNWINDING>
|
template<bool STRICT_UNWINDING>
|
||||||
static void** NextStackFrame(void** old_sp) {
|
static void **NextStackFrame(void **old_sp) {
|
||||||
void** new_sp = static_cast<void**>(*old_sp);
|
void **new_sp = static_cast<void **>(*old_sp);
|
||||||
|
|
||||||
// Check that the transition from frame pointer old_sp to frame
|
// Check that the transition from frame pointer old_sp to frame
|
||||||
// pointer new_sp isn't clearly bogus
|
// pointer new_sp isn't clearly bogus
|
||||||
@ -76,7 +75,7 @@ static void** NextStackFrame(void** old_sp) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void*) - 1)) {
|
if (reinterpret_cast<uintptr_t>(new_sp) & (sizeof(void *) - 1)) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
@ -93,9 +92,9 @@ static void** NextStackFrame(void** old_sp) {
|
|||||||
// Note: NextStackFrame<false>() is only called while the program
|
// Note: NextStackFrame<false>() is only called while the program
|
||||||
// is already on its last leg, so it's ok to be slow here.
|
// is already on its last leg, so it's ok to be slow here.
|
||||||
static int page_size = getpagesize();
|
static int page_size = getpagesize();
|
||||||
void* new_sp_aligned =
|
void *new_sp_aligned =
|
||||||
reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(new_sp) &
|
reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(new_sp) &
|
||||||
static_cast<uintptr_t>(~(page_size - 1)));
|
static_cast<uintptr_t>(~(page_size - 1)));
|
||||||
if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {
|
if (msync(new_sp_aligned, static_cast<size_t>(page_size), MS_ASYNC) == -1) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -106,12 +105,12 @@ static void** NextStackFrame(void** old_sp) {
|
|||||||
|
|
||||||
// If you change this function, also change GetStackFrames below.
|
// If you change this function, also change GetStackFrames below.
|
||||||
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
int GetStackTrace(void** result, int max_depth, int skip_count) {
|
||||||
void** sp;
|
void **sp;
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
# if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
|
#if __GNUC__ * 100 + __GNUC_MINOR__ >= 402
|
||||||
# define USE_BUILTIN_FRAME_ADDRESS
|
#define USE_BUILTIN_FRAME_ADDRESS
|
||||||
# endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_BUILTIN_FRAME_ADDRESS
|
#ifdef USE_BUILTIN_FRAME_ADDRESS
|
||||||
@ -122,7 +121,7 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
// sp[1] caller address
|
// sp[1] caller address
|
||||||
// sp[2] first argument
|
// sp[2] first argument
|
||||||
// ...
|
// ...
|
||||||
sp = (void**)&result - 2;
|
sp = (void **)&result - 2;
|
||||||
#elif defined(__x86_64__)
|
#elif defined(__x86_64__)
|
||||||
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
|
// __builtin_frame_address(0) can return the wrong address on gcc-4.1.0-k8
|
||||||
unsigned long rbp;
|
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
|
// would be (before this __asm__ instruction) to call Noop() defined as
|
||||||
// static void Noop() __attribute__ ((noinline)); // prevent inlining
|
// static void Noop() __attribute__ ((noinline)); // prevent inlining
|
||||||
// static void Noop() { asm(""); } // prevent optimizing-away
|
// 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
|
// Arguments are passed in registers on x86-64, so we can't just
|
||||||
// offset from &result
|
// offset from &result
|
||||||
sp = (void**)rbp;
|
sp = (void **) rbp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int n = 0;
|
int n = 0;
|
||||||
@ -149,12 +148,12 @@ int GetStackTrace(void** result, int max_depth, int skip_count) {
|
|||||||
if (skip_count > 0) {
|
if (skip_count > 0) {
|
||||||
skip_count--;
|
skip_count--;
|
||||||
} else {
|
} else {
|
||||||
result[n++] = *(sp + 1);
|
result[n++] = *(sp+1);
|
||||||
}
|
}
|
||||||
// Use strict unwinding rules.
|
// Use strict unwinding rules.
|
||||||
sp = NextStackFrame<true>(sp);
|
sp = NextStackFrame<true>(sp);
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
} // namespace glog_internal_namespace_
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|||||||
@ -62,14 +62,14 @@ static void TestSTLLogging() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// Test a sorted pair associative container.
|
// Test a sorted pair associative container.
|
||||||
map<int, string> m;
|
map< int, string > m;
|
||||||
m[20] = "twenty";
|
m[20] = "twenty";
|
||||||
m[10] = "ten";
|
m[10] = "ten";
|
||||||
m[30] = "thirty";
|
m[30] = "thirty";
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << m;
|
ss << m;
|
||||||
EXPECT_EQ(ss.str(), "(10, ten) (20, twenty) (30, thirty)");
|
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.
|
CHECK_EQ(m, copied_m); // This must compile.
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ static void TestSTLLogging() {
|
|||||||
if (i > 0) expected += ' ';
|
if (i > 0) expected += ' ';
|
||||||
const size_t buf_size = 256;
|
const size_t buf_size = 256;
|
||||||
char buf[buf_size];
|
char buf[buf_size];
|
||||||
std::snprintf(buf, buf_size, "%d", i);
|
snprintf(buf, buf_size, "%d", i);
|
||||||
expected += buf;
|
expected += buf;
|
||||||
}
|
}
|
||||||
v.push_back(100);
|
v.push_back(100);
|
||||||
@ -95,14 +95,14 @@ static void TestSTLLogging() {
|
|||||||
{
|
{
|
||||||
// Test a sorted pair associative container.
|
// Test a sorted pair associative container.
|
||||||
// Use a non-default comparison functor.
|
// Use a non-default comparison functor.
|
||||||
map<int, string, greater<>> m;
|
map<int, string, greater<> > m;
|
||||||
m[20] = "twenty";
|
m[20] = "twenty";
|
||||||
m[10] = "ten";
|
m[10] = "ten";
|
||||||
m[30] = "thirty";
|
m[30] = "thirty";
|
||||||
ostringstream ss;
|
ostringstream ss;
|
||||||
ss << m;
|
ss << m;
|
||||||
EXPECT_EQ(ss.str(), "(30, thirty) (20, twenty) (10, ten)");
|
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.
|
CHECK_EQ(m, copied_m); // This must compile.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
559
src/symbolize.cc
559
src/symbolize.cc
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -49,123 +49,111 @@
|
|||||||
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
|
// macro to add platform specific defines (e.g. GLOG_OS_OPENBSD).
|
||||||
|
|
||||||
#ifdef GLOG_BUILD_CONFIG_INCLUDE
|
#ifdef GLOG_BUILD_CONFIG_INCLUDE
|
||||||
# include GLOG_BUILD_CONFIG_INCLUDE
|
#include GLOG_BUILD_CONFIG_INCLUDE
|
||||||
#endif // GLOG_BUILD_CONFIG_INCLUDE
|
#endif // GLOG_BUILD_CONFIG_INCLUDE
|
||||||
|
|
||||||
#include "symbolize.h"
|
|
||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_SYMBOLIZE)
|
||||||
|
|
||||||
# include <algorithm>
|
#include <cstring>
|
||||||
# include <cstdlib>
|
|
||||||
# include <cstring>
|
|
||||||
# include <limits>
|
|
||||||
|
|
||||||
# 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
|
// We don't use assert() since it's not guaranteed to be
|
||||||
// async-signal-safe. Instead we define a minimal assertion
|
// async-signal-safe. Instead we define a minimal assertion
|
||||||
// macro. So far, we don't need pretty printing for __FILE__, etc.
|
// macro. So far, we don't need pretty printing for __FILE__, etc.
|
||||||
# define GLOG_SAFE_ASSERT(expr) ((expr) ? 0 : (std::abort(), 0))
|
|
||||||
|
|
||||||
namespace google {
|
// A wrapper for abort() to make it callable in ? :.
|
||||||
inline namespace glog_internal_namespace_ {
|
static int AssertFail() {
|
||||||
|
abort();
|
||||||
namespace {
|
return 0; // Should not reach.
|
||||||
|
|
||||||
SymbolizeCallback g_symbolize_callback = nullptr;
|
|
||||||
SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback = nullptr;
|
|
||||||
|
|
||||||
// This function wraps the Demangle function to provide an interface
|
|
||||||
// where the input symbol is demangled in-place.
|
|
||||||
// To keep stack consumption low, we would like this function to not
|
|
||||||
// get inlined.
|
|
||||||
ATTRIBUTE_NOINLINE
|
|
||||||
void DemangleInplace(char* out, size_t out_size) {
|
|
||||||
char demangled[256]; // Big enough for sane demangled symbols.
|
|
||||||
if (Demangle(out, demangled, sizeof(demangled))) {
|
|
||||||
// Demangling succeeded. Copy to out if the space allows.
|
|
||||||
size_t len = strlen(demangled);
|
|
||||||
if (len + 1 <= out_size) { // +1 for '\0'.
|
|
||||||
GLOG_SAFE_ASSERT(len < sizeof(demangled));
|
|
||||||
memmove(out, demangled, len + 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
#define SAFE_ASSERT(expr) ((expr) ? 0 : AssertFail())
|
||||||
|
|
||||||
|
static SymbolizeCallback g_symbolize_callback = nullptr;
|
||||||
void InstallSymbolizeCallback(SymbolizeCallback callback) {
|
void InstallSymbolizeCallback(SymbolizeCallback callback) {
|
||||||
g_symbolize_callback = callback;
|
g_symbolize_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static SymbolizeOpenObjectFileCallback g_symbolize_open_object_file_callback =
|
||||||
|
nullptr;
|
||||||
void InstallSymbolizeOpenObjectFileCallback(
|
void InstallSymbolizeOpenObjectFileCallback(
|
||||||
SymbolizeOpenObjectFileCallback callback) {
|
SymbolizeOpenObjectFileCallback callback) {
|
||||||
g_symbolize_open_object_file_callback = callback;
|
g_symbolize_open_object_file_callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
// This function wraps the Demangle function to provide an interface
|
||||||
} // namespace google
|
// where the input symbol is demangled in-place.
|
||||||
|
// To keep stack consumption low, we would like this function to not
|
||||||
# if defined(HAVE_LINK_H)
|
// get inlined.
|
||||||
|
static ATTRIBUTE_NOINLINE void DemangleInplace(char *out, size_t out_size) {
|
||||||
# if defined(HAVE_DLFCN_H)
|
char demangled[256]; // Big enough for sane demangled symbols.
|
||||||
# include <dlfcn.h>
|
if (Demangle(out, demangled, sizeof(demangled))) {
|
||||||
# endif
|
// Demangling succeeded. Copy to out if the space allows.
|
||||||
# include <fcntl.h>
|
size_t len = strlen(demangled);
|
||||||
# include <sys/stat.h>
|
if (len + 1 <= out_size) { // +1 for '\0'.
|
||||||
# include <sys/types.h>
|
SAFE_ASSERT(len < sizeof(demangled));
|
||||||
# include <unistd.h>
|
memmove(out, demangled, len + 1);
|
||||||
|
}
|
||||||
# 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) {
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Read up to "count" bytes from "offset" in the file pointed by file
|
||||||
// descriptor "fd" into the buffer starting at "buf" while handling short reads
|
// descriptor "fd" into the buffer starting at "buf" while handling short reads
|
||||||
// and EINTR. On success, return the number of bytes read. Otherwise, return
|
// and EINTR. On success, return the number of bytes read. Otherwise, return
|
||||||
// -1.
|
// -1.
|
||||||
static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
static ssize_t ReadFromOffset(const int fd, void *buf, const size_t count,
|
||||||
const size_t offset) {
|
const size_t offset) {
|
||||||
GLOG_SAFE_ASSERT(fd >= 0);
|
SAFE_ASSERT(fd >= 0);
|
||||||
GLOG_SAFE_ASSERT(count <=
|
SAFE_ASSERT(count <= static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
||||||
static_cast<size_t>(std::numeric_limits<ssize_t>::max()));
|
char *buf0 = reinterpret_cast<char *>(buf);
|
||||||
char* buf0 = reinterpret_cast<char*>(buf);
|
|
||||||
size_t num_bytes = 0;
|
size_t num_bytes = 0;
|
||||||
while (num_bytes < count) {
|
while (num_bytes < count) {
|
||||||
ssize_t len = FailureRetry([fd, p = buf0 + num_bytes, n = count - num_bytes,
|
ssize_t len;
|
||||||
m = static_cast<off_t>(offset + num_bytes)] {
|
NO_INTR(len = pread(fd, buf0 + num_bytes, count - num_bytes,
|
||||||
return pread(fd, p, n, m);
|
static_cast<off_t>(offset + num_bytes)));
|
||||||
});
|
|
||||||
if (len < 0) { // There was an error other than EINTR.
|
if (len < 0) { // There was an error other than EINTR.
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -174,7 +162,7 @@ static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
|||||||
}
|
}
|
||||||
num_bytes += static_cast<size_t>(len);
|
num_bytes += static_cast<size_t>(len);
|
||||||
}
|
}
|
||||||
GLOG_SAFE_ASSERT(num_bytes <= count);
|
SAFE_ASSERT(num_bytes <= count);
|
||||||
return static_cast<ssize_t>(num_bytes);
|
return static_cast<ssize_t>(num_bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -182,8 +170,8 @@ static ssize_t ReadFromOffset(const int fd, void* buf, const size_t count,
|
|||||||
// pointed by "fd" into the buffer starting at "buf" while handling
|
// pointed by "fd" into the buffer starting at "buf" while handling
|
||||||
// short reads and EINTR. On success, return true. Otherwise, return
|
// short reads and EINTR. On success, return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool ReadFromOffsetExact(const int fd, void* buf, const size_t count,
|
static bool ReadFromOffsetExact(const int fd, void *buf,
|
||||||
const size_t offset) {
|
const size_t count, const size_t offset) {
|
||||||
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
ssize_t len = ReadFromOffset(fd, buf, count, offset);
|
||||||
return static_cast<size_t>(len) == count;
|
return static_cast<size_t>(len) == count;
|
||||||
}
|
}
|
||||||
@ -205,11 +193,9 @@ static int FileGetElfType(const int fd) {
|
|||||||
// and return true. Otherwise, return false.
|
// and return true. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
|
static ATTRIBUTE_NOINLINE bool
|
||||||
ElfW(Half) sh_num,
|
GetSectionHeaderByType(const int fd, ElfW(Half) sh_num, const size_t sh_offset,
|
||||||
const size_t sh_offset,
|
ElfW(Word) type, ElfW(Shdr) *out) {
|
||||||
ElfW(Word) type,
|
|
||||||
ElfW(Shdr) * out) {
|
|
||||||
// Read at most 16 section headers at a time to save read calls.
|
// Read at most 16 section headers at a time to save read calls.
|
||||||
ElfW(Shdr) buf[16];
|
ElfW(Shdr) buf[16];
|
||||||
for (size_t i = 0; i < sh_num;) {
|
for (size_t i = 0; i < sh_num;) {
|
||||||
@ -221,9 +207,9 @@ static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
|
|||||||
if (len == -1) {
|
if (len == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
|
SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
|
||||||
const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
|
const size_t num_headers_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
|
||||||
GLOG_SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
|
SAFE_ASSERT(num_headers_in_buf <= sizeof(buf) / sizeof(buf[0]));
|
||||||
for (size_t j = 0; j < num_headers_in_buf; ++j) {
|
for (size_t j = 0; j < num_headers_in_buf; ++j) {
|
||||||
if (buf[j].sh_type == type) {
|
if (buf[j].sh_type == type) {
|
||||||
*out = buf[j];
|
*out = buf[j];
|
||||||
@ -240,8 +226,8 @@ static ATTRIBUTE_NOINLINE bool GetSectionHeaderByType(const int fd,
|
|||||||
const int kMaxSectionNameLen = 64;
|
const int kMaxSectionNameLen = 64;
|
||||||
|
|
||||||
// name_len should include terminating '\0'.
|
// name_len should include terminating '\0'.
|
||||||
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
|
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
||||||
ElfW(Shdr) * out) {
|
ElfW(Shdr) *out) {
|
||||||
ElfW(Ehdr) elf_header;
|
ElfW(Ehdr) elf_header;
|
||||||
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
||||||
return false;
|
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) {
|
for (size_t i = 0; i < elf_header.e_shnum; ++i) {
|
||||||
size_t section_header_offset =
|
size_t section_header_offset = (elf_header.e_shoff +
|
||||||
(elf_header.e_shoff + elf_header.e_shentsize * i);
|
elf_header.e_shentsize * i);
|
||||||
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
if (!ReadFromOffsetExact(fd, out, sizeof(*out), section_header_offset)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
char header_name[kMaxSectionNameLen];
|
char header_name[kMaxSectionNameLen];
|
||||||
if (sizeof(header_name) < name_len) {
|
if (sizeof(header_name) < name_len) {
|
||||||
RAW_LOG(WARNING,
|
RAW_LOG(WARNING, "Section name '%s' is too long (%" PRIuS "); "
|
||||||
"Section name '%s' is too long (%zu); "
|
"section will not be found (even if present).", name, name_len);
|
||||||
"section will not be found (even if present).",
|
|
||||||
name, name_len);
|
|
||||||
// No point in even trying.
|
// No point in even trying.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -291,11 +275,10 @@ bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
|
|||||||
// to out. Otherwise, return false.
|
// to out. Otherwise, return false.
|
||||||
// To keep stack consumption low, we would like this function to not get
|
// To keep stack consumption low, we would like this function to not get
|
||||||
// inlined.
|
// inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
|
static ATTRIBUTE_NOINLINE bool
|
||||||
size_t out_size,
|
FindSymbol(uint64_t pc, const int fd, char *out, size_t out_size,
|
||||||
uint64_t symbol_offset,
|
uint64_t symbol_offset, const ElfW(Shdr) *strtab,
|
||||||
const ElfW(Shdr) * strtab,
|
const ElfW(Shdr) *symtab) {
|
||||||
const ElfW(Shdr) * symtab) {
|
|
||||||
if (symtab == nullptr) {
|
if (symtab == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -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
|
// If we are reading Elf64_Sym's, we want to limit this array to
|
||||||
// 32 elements (to keep stack consumption low), otherwise we can
|
// 32 elements (to keep stack consumption low), otherwise we can
|
||||||
// have a 64 element Elf32_Sym array.
|
// have a 64 element Elf32_Sym array.
|
||||||
# if defined(__WORDSIZE) && __WORDSIZE == 64
|
#if defined(__WORDSIZE) && __WORDSIZE == 64
|
||||||
const size_t NUM_SYMBOLS = 32U;
|
const size_t NUM_SYMBOLS = 32U;
|
||||||
# else
|
#else
|
||||||
const size_t NUM_SYMBOLS = 64U;
|
const size_t NUM_SYMBOLS = 64U;
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
|
// Read at most NUM_SYMBOLS symbols at once to save read() calls.
|
||||||
ElfW(Sym) buf[NUM_SYMBOLS];
|
ElfW(Sym) buf[NUM_SYMBOLS];
|
||||||
size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
|
size_t num_symbols_to_read = std::min(NUM_SYMBOLS, num_symbols - i);
|
||||||
const ssize_t len =
|
const ssize_t len =
|
||||||
ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
|
ReadFromOffset(fd, &buf, sizeof(buf[0]) * num_symbols_to_read, offset);
|
||||||
GLOG_SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
|
SAFE_ASSERT(static_cast<size_t>(len) % sizeof(buf[0]) == 0);
|
||||||
const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
|
const size_t num_symbols_in_buf = static_cast<size_t>(len) / sizeof(buf[0]);
|
||||||
GLOG_SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
|
SAFE_ASSERT(num_symbols_in_buf <= num_symbols_to_read);
|
||||||
for (unsigned j = 0; j < num_symbols_in_buf; ++j) {
|
for (unsigned j = 0; j < num_symbols_in_buf; ++j) {
|
||||||
const ElfW(Sym)& symbol = buf[j];
|
const ElfW(Sym)& symbol = buf[j];
|
||||||
uint64_t start_address = symbol.st_value;
|
uint64_t start_address = symbol.st_value;
|
||||||
@ -346,8 +329,11 @@ static ATTRIBUTE_NOINLINE bool FindSymbol(uint64_t pc, const int fd, char* out,
|
|||||||
// both regular and dynamic symbol tables if necessary. On success,
|
// both regular and dynamic symbol tables if necessary. On success,
|
||||||
// write the symbol name to "out" and return true. Otherwise, return
|
// write the symbol name to "out" and return true. Otherwise, return
|
||||||
// false.
|
// false.
|
||||||
static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
static bool GetSymbolFromObjectFile(const int fd,
|
||||||
size_t out_size, uint64_t base_address) {
|
uint64_t pc,
|
||||||
|
char* out,
|
||||||
|
size_t out_size,
|
||||||
|
uint64_t base_address) {
|
||||||
// Read the ELF header.
|
// Read the ELF header.
|
||||||
ElfW(Ehdr) elf_header;
|
ElfW(Ehdr) elf_header;
|
||||||
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
if (!ReadFromOffsetExact(fd, &elf_header, sizeof(elf_header), 0)) {
|
||||||
@ -359,9 +345,8 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
|||||||
// Consult a regular symbol table first.
|
// Consult a regular symbol table first.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_SYMTAB, &symtab)) {
|
SHT_SYMTAB, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(
|
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
||||||
fd, &strtab, sizeof(strtab),
|
symtab.sh_link * sizeof(symtab))) {
|
||||||
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -372,9 +357,8 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
|||||||
// If the symbol is not found, then consult a dynamic symbol table.
|
// If the symbol is not found, then consult a dynamic symbol table.
|
||||||
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
if (GetSectionHeaderByType(fd, elf_header.e_shnum, elf_header.e_shoff,
|
||||||
SHT_DYNSYM, &symtab)) {
|
SHT_DYNSYM, &symtab)) {
|
||||||
if (!ReadFromOffsetExact(
|
if (!ReadFromOffsetExact(fd, &strtab, sizeof(strtab), elf_header.e_shoff +
|
||||||
fd, &strtab, sizeof(strtab),
|
symtab.sh_link * sizeof(symtab))) {
|
||||||
elf_header.e_shoff + symtab.sh_link * sizeof(symtab))) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
if (FindSymbol(pc, fd, out, out_size, base_address, &strtab, &symtab)) {
|
||||||
@ -386,15 +370,31 @@ static bool GetSymbolFromObjectFile(const int fd, uint64_t pc, char* out,
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
// Thin wrapper around a file descriptor so that the file descriptor
|
||||||
|
// gets closed for sure.
|
||||||
|
struct FileDescriptor {
|
||||||
|
const int fd_;
|
||||||
|
explicit FileDescriptor(int fd) : fd_(fd) {}
|
||||||
|
~FileDescriptor() {
|
||||||
|
if (fd_ >= 0) {
|
||||||
|
close(fd_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int get() { return fd_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
FileDescriptor(const FileDescriptor &) = delete;
|
||||||
|
void operator=(const FileDescriptor &) = delete;
|
||||||
|
};
|
||||||
|
|
||||||
// Helper class for reading lines from file.
|
// Helper class for reading lines from file.
|
||||||
//
|
//
|
||||||
// Note: we don't use ProcMapsIterator since the object is big (it has
|
// Note: we don't use ProcMapsIterator since the object is big (it has
|
||||||
// a 5k array member) and uses async-unsafe functions such as sscanf()
|
// a 5k array member) and uses async-unsafe functions such as sscanf()
|
||||||
// and std::snprintf().
|
// and snprintf().
|
||||||
class LineReader {
|
class LineReader {
|
||||||
public:
|
public:
|
||||||
explicit LineReader(int fd, char* buf, size_t buf_len, size_t offset)
|
explicit LineReader(int fd, char *buf, size_t buf_len, size_t offset)
|
||||||
: fd_(fd),
|
: fd_(fd),
|
||||||
buf_(buf),
|
buf_(buf),
|
||||||
buf_len_(buf_len),
|
buf_len_(buf_len),
|
||||||
@ -408,7 +408,7 @@ class LineReader {
|
|||||||
//
|
//
|
||||||
// Note: if the last line doesn't end with '\n', the line will be
|
// 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.
|
// 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.
|
if (BufferIsEmpty()) { // First time.
|
||||||
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
|
const ssize_t num_bytes = ReadFromOffset(fd_, buf_, buf_len_, offset_);
|
||||||
if (num_bytes <= 0) { // EOF or error.
|
if (num_bytes <= 0) { // EOF or error.
|
||||||
@ -419,13 +419,13 @@ class LineReader {
|
|||||||
bol_ = buf_;
|
bol_ = buf_;
|
||||||
} else {
|
} else {
|
||||||
bol_ = eol_ + 1; // Advance to the next line in the buffer.
|
bol_ = eol_ + 1; // Advance to the next line in the buffer.
|
||||||
GLOG_SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
|
SAFE_ASSERT(bol_ <= eod_); // "bol_" can point to "eod_".
|
||||||
if (!HasCompleteLine()) {
|
if (!HasCompleteLine()) {
|
||||||
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
|
const auto incomplete_line_length = static_cast<size_t>(eod_ - bol_);
|
||||||
// Move the trailing incomplete line to the beginning.
|
// Move the trailing incomplete line to the beginning.
|
||||||
memmove(buf_, bol_, incomplete_line_length);
|
memmove(buf_, bol_, incomplete_line_length);
|
||||||
// Read text from file and append it.
|
// 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 size_t capacity_left = buf_len_ - incomplete_line_length;
|
||||||
const ssize_t num_bytes =
|
const ssize_t num_bytes =
|
||||||
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
|
ReadFromOffset(fd_, append_pos, capacity_left, offset_);
|
||||||
@ -449,53 +449,57 @@ class LineReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Beginning of line.
|
// Beginning of line.
|
||||||
const char* bol() { return bol_; }
|
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_)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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() {
|
bool HasCompleteLine() {
|
||||||
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
return !BufferIsEmpty() && FindLineFeed() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int fd_;
|
const int fd_;
|
||||||
char* const buf_;
|
char * const buf_;
|
||||||
const size_t buf_len_;
|
const size_t buf_len_;
|
||||||
size_t offset_;
|
size_t offset_;
|
||||||
char* bol_;
|
char *bol_;
|
||||||
char* eol_;
|
char *eol_;
|
||||||
const char* eod_; // End of data in "buf_".
|
const char *eod_; // End of data in "buf_".
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// Place the hex number read from "start" into "*hex". The pointer to
|
// Place the hex number read from "start" into "*hex". The pointer to
|
||||||
// the first non-hex character or "end" is returned.
|
// 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;
|
*hex = 0;
|
||||||
const char* p;
|
const char *p;
|
||||||
for (p = start; p < end; ++p) {
|
for (p = start; p < end; ++p) {
|
||||||
int ch = *p;
|
int ch = *p;
|
||||||
if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') ||
|
if ((ch >= '0' && ch <= '9') ||
|
||||||
(ch >= 'a' && ch <= 'f')) {
|
(ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f')) {
|
||||||
*hex = (*hex << 4U) |
|
*hex = (*hex << 4U) | (ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
||||||
(ch < 'A' ? static_cast<uint64_t>(ch - '0') : (ch & 0xF) + 9U);
|
|
||||||
} else { // Encountered the first non-hex character.
|
} else { // Encountered the first non-hex character.
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
GLOG_SAFE_ASSERT(p <= end);
|
SAFE_ASSERT(p <= end);
|
||||||
return const_cast<char*>(p);
|
return const_cast<char *>(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches for the object file (from /proc/self/maps) that contains
|
// 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,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
static ATTRIBUTE_NOINLINE FileDescriptor
|
static ATTRIBUTE_NOINLINE int
|
||||||
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
||||||
uint64_t& start_address,
|
uint64_t &start_address,
|
||||||
uint64_t& base_address,
|
uint64_t &base_address,
|
||||||
char* out_file_name,
|
char *out_file_name,
|
||||||
size_t out_file_name_size) {
|
size_t out_file_name_size) {
|
||||||
FileDescriptor maps_fd{
|
int object_fd;
|
||||||
FailureRetry([] { return open("/proc/self/maps", O_RDONLY); })};
|
|
||||||
if (!maps_fd) {
|
int maps_fd;
|
||||||
return nullptr;
|
NO_INTR(maps_fd = open("/proc/self/maps", O_RDONLY));
|
||||||
|
FileDescriptor wrapped_maps_fd(maps_fd);
|
||||||
|
if (wrapped_maps_fd.get() < 0) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
FileDescriptor mem_fd{
|
int mem_fd;
|
||||||
FailureRetry([] { return open("/proc/self/mem", O_RDONLY); })};
|
NO_INTR(mem_fd = open("/proc/self/mem", O_RDONLY));
|
||||||
if (!mem_fd) {
|
FileDescriptor wrapped_mem_fd(mem_fd);
|
||||||
return nullptr;
|
if (wrapped_mem_fd.get() < 0) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over maps and look for the map containing the pc. Then
|
// Iterate over maps and look for the map containing the pc. Then
|
||||||
// look into the symbol tables inside.
|
// look into the symbol tables inside.
|
||||||
char buf[1024]; // Big enough for line of sane /proc/self/maps
|
char buf[1024]; // Big enough for line of sane /proc/self/maps
|
||||||
LineReader reader(maps_fd.get(), buf, sizeof(buf), 0);
|
LineReader reader(wrapped_maps_fd.get(), buf, sizeof(buf), 0);
|
||||||
while (true) {
|
while (true) {
|
||||||
const char* cursor;
|
const char *cursor;
|
||||||
const char* eol;
|
const char *eol;
|
||||||
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
|
if (!reader.ReadLine(&cursor, &eol)) { // EOF or malformed line.
|
||||||
return nullptr;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start parsing line in /proc/self/maps. Here is an example:
|
// Start parsing line in /proc/self/maps. Here is an example:
|
||||||
@ -545,7 +553,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
// Read start address.
|
// Read start address.
|
||||||
cursor = GetHex(cursor, eol, &start_address);
|
cursor = GetHex(cursor, eol, &start_address);
|
||||||
if (cursor == eol || *cursor != '-') {
|
if (cursor == eol || *cursor != '-') {
|
||||||
return nullptr; // Malformed line.
|
return -1; // Malformed line.
|
||||||
}
|
}
|
||||||
++cursor; // Skip '-'.
|
++cursor; // Skip '-'.
|
||||||
|
|
||||||
@ -553,26 +561,25 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
uint64_t end_address;
|
uint64_t end_address;
|
||||||
cursor = GetHex(cursor, eol, &end_address);
|
cursor = GetHex(cursor, eol, &end_address);
|
||||||
if (cursor == eol || *cursor != ' ') {
|
if (cursor == eol || *cursor != ' ') {
|
||||||
return nullptr; // Malformed line.
|
return -1; // Malformed line.
|
||||||
}
|
}
|
||||||
++cursor; // Skip ' '.
|
++cursor; // Skip ' '.
|
||||||
|
|
||||||
// Read flags. Skip flags until we encounter a space or eol.
|
// 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 != ' ') {
|
while (cursor < eol && *cursor != ' ') {
|
||||||
++cursor;
|
++cursor;
|
||||||
}
|
}
|
||||||
// We expect at least four letters for flags (ex. "r-xp").
|
// We expect at least four letters for flags (ex. "r-xp").
|
||||||
if (cursor == eol || cursor < flags_start + 4) {
|
if (cursor == eol || cursor < flags_start + 4) {
|
||||||
return nullptr; // Malformed line.
|
return -1; // Malformed line.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine the base address by reading ELF headers in process memory.
|
// Determine the base address by reading ELF headers in process memory.
|
||||||
ElfW(Ehdr) ehdr;
|
ElfW(Ehdr) ehdr;
|
||||||
// Skip non-readable maps.
|
// Skip non-readable maps.
|
||||||
if (flags_start[0] == 'r' &&
|
if (flags_start[0] == 'r' &&
|
||||||
ReadFromOffsetExact(mem_fd.get(), &ehdr, sizeof(ElfW(Ehdr)),
|
ReadFromOffsetExact(mem_fd, &ehdr, sizeof(ElfW(Ehdr)), start_address) &&
|
||||||
start_address) &&
|
|
||||||
memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
|
memcmp(ehdr.e_ident, ELFMAG, SELFMAG) == 0) {
|
||||||
switch (ehdr.e_type) {
|
switch (ehdr.e_type) {
|
||||||
case ET_EXEC:
|
case ET_EXEC:
|
||||||
@ -591,7 +598,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
|
for (unsigned i = 0; i != ehdr.e_phnum; ++i) {
|
||||||
ElfW(Phdr) phdr;
|
ElfW(Phdr) phdr;
|
||||||
if (ReadFromOffsetExact(
|
if (ReadFromOffsetExact(
|
||||||
mem_fd.get(), &phdr, sizeof(phdr),
|
mem_fd, &phdr, sizeof(phdr),
|
||||||
start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
|
start_address + ehdr.e_phoff + i * sizeof(phdr)) &&
|
||||||
phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
|
phdr.p_type == PT_LOAD && phdr.p_offset == 0) {
|
||||||
base_address = start_address - phdr.p_vaddr;
|
base_address = start_address - phdr.p_vaddr;
|
||||||
@ -607,11 +614,11 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check start and end addresses.
|
// Check start and end addresses.
|
||||||
if (start_address > pc || pc >= end_address) {
|
if (!(start_address <= pc && pc < end_address)) {
|
||||||
continue; // We skip this map. PC isn't in this map.
|
continue; // We skip this map. PC isn't in this map.
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check flags. We are only interested in "r*x" maps.
|
// Check flags. We are only interested in "r*x" maps.
|
||||||
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
|
if (flags_start[0] != 'r' || flags_start[2] != 'x') {
|
||||||
continue; // We skip this map.
|
continue; // We skip this map.
|
||||||
}
|
}
|
||||||
@ -621,7 +628,7 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
uint64_t file_offset;
|
uint64_t file_offset;
|
||||||
cursor = GetHex(cursor, eol, &file_offset);
|
cursor = GetHex(cursor, eol, &file_offset);
|
||||||
if (cursor == eol || *cursor != ' ') {
|
if (cursor == eol || *cursor != ' ') {
|
||||||
return nullptr; // Malformed line.
|
return -1; // Malformed line.
|
||||||
}
|
}
|
||||||
++cursor; // Skip ' '.
|
++cursor; // Skip ' '.
|
||||||
|
|
||||||
@ -639,16 +646,20 @@ OpenObjectFileContainingPcAndGetStartAddress(uint64_t pc,
|
|||||||
++cursor;
|
++cursor;
|
||||||
}
|
}
|
||||||
if (cursor == eol) {
|
if (cursor == eol) {
|
||||||
return nullptr; // Malformed line.
|
return -1; // Malformed line.
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
// Finally, "cursor" now points to file name of our interest.
|
||||||
return FileDescriptor{
|
NO_INTR(object_fd = open(cursor, O_RDONLY));
|
||||||
FailureRetry([cursor] { return 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';
|
||||||
|
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
|
// "sz" bytes. Output will be truncated as needed, and a NUL character is always
|
||||||
// appended.
|
// appended.
|
||||||
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
// NOTE: code from sandbox/linux/seccomp-bpf/demo.cc.
|
||||||
static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
|
static char *itoa_r(uintptr_t i, char *buf, size_t sz, unsigned base, size_t padding) {
|
||||||
size_t padding) {
|
|
||||||
// Make sure we can write at least one NUL byte.
|
// Make sure we can write at least one NUL byte.
|
||||||
size_t n = 1;
|
size_t n = 1;
|
||||||
if (n > sz) {
|
if (n > sz) {
|
||||||
@ -672,11 +682,11 @@ static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* start = buf;
|
char *start = buf;
|
||||||
|
|
||||||
// Loop until we have converted the entire number. Output at least one
|
// Loop until we have converted the entire number. Output at least one
|
||||||
// character (i.e. '0').
|
// character (i.e. '0').
|
||||||
char* ptr = start;
|
char *ptr = start;
|
||||||
do {
|
do {
|
||||||
// Make sure there is still enough space left in our output buffer.
|
// Make sure there is still enough space left in our output buffer.
|
||||||
if (++n > sz) {
|
if (++n > sz) {
|
||||||
@ -712,7 +722,7 @@ static char* itoa_r(uintptr_t i, char* buf, size_t sz, unsigned base,
|
|||||||
// buffer size |dest_size| and guarantees that |dest| is null-terminated.
|
// buffer size |dest_size| and guarantees that |dest| is null-terminated.
|
||||||
static void SafeAppendString(const char* source, char* dest, size_t dest_size) {
|
static void SafeAppendString(const char* source, char* dest, size_t dest_size) {
|
||||||
size_t dest_string_length = strlen(dest);
|
size_t dest_string_length = strlen(dest);
|
||||||
GLOG_SAFE_ASSERT(dest_string_length < dest_size);
|
SAFE_ASSERT(dest_string_length < dest_size);
|
||||||
dest += dest_string_length;
|
dest += dest_string_length;
|
||||||
dest_size -= dest_string_length;
|
dest_size -= dest_string_length;
|
||||||
strncpy(dest, source, dest_size);
|
strncpy(dest, source, dest_size);
|
||||||
@ -737,12 +747,12 @@ static void SafeAppendHexNumber(uint64_t value, char* dest, size_t dest_size) {
|
|||||||
// and "out" is used as its output.
|
// and "out" is used as its output.
|
||||||
// To keep stack consumption low, we would like this function to not
|
// To keep stack consumption low, we would like this function to not
|
||||||
// get inlined.
|
// get inlined.
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
||||||
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {
|
size_t out_size) {
|
||||||
auto pc0 = reinterpret_cast<uintptr_t>(pc);
|
auto pc0 = reinterpret_cast<uintptr_t>(pc);
|
||||||
uint64_t start_address = 0;
|
uint64_t start_address = 0;
|
||||||
uint64_t base_address = 0;
|
uint64_t base_address = 0;
|
||||||
FileDescriptor object_fd;
|
int object_fd = -1;
|
||||||
|
|
||||||
if (out_size < 1) {
|
if (out_size < 1) {
|
||||||
return false;
|
return false;
|
||||||
@ -751,19 +761,24 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
|||||||
SafeAppendString("(", out, out_size);
|
SafeAppendString("(", out, out_size);
|
||||||
|
|
||||||
if (g_symbolize_open_object_file_callback) {
|
if (g_symbolize_open_object_file_callback) {
|
||||||
object_fd.reset(g_symbolize_open_object_file_callback(
|
object_fd = g_symbolize_open_object_file_callback(pc0, start_address,
|
||||||
pc0, start_address, base_address, out + 1, out_size - 1));
|
base_address, out + 1,
|
||||||
|
out_size - 1);
|
||||||
} else {
|
} else {
|
||||||
object_fd = OpenObjectFileContainingPcAndGetStartAddress(
|
object_fd = OpenObjectFileContainingPcAndGetStartAddress(pc0, start_address,
|
||||||
pc0, start_address, base_address, out + 1, out_size - 1);
|
base_address,
|
||||||
|
out + 1,
|
||||||
|
out_size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
# 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.
|
// Check whether a file name was returned.
|
||||||
if (!object_fd) {
|
if (object_fd < 0) {
|
||||||
# endif
|
#endif
|
||||||
if (out[1]) {
|
if (out[1]) {
|
||||||
// The object file containing PC was determined successfully however the
|
// The object file containing PC was determined successfully however the
|
||||||
// object file was not opened successfully. This is still considered
|
// 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.
|
// Failed to determine the object file containing PC. Bail out.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int elf_type = FileGetElfType(object_fd.get());
|
int elf_type = FileGetElfType(wrapped_object_fd.get());
|
||||||
if (elf_type == -1) {
|
if (elf_type == -1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -787,15 +802,16 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
|||||||
// Note: relocation (and much of the rest of this code) will be
|
// Note: relocation (and much of the rest of this code) will be
|
||||||
// wrong for prelinked shared libraries and PIE executables.
|
// wrong for prelinked shared libraries and PIE executables.
|
||||||
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
uint64_t relocation = (elf_type == ET_DYN) ? start_address : 0;
|
||||||
int num_bytes_written =
|
int num_bytes_written = g_symbolize_callback(wrapped_object_fd.get(),
|
||||||
g_symbolize_callback(object_fd.get(), pc, out, out_size, relocation);
|
pc, out, out_size,
|
||||||
|
relocation);
|
||||||
if (num_bytes_written > 0) {
|
if (num_bytes_written > 0) {
|
||||||
out += static_cast<size_t>(num_bytes_written);
|
out += static_cast<size_t>(num_bytes_written);
|
||||||
out_size -= static_cast<size_t>(num_bytes_written);
|
out_size -= static_cast<size_t>(num_bytes_written);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!GetSymbolFromObjectFile(object_fd.get(), pc0, out, out_size,
|
if (!GetSymbolFromObjectFile(wrapped_object_fd.get(), pc0,
|
||||||
base_address)) {
|
out, out_size, base_address)) {
|
||||||
if (out[1] && !g_symbolize_callback) {
|
if (out[1] && !g_symbolize_callback) {
|
||||||
// The object file containing PC was opened successfully however the
|
// The object file containing PC was opened successfully however the
|
||||||
// symbol was not found. The object may have been stripped. This is still
|
// symbol was not found. The object may have been stripped. This is still
|
||||||
@ -815,20 +831,17 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
#elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
||||||
|
|
||||||
# include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
# include <cstring>
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
namespace google {
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
||||||
inline namespace glog_internal_namespace_ {
|
size_t out_size) {
|
||||||
|
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
|
||||||
void* pc, char* out, size_t out_size, SymbolizeOptions /*options*/) {
|
|
||||||
Dl_info info;
|
Dl_info info;
|
||||||
if (dladdr(pc, &info)) {
|
if (dladdr(pc, &info)) {
|
||||||
if (info.dli_sname) {
|
if (info.dli_sname) {
|
||||||
@ -843,30 +856,31 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
#elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
|
|
||||||
# include <dbghelp.h>
|
#include <windows.h>
|
||||||
# include <windows.h>
|
#include <dbghelp.h>
|
||||||
|
|
||||||
namespace google {
|
#ifdef _MSC_VER
|
||||||
inline namespace glog_internal_namespace_ {
|
#pragma comment(lib, "dbghelp")
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
class SymInitializer final {
|
class SymInitializer {
|
||||||
public:
|
public:
|
||||||
HANDLE process;
|
HANDLE process;
|
||||||
bool ready;
|
bool ready;
|
||||||
SymInitializer() : process(GetCurrentProcess()), ready(false) {
|
SymInitializer() : process(nullptr), ready(false) {
|
||||||
// Initialize the symbol handler.
|
// Initialize the symbol handler.
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680344(v=vs.85).aspx
|
||||||
|
process = GetCurrentProcess();
|
||||||
// Defer symbol loading.
|
// Defer symbol loading.
|
||||||
// We do not request undecorated symbols with SYMOPT_UNDNAME
|
// We do not request undecorated symbols with SYMOPT_UNDNAME
|
||||||
// because the mangling library calls UnDecorateSymbolName.
|
// because the mangling library calls UnDecorateSymbolName.
|
||||||
SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES);
|
SymSetOptions(SYMOPT_DEFERRED_LOADS);
|
||||||
if (SymInitialize(process, nullptr, true)) {
|
if (SymInitialize(process, nullptr, true)) {
|
||||||
ready = true;
|
ready = true;
|
||||||
}
|
}
|
||||||
@ -875,18 +889,13 @@ class SymInitializer final {
|
|||||||
SymCleanup(process);
|
SymCleanup(process);
|
||||||
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
// We do not need to close `HANDLE process` because it's a "pseudo handle."
|
||||||
}
|
}
|
||||||
|
private:
|
||||||
SymInitializer(const SymInitializer&) = delete;
|
SymInitializer(const SymInitializer&);
|
||||||
SymInitializer& operator=(const SymInitializer&) = delete;
|
SymInitializer& operator=(const SymInitializer&);
|
||||||
SymInitializer(SymInitializer&&) = delete;
|
|
||||||
SymInitializer& operator=(SymInitializer&&) = delete;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void *pc, char *out,
|
||||||
|
size_t out_size) {
|
||||||
static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
|
|
||||||
size_t out_size,
|
|
||||||
SymbolizeOptions options) {
|
|
||||||
const static SymInitializer symInitializer;
|
const static SymInitializer symInitializer;
|
||||||
if (!symInitializer.ready) {
|
if (!symInitializer.ready) {
|
||||||
return false;
|
return false;
|
||||||
@ -894,70 +903,52 @@ static ATTRIBUTE_NOINLINE bool SymbolizeAndDemangle(void* pc, char* out,
|
|||||||
// Resolve symbol information from address.
|
// Resolve symbol information from address.
|
||||||
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
|
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms680578(v=vs.85).aspx
|
||||||
char buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME];
|
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->SizeOfStruct = sizeof(SYMBOL_INFO);
|
||||||
symbol->MaxNameLen = MAX_SYM_NAME;
|
symbol->MaxNameLen = MAX_SYM_NAME;
|
||||||
// We use the ANSI version to ensure the string type is always `char *`.
|
// We use the ANSI version to ensure the string type is always `char *`.
|
||||||
// This could break if a symbol has Unicode in it.
|
// This could break if a symbol has Unicode in it.
|
||||||
BOOL ret = SymFromAddr(symInitializer.process, reinterpret_cast<DWORD64>(pc),
|
BOOL ret = SymFromAddr(symInitializer.process,
|
||||||
0, symbol);
|
reinterpret_cast<DWORD64>(pc), 0, symbol);
|
||||||
std::size_t namelen = static_cast<size_t>(symbol->NameLen);
|
if (ret == 1 && static_cast<ssize_t>(symbol->NameLen) < out_size) {
|
||||||
if (ret && namelen < out_size) {
|
// `NameLen` does not include the null terminating character.
|
||||||
std::strncpy(out, symbol->Name, namelen);
|
strncpy(out, symbol->Name, static_cast<size_t>(symbol->NameLen) + 1);
|
||||||
out[namelen] = '\0';
|
out[static_cast<size_t>(symbol->NameLen)] = '\0';
|
||||||
|
|
||||||
DWORD displacement;
|
|
||||||
IMAGEHLP_LINE64 line{sizeof(IMAGEHLP_LINE64)};
|
|
||||||
|
|
||||||
BOOL found = FALSE;
|
|
||||||
|
|
||||||
if ((options & SymbolizeOptions::kNoLineNumbers) !=
|
|
||||||
SymbolizeOptions::kNoLineNumbers) {
|
|
||||||
found = SymGetLineFromAddr64(symInitializer.process,
|
|
||||||
reinterpret_cast<DWORD64>(pc), &displacement,
|
|
||||||
&line);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbolization succeeded. Now we try to demangle the symbol.
|
// Symbolization succeeded. Now we try to demangle the symbol.
|
||||||
DemangleInplace(out, out_size);
|
DemangleInplace(out, out_size);
|
||||||
out_size -= std::strlen(out);
|
|
||||||
|
|
||||||
if (found) {
|
|
||||||
std::size_t fnlen = std::strlen(line.FileName);
|
|
||||||
// Determine the number of digits (base 10) necessary to represent the
|
|
||||||
// line number
|
|
||||||
std::size_t digits = 1; // At least one digit required
|
|
||||||
for (DWORD value = line.LineNumber; (value /= 10) != 0; ++digits) {
|
|
||||||
}
|
|
||||||
constexpr std::size_t extralen = 4; // space + parens () + :
|
|
||||||
const std::size_t suffixlen = fnlen + extralen + fnlen + digits;
|
|
||||||
|
|
||||||
if (suffixlen < out_size) {
|
|
||||||
out_size -= std::snprintf(out + namelen, out_size, " (%s:%lu)",
|
|
||||||
line.FileName, line.LineNumber);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
# else
|
#else
|
||||||
# error BUG: HAVE_SYMBOLIZE was wrongly set
|
# error BUG: HAVE_SYMBOLIZE was wrongly set
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
bool Symbolize(void* pc, char* out, size_t out_size, SymbolizeOptions options) {
|
bool Symbolize(void *pc, char *out, size_t out_size) {
|
||||||
return SymbolizeAndDemangle(pc, out, out_size, options);
|
return SymbolizeAndDemangle(pc, out, out_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
#else /* HAVE_SYMBOLIZE */
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
|
// TODO: Support other environments.
|
||||||
|
bool Symbolize(void* /*pc*/, char* /*out*/, size_t /*out_size*/) {
|
||||||
|
assert(0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
154
src/symbolize.h
154
src/symbolize.h
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -51,86 +51,59 @@
|
|||||||
// malloc() and other unsafe operations. It should be both
|
// malloc() and other unsafe operations. It should be both
|
||||||
// thread-safe and async-signal-safe.
|
// thread-safe and async-signal-safe.
|
||||||
|
|
||||||
#ifndef GLOG_INTERNAL_SYMBOLIZE_H
|
#ifndef BASE_SYMBOLIZE_H_
|
||||||
#define GLOG_INTERNAL_SYMBOLIZE_H
|
#define BASE_SYMBOLIZE_H_
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "glog/platform.h"
|
#include "glog/logging.h"
|
||||||
|
#include "utilities.h"
|
||||||
#if defined(HAVE_LINK_H)
|
|
||||||
# include <link.h> // For ElfW() macro.
|
|
||||||
#elif defined(HAVE_ELF_H)
|
|
||||||
# include <elf.h>
|
|
||||||
#elif defined(HAVE_SYS_EXEC_ELF_H)
|
|
||||||
# include <sys/exec_elf.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(GLOG_USE_GLOG_EXPORT)
|
|
||||||
# include "glog/export.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(GLOG_NO_EXPORT)
|
|
||||||
# error "symbolize.h" was not included correctly.
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// We prefer to let the build system detect the availability of certain features
|
|
||||||
// such as symbolization support. HAVE_SYMBOLIZE should therefore be defined by
|
|
||||||
// the build system in general unless there is a good reason to perform the
|
|
||||||
// detection using the preprocessor.
|
|
||||||
#ifndef GLOG_NO_SYMBOLIZE_DETECTION
|
|
||||||
# ifndef HAVE_SYMBOLIZE
|
|
||||||
// defined by gcc
|
|
||||||
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
|
|
||||||
# define HAVE_SYMBOLIZE
|
|
||||||
# elif defined(GLOG_OS_MACOSX) && defined(HAVE_DLADDR)
|
|
||||||
// Use dladdr to symbolize.
|
|
||||||
# define HAVE_SYMBOLIZE
|
|
||||||
# elif defined(GLOG_OS_WINDOWS)
|
|
||||||
// Use DbgHelp to symbolize
|
|
||||||
# define HAVE_SYMBOLIZE
|
|
||||||
# endif
|
|
||||||
# endif // !defined(HAVE_SYMBOLIZE)
|
|
||||||
#endif // !defined(GLOG_NO_SYMBOLIZE_DETECTION)
|
|
||||||
|
|
||||||
#ifdef HAVE_SYMBOLIZE
|
#ifdef HAVE_SYMBOLIZE
|
||||||
|
|
||||||
# if !defined(SIZEOF_VOID_P) && defined(__SIZEOF_POINTER__)
|
#if defined(__ELF__) // defined by gcc
|
||||||
# define SIZEOF_VOID_P __SIZEOF_POINTER__
|
#if defined(__OpenBSD__)
|
||||||
# endif
|
#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.
|
// If there is no ElfW macro, let's define it by ourself.
|
||||||
# ifndef ElfW
|
#ifndef ElfW
|
||||||
# if SIZEOF_VOID_P == 4
|
# if SIZEOF_VOID_P == 4
|
||||||
# define ElfW(type) Elf32_##type
|
# define ElfW(type) Elf32_##type
|
||||||
# elif SIZEOF_VOID_P == 8
|
# elif SIZEOF_VOID_P == 8
|
||||||
# define ElfW(type) Elf64_##type
|
# define ElfW(type) Elf64_##type
|
||||||
# else
|
# else
|
||||||
# error "Unknown sizeof(void *)"
|
# error "Unknown sizeof(void *)"
|
||||||
# endif
|
# endif
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Gets the section header for the given name, if it exists. Returns true on
|
// Gets the section header for the given name, if it exists. Returns true on
|
||||||
// success. Otherwise, returns false.
|
// success. Otherwise, returns false.
|
||||||
GLOG_NO_EXPORT
|
bool GetSectionHeaderByName(int fd, const char *name, size_t name_len,
|
||||||
bool GetSectionHeaderByName(int fd, const char* name, size_t name_len,
|
ElfW(Shdr) *out);
|
||||||
ElfW(Shdr) * out);
|
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
# endif
|
#endif /* __ELF__ */
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
// Restrictions on the callbacks that follow:
|
// Restrictions on the callbacks that follow:
|
||||||
// - The callbacks must not use heaps but only use stacks.
|
// - The callbacks must not use heaps but only use stacks.
|
||||||
@ -143,8 +116,8 @@ inline namespace glog_internal_namespace_ {
|
|||||||
// counter "pc". The callback function should write output to "out"
|
// counter "pc". The callback function should write output to "out"
|
||||||
// and return the size of the output written. On error, the callback
|
// and return the size of the output written. On error, the callback
|
||||||
// function should return -1.
|
// function should return -1.
|
||||||
using SymbolizeCallback = int (*)(int, void*, char*, size_t, uint64_t);
|
using SymbolizeCallback = int (*)(int, void *, char *, size_t, uint64_t);
|
||||||
GLOG_NO_EXPORT
|
GLOG_EXPORT
|
||||||
void InstallSymbolizeCallback(SymbolizeCallback callback);
|
void InstallSymbolizeCallback(SymbolizeCallback callback);
|
||||||
|
|
||||||
// Installs a callback function, which will be called instead of
|
// Installs a callback function, which will be called instead of
|
||||||
@ -157,54 +130,23 @@ void InstallSymbolizeCallback(SymbolizeCallback callback);
|
|||||||
// file is opened successfully, returns the file descriptor. Otherwise,
|
// file is opened successfully, returns the file descriptor. Otherwise,
|
||||||
// returns -1. |out_file_name_size| is the size of the file name buffer
|
// returns -1. |out_file_name_size| is the size of the file name buffer
|
||||||
// (including the null-terminator).
|
// (including the null-terminator).
|
||||||
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t&, uint64_t&,
|
using SymbolizeOpenObjectFileCallback = int (*)(uint64_t, uint64_t &,
|
||||||
char*, size_t);
|
uint64_t &, char *, size_t);
|
||||||
GLOG_NO_EXPORT
|
|
||||||
void InstallSymbolizeOpenObjectFileCallback(
|
void InstallSymbolizeOpenObjectFileCallback(
|
||||||
SymbolizeOpenObjectFileCallback callback);
|
SymbolizeOpenObjectFileCallback callback);
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
_END_GOOGLE_NAMESPACE_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
inline namespace glog_internal_namespace_ {
|
|
||||||
|
|
||||||
#if defined(HAVE_SYMBOLIZE)
|
|
||||||
|
|
||||||
enum class SymbolizeOptions {
|
|
||||||
// No additional options.
|
|
||||||
kNone = 0,
|
|
||||||
// Do not display source and line numbers in the symbolized output.
|
|
||||||
kNoLineNumbers = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr SymbolizeOptions operator&(SymbolizeOptions lhs,
|
|
||||||
SymbolizeOptions rhs) noexcept {
|
|
||||||
return static_cast<SymbolizeOptions>(
|
|
||||||
static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) &
|
|
||||||
static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr SymbolizeOptions operator|(SymbolizeOptions lhs,
|
|
||||||
SymbolizeOptions rhs) noexcept {
|
|
||||||
return static_cast<SymbolizeOptions>(
|
|
||||||
static_cast<std::underlying_type_t<SymbolizeOptions>>(lhs) |
|
|
||||||
static_cast<std::underlying_type_t<SymbolizeOptions>>(rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Symbolizes a program counter. On success, returns true and write the
|
// Symbolizes a program counter. On success, returns true and write the
|
||||||
// symbol name to "out". The symbol name is demangled if possible
|
// symbol name to "out". The symbol name is demangled if possible
|
||||||
// (supports symbols generated by GCC 3.x or newer). Otherwise,
|
// (supports symbols generated by GCC 3.x or newer). Otherwise,
|
||||||
// returns false.
|
// returns false.
|
||||||
GLOG_NO_EXPORT bool Symbolize(
|
GLOG_EXPORT bool Symbolize(void* pc, char* out, size_t out_size);
|
||||||
void* pc, char* out, size_t out_size,
|
|
||||||
SymbolizeOptions options = SymbolizeOptions::kNone);
|
|
||||||
|
|
||||||
#endif // defined(HAVE_SYMBOLIZE)
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
#endif // BASE_SYMBOLIZE_H_
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
#endif // GLOG_INTERNAL_SYMBOLIZE_H
|
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2006, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -40,57 +40,56 @@
|
|||||||
#include "glog/logging.h"
|
#include "glog/logging.h"
|
||||||
#include "googletest.h"
|
#include "googletest.h"
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
#include "stacktrace.h"
|
|
||||||
|
|
||||||
#ifdef GLOG_USE_GFLAGS
|
#ifdef HAVE_LIB_GFLAGS
|
||||||
# include <gflags/gflags.h>
|
#include <gflags/gflags.h>
|
||||||
using namespace GFLAGS_NAMESPACE;
|
using namespace GFLAGS_NAMESPACE;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace google;
|
using namespace GOOGLE_NAMESPACE;
|
||||||
|
|
||||||
// Avoid compile error due to "cast between pointer-to-function and
|
// Avoid compile error due to "cast between pointer-to-function and
|
||||||
// pointer-to-object is an extension" warnings.
|
// pointer-to-object is an extension" warnings.
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
# pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
# pragma GCC diagnostic ignored "-Wpedantic"
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE_STACKTRACE)
|
#if defined(HAVE_STACKTRACE)
|
||||||
|
|
||||||
# define always_inline
|
#define always_inline
|
||||||
|
|
||||||
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H) || \
|
#if defined(__ELF__) || defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
|
||||||
// A wrapper function for Symbolize() to make the unit test simple.
|
// A wrapper function for Symbolize() to make the unit test simple.
|
||||||
static const char* TrySymbolize(void* pc, google::SymbolizeOptions options =
|
static const char *TrySymbolize(void *pc) {
|
||||||
google::SymbolizeOptions::kNone) {
|
|
||||||
static char symbol[4096];
|
static char symbol[4096];
|
||||||
if (Symbolize(pc, symbol, sizeof(symbol), options)) {
|
if (Symbolize(pc, symbol, sizeof(symbol))) {
|
||||||
return symbol;
|
return symbol;
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
|
# if defined(__ELF__)
|
||||||
|
|
||||||
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
|
|
||||||
// This unit tests make sense only with GCC.
|
// This unit tests make sense only with GCC.
|
||||||
// Uses lots of GCC specific features.
|
// Uses lots of GCC specific features.
|
||||||
# if defined(__GNUC__) && !defined(__OPENCC__)
|
#if defined(__GNUC__) && !defined(__OPENCC__)
|
||||||
# if __GNUC__ >= 4
|
# if __GNUC__ >= 4
|
||||||
# define TEST_WITH_MODERN_GCC
|
# define TEST_WITH_MODERN_GCC
|
||||||
# if defined(__i386__) && __i386__ // always_inline isn't supported for
|
# if defined(__i386__) && __i386__ // always_inline isn't supported for x86_64 with GCC 4.1.0.
|
||||||
// x86_64 with GCC 4.1.0.
|
# undef always_inline
|
||||||
# undef always_inline
|
# define always_inline __attribute__((always_inline))
|
||||||
# define always_inline __attribute__((always_inline))
|
# define HAVE_ALWAYS_INLINE
|
||||||
# define HAVE_ALWAYS_INLINE
|
# endif // __i386__
|
||||||
# endif // __i386__
|
# else
|
||||||
# else
|
# endif // __GNUC__ >= 4
|
||||||
# endif // __GNUC__ >= 4
|
# if defined(__i386__) || defined(__x86_64__)
|
||||||
# define TEST_WITH_LABEL_ADDRESSES
|
# define TEST_X86_32_AND_64 1
|
||||||
# endif
|
# endif // defined(__i386__) || defined(__x86_64__)
|
||||||
|
#endif
|
||||||
|
|
||||||
// Make them C linkage to avoid mangled names.
|
// Make them C linkage to avoid mangled names.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@ -115,18 +114,18 @@ TEST(Symbolize, Symbolize) {
|
|||||||
// reinterpret_cast<void *>(&func).
|
// reinterpret_cast<void *>(&func).
|
||||||
|
|
||||||
// Compilers should give us pointers to them.
|
// 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
|
// The name of an internal linkage symbol is not specified; allow either a
|
||||||
// mangled or an unmangled name here.
|
// mangled or an unmangled name here.
|
||||||
const char* static_func_symbol =
|
const char *static_func_symbol =
|
||||||
TrySymbolize(reinterpret_cast<void*>(&static_func));
|
TrySymbolize(reinterpret_cast<void *>(&static_func));
|
||||||
|
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(nullptr != static_func_symbol);
|
CHECK(nullptr != static_func_symbol);
|
||||||
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
|
EXPECT_TRUE(strcmp("static_func", static_func_symbol) == 0 ||
|
||||||
strcmp("static_func()", static_func_symbol) == 0);
|
strcmp("static_func()", static_func_symbol) == 0);
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
|
EXPECT_TRUE(nullptr == TrySymbolize(nullptr));
|
||||||
}
|
}
|
||||||
@ -144,18 +143,14 @@ void ATTRIBUTE_NOINLINE Foo::func(int x) {
|
|||||||
|
|
||||||
// With a modern GCC, Symbolize() should return demangled symbol
|
// With a modern GCC, Symbolize() should return demangled symbol
|
||||||
// names. Function parameters should be omitted.
|
// names. Function parameters should be omitted.
|
||||||
# ifdef TEST_WITH_MODERN_GCC
|
#ifdef TEST_WITH_MODERN_GCC
|
||||||
TEST(Symbolize, SymbolizeWithDemangling) {
|
TEST(Symbolize, SymbolizeWithDemangling) {
|
||||||
Foo::func(100);
|
Foo::func(100);
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
# if defined(HAVE___CXA_DEMANGLE)
|
EXPECT_STREQ("Foo::func()", TrySymbolize((void *)(&Foo::func)));
|
||||||
EXPECT_STREQ("Foo::func(int)", TrySymbolize((void*)(&Foo::func)));
|
#endif
|
||||||
# else
|
|
||||||
EXPECT_STREQ("Foo::func()", TrySymbolize((void*)(&Foo::func)));
|
|
||||||
# endif
|
|
||||||
# endif
|
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
// Tests that verify that Symbolize footprint is within some limit.
|
// Tests that verify that Symbolize footprint is within some limit.
|
||||||
|
|
||||||
@ -174,9 +169,9 @@ TEST(Symbolize, SymbolizeWithDemangling) {
|
|||||||
// calls Symbolize. The difference between the stack consumption of these
|
// calls Symbolize. The difference between the stack consumption of these
|
||||||
// two signals handlers should give us the Symbolize stack foorprint.
|
// 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_buffer[4096];
|
||||||
static char* g_symbolize_result;
|
static char *g_symbolize_result;
|
||||||
|
|
||||||
static void EmptySignalHandler(int /*signo*/) {}
|
static void EmptySignalHandler(int /*signo*/) {}
|
||||||
|
|
||||||
@ -195,7 +190,7 @@ const char kAlternateStackFillValue = 0x55;
|
|||||||
// These helper functions look at the alternate stack buffer, and figure
|
// These helper functions look at the alternate stack buffer, and figure
|
||||||
// out what portion of this buffer has been touched - this is the stack
|
// out what portion of this buffer has been touched - this is the stack
|
||||||
// consumption of the signal handler running on this alternate 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;
|
int y;
|
||||||
return &y < x;
|
return &y < x;
|
||||||
}
|
}
|
||||||
@ -217,10 +212,11 @@ static int GetStackConsumption(const char* alt_stack) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef HAVE_SIGALTSTACK
|
#ifdef HAVE_SIGALTSTACK
|
||||||
|
|
||||||
// Call Symbolize and figure out the stack footprint of this call.
|
// Call Symbolize and figure out the stack footprint of this call.
|
||||||
static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
|
static const char *SymbolizeStackConsumption(void *pc, int *stack_consumed) {
|
||||||
|
|
||||||
g_pc_to_symbolize = pc;
|
g_pc_to_symbolize = pc;
|
||||||
|
|
||||||
// The alt-signal-stack cannot be heap allocated because there is a
|
// The alt-signal-stack cannot be heap allocated because there is a
|
||||||
@ -288,131 +284,118 @@ static const char* SymbolizeStackConsumption(void* pc, int* stack_consumed) {
|
|||||||
return g_symbolize_result;
|
return g_symbolize_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
# if !defined(HAVE___CXA_DEMANGLE)
|
#ifdef __ppc64__
|
||||||
# ifdef __ppc64__
|
|
||||||
// Symbolize stack consumption should be within 4kB.
|
// Symbolize stack consumption should be within 4kB.
|
||||||
constexpr int kStackConsumptionUpperLimit = 4096;
|
const int kStackConsumptionUpperLimit = 4096;
|
||||||
# else
|
#else
|
||||||
// Symbolize stack consumption should be within 2kB.
|
// Symbolize stack consumption should be within 2kB.
|
||||||
constexpr int kStackConsumptionUpperLimit = 2048;
|
const int kStackConsumptionUpperLimit = 2048;
|
||||||
# endif
|
#endif
|
||||||
# endif
|
|
||||||
|
|
||||||
TEST(Symbolize, SymbolizeStackConsumption) {
|
TEST(Symbolize, SymbolizeStackConsumption) {
|
||||||
int stack_consumed;
|
int stack_consumed;
|
||||||
const char* symbol;
|
const char* symbol;
|
||||||
|
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&nonstatic_func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&nonstatic_func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
EXPECT_STREQ("nonstatic_func", symbol);
|
EXPECT_STREQ("nonstatic_func", symbol);
|
||||||
EXPECT_GT(stack_consumed, 0);
|
EXPECT_GT(stack_consumed, 0);
|
||||||
# if !defined(HAVE___CXA_DEMANGLE)
|
|
||||||
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
||||||
# endif
|
|
||||||
|
|
||||||
// The name of an internal linkage symbol is not specified; allow either a
|
// The name of an internal linkage symbol is not specified; allow either a
|
||||||
// mangled or an unmangled name here.
|
// mangled or an unmangled name here.
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&static_func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&static_func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
CHECK(nullptr != symbol);
|
CHECK(nullptr != symbol);
|
||||||
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
|
EXPECT_TRUE(strcmp("static_func", symbol) == 0 ||
|
||||||
strcmp("static_func()", symbol) == 0);
|
strcmp("static_func()", symbol) == 0);
|
||||||
EXPECT_GT(stack_consumed, 0);
|
EXPECT_GT(stack_consumed, 0);
|
||||||
# if !defined(HAVE___CXA_DEMANGLE)
|
|
||||||
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
||||||
# endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# if defined(TEST_WITH_MODERN_GCC) && !defined(HAVE___CXA_DEMANGLE)
|
#ifdef TEST_WITH_MODERN_GCC
|
||||||
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
|
TEST(Symbolize, SymbolizeWithDemanglingStackConsumption) {
|
||||||
Foo::func(100);
|
Foo::func(100);
|
||||||
int stack_consumed;
|
int stack_consumed;
|
||||||
const char* symbol;
|
const char* symbol;
|
||||||
|
|
||||||
symbol = SymbolizeStackConsumption(reinterpret_cast<void*>(&Foo::func),
|
symbol = SymbolizeStackConsumption(reinterpret_cast<void *>(&Foo::func),
|
||||||
&stack_consumed);
|
&stack_consumed);
|
||||||
|
|
||||||
# if defined(HAVE___CXA_DEMANGLE)
|
|
||||||
EXPECT_STREQ("Foo::func(int)", symbol);
|
|
||||||
# else
|
|
||||||
EXPECT_STREQ("Foo::func()", symbol);
|
EXPECT_STREQ("Foo::func()", symbol);
|
||||||
# endif
|
|
||||||
EXPECT_GT(stack_consumed, 0);
|
EXPECT_GT(stack_consumed, 0);
|
||||||
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
EXPECT_LT(stack_consumed, kStackConsumptionUpperLimit);
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
# endif // HAVE_SIGALTSTACK
|
#endif // HAVE_SIGALTSTACK
|
||||||
|
|
||||||
// x86 specific tests. Uses some inline assembler.
|
// x86 specific tests. Uses some inline assembler.
|
||||||
extern "C" {
|
extern "C" {
|
||||||
inline void* always_inline inline_func() {
|
inline void* always_inline inline_func() {
|
||||||
void* pc = nullptr;
|
void *pc = nullptr;
|
||||||
# ifdef TEST_WITH_LABEL_ADDRESSES
|
#ifdef TEST_X86_32_AND_64
|
||||||
pc = &&curr_pc;
|
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
|
||||||
curr_pc:
|
#endif
|
||||||
# endif
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* ATTRIBUTE_NOINLINE non_inline_func();
|
void* ATTRIBUTE_NOINLINE non_inline_func();
|
||||||
void* ATTRIBUTE_NOINLINE non_inline_func() {
|
void* ATTRIBUTE_NOINLINE non_inline_func() {
|
||||||
void* pc = nullptr;
|
void *pc = nullptr;
|
||||||
# ifdef TEST_WITH_LABEL_ADDRESSES
|
#ifdef TEST_X86_32_AND_64
|
||||||
pc = &&curr_pc;
|
__asm__ __volatile__("call 1f; 1: pop %0" : "=r"(pc));
|
||||||
curr_pc:
|
#endif
|
||||||
# endif
|
|
||||||
return pc;
|
return pc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
|
static void ATTRIBUTE_NOINLINE TestWithPCInsideNonInlineFunction() {
|
||||||
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ATTRIBUTE_NOINLINE)
|
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
void* pc = non_inline_func();
|
void *pc = non_inline_func();
|
||||||
const char* symbol = TrySymbolize(pc);
|
const char *symbol = TrySymbolize(pc);
|
||||||
|
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "non_inline_func");
|
CHECK_STREQ(symbol, "non_inline_func");
|
||||||
# endif
|
#endif
|
||||||
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
|
cout << "Test case TestWithPCInsideNonInlineFunction passed." << endl;
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
|
static void ATTRIBUTE_NOINLINE TestWithPCInsideInlineFunction() {
|
||||||
# if defined(TEST_WITH_LABEL_ADDRESSES) && defined(HAVE_ALWAYS_INLINE)
|
#if defined(TEST_X86_32_AND_64) && defined(HAVE_ALWAYS_INLINE)
|
||||||
void* pc = inline_func(); // Must be inlined.
|
void *pc = inline_func(); // Must be inlined.
|
||||||
const char* symbol = TrySymbolize(pc);
|
const char *symbol = TrySymbolize(pc);
|
||||||
|
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, __FUNCTION__);
|
CHECK_STREQ(symbol, __FUNCTION__);
|
||||||
# endif
|
#endif
|
||||||
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
|
cout << "Test case TestWithPCInsideInlineFunction passed." << endl;
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test with a return address.
|
// Test with a return address.
|
||||||
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
|
static void ATTRIBUTE_NOINLINE TestWithReturnAddress() {
|
||||||
# if defined(HAVE_ATTRIBUTE_NOINLINE)
|
#if defined(HAVE_ATTRIBUTE_NOINLINE)
|
||||||
void* return_address = __builtin_return_address(0);
|
void *return_address = __builtin_return_address(0);
|
||||||
const char* symbol =
|
const char *symbol = TrySymbolize(return_address);
|
||||||
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
|
|
||||||
|
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "main");
|
CHECK_STREQ(symbol, "main");
|
||||||
# endif
|
#endif
|
||||||
cout << "Test case TestWithReturnAddress passed." << endl;
|
cout << "Test case TestWithReturnAddress passed." << endl;
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
|
|
||||||
# ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# include <intrin.h>
|
#include <intrin.h>
|
||||||
# pragma intrinsic(_ReturnAddress)
|
#pragma intrinsic(_ReturnAddress)
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
struct Foo {
|
struct Foo {
|
||||||
static void func(int x);
|
static void func(int x);
|
||||||
@ -427,38 +410,37 @@ __declspec(noinline) void Foo::func(int x) {
|
|||||||
|
|
||||||
TEST(Symbolize, SymbolizeWithDemangling) {
|
TEST(Symbolize, SymbolizeWithDemangling) {
|
||||||
Foo::func(100);
|
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);
|
EXPECT_STREQ("public: static void __cdecl Foo::func(int)", ret);
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
__declspec(noinline) void TestWithReturnAddress() {
|
__declspec(noinline) void TestWithReturnAddress() {
|
||||||
void* return_address =
|
void *return_address =
|
||||||
# ifdef __GNUC__ // Cygwin and MinGW support
|
#ifdef __GNUC__ // Cygwin and MinGW support
|
||||||
__builtin_return_address(0)
|
__builtin_return_address(0)
|
||||||
# else
|
#else
|
||||||
_ReturnAddress()
|
_ReturnAddress()
|
||||||
# endif
|
#endif
|
||||||
;
|
;
|
||||||
const char* symbol =
|
const char *symbol = TrySymbolize(return_address);
|
||||||
TrySymbolize(return_address, google::SymbolizeOptions::kNoLineNumbers);
|
#if !defined(_MSC_VER) || !defined(NDEBUG)
|
||||||
# if !defined(_MSC_VER) || !defined(NDEBUG)
|
|
||||||
CHECK(symbol != nullptr);
|
CHECK(symbol != nullptr);
|
||||||
CHECK_STREQ(symbol, "main");
|
CHECK_STREQ(symbol, "main");
|
||||||
# endif
|
#endif
|
||||||
cout << "Test case TestWithReturnAddress passed." << endl;
|
cout << "Test case TestWithReturnAddress passed." << endl;
|
||||||
}
|
}
|
||||||
# endif
|
# endif // __ELF__
|
||||||
#endif // HAVE_STACKTRACE
|
#endif // HAVE_STACKTRACE
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(int argc, char **argv) {
|
||||||
FLAGS_logtostderr = true;
|
FLAGS_logtostderr = true;
|
||||||
InitGoogleLogging(argv[0]);
|
InitGoogleLogging(argv[0]);
|
||||||
InitGoogleTest(&argc, argv);
|
InitGoogleTest(&argc, argv);
|
||||||
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
|
#if defined(HAVE_SYMBOLIZE) && defined(HAVE_STACKTRACE)
|
||||||
# if defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
|
# if defined(__ELF__)
|
||||||
// We don't want to get affected by the callback interface, that may be
|
// We don't want to get affected by the callback interface, that may be
|
||||||
// used to install some callback function at InitGoogle() time.
|
// used to install some callback function at InitGoogle() time.
|
||||||
InstallSymbolizeCallback(nullptr);
|
InstallSymbolizeCallback(nullptr);
|
||||||
@ -467,13 +449,13 @@ int main(int argc, char** argv) {
|
|||||||
TestWithPCInsideNonInlineFunction();
|
TestWithPCInsideNonInlineFunction();
|
||||||
TestWithReturnAddress();
|
TestWithReturnAddress();
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
# elif defined(GLOG_OS_WINDOWS) || defined(GLOG_OS_CYGWIN)
|
||||||
TestWithReturnAddress();
|
TestWithReturnAddress();
|
||||||
return RUN_ALL_TESTS();
|
return RUN_ALL_TESTS();
|
||||||
# else // GLOG_OS_WINDOWS
|
# else // GLOG_OS_WINDOWS
|
||||||
printf("PASS (no symbolize_unittest support)\n");
|
printf("PASS (no symbolize_unittest support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
# endif // defined(HAVE_ELF_H) || defined(HAVE_SYS_EXEC_ELF_H)
|
# endif // __ELF__
|
||||||
#else
|
#else
|
||||||
printf("PASS (no symbolize support)\n");
|
printf("PASS (no symbolize support)\n");
|
||||||
return 0;
|
return 0;
|
||||||
@ -481,5 +463,5 @@ int main(int argc, char** argv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__GNUG__)
|
#if defined(__GNUG__)
|
||||||
# pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
327
src/utilities.cc
327
src/utilities.cc
@ -1,4 +1,4 @@
|
|||||||
// Copyright (c) 2024, Google Inc.
|
// Copyright (c) 2008, Google Inc.
|
||||||
// All rights reserved.
|
// All rights reserved.
|
||||||
//
|
//
|
||||||
// Redistribution and use in source and binary forms, with or without
|
// Redistribution and use in source and binary forms, with or without
|
||||||
@ -29,51 +29,40 @@
|
|||||||
//
|
//
|
||||||
// Author: Shinichiro Hamaji
|
// Author: Shinichiro Hamaji
|
||||||
|
|
||||||
#define _GNU_SOURCE 1
|
#include "config.h"
|
||||||
|
|
||||||
#include "utilities.h"
|
#include "utilities.h"
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <cerrno>
|
|
||||||
#include <csignal>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
|
||||||
#include "base/googleinit.h"
|
#include <csignal>
|
||||||
#include "config.h"
|
|
||||||
#include "glog/flags.h"
|
|
||||||
#include "glog/logging.h"
|
|
||||||
#include "stacktrace.h"
|
|
||||||
#include "symbolize.h"
|
|
||||||
|
|
||||||
#ifdef GLOG_OS_ANDROID
|
|
||||||
# include <android/log.h>
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_SYS_TIME_H
|
#ifdef HAVE_SYS_TIME_H
|
||||||
# include <sys/time.h>
|
# include <sys/time.h>
|
||||||
#endif
|
#endif
|
||||||
|
#include <ctime>
|
||||||
#if defined(HAVE_SYSCALL_H)
|
#if defined(HAVE_SYSCALL_H)
|
||||||
# include <syscall.h> // for syscall()
|
#include <syscall.h> // for syscall()
|
||||||
#elif defined(HAVE_SYS_SYSCALL_H)
|
#elif defined(HAVE_SYS_SYSCALL_H)
|
||||||
# include <sys/syscall.h> // for syscall()
|
#include <sys/syscall.h> // for syscall()
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
# include <syslog.h>
|
# include <syslog.h>
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_UNISTD_H
|
#ifdef HAVE_UNISTD_H
|
||||||
# include <unistd.h> // For geteuid.
|
# include <unistd.h> // For geteuid.
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
# include <pwd.h>
|
# include <pwd.h>
|
||||||
|
#endif
|
||||||
|
#ifdef __ANDROID__
|
||||||
|
#include <android/log.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(HAVE___PROGNAME)
|
#include "base/googleinit.h"
|
||||||
extern char* __progname;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
static const char* g_program_invocation_short_name = nullptr;
|
static const char* g_program_invocation_short_name = nullptr;
|
||||||
|
|
||||||
@ -81,45 +70,19 @@ bool IsGoogleLoggingInitialized() {
|
|||||||
return g_program_invocation_short_name != nullptr;
|
return g_program_invocation_short_name != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline namespace glog_internal_namespace_ {
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
constexpr int FileDescriptor::InvalidHandle;
|
|
||||||
|
|
||||||
void AlsoErrorWrite(LogSeverity severity, const char* tag,
|
|
||||||
const char* message) noexcept {
|
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
|
||||||
(void)severity;
|
|
||||||
(void)tag;
|
|
||||||
// On Windows, also output to the debugger
|
|
||||||
::OutputDebugStringA(message);
|
|
||||||
#elif defined(GLOG_OS_ANDROID)
|
|
||||||
constexpr int android_log_levels[] = {
|
|
||||||
ANDROID_LOG_INFO,
|
|
||||||
ANDROID_LOG_WARN,
|
|
||||||
ANDROID_LOG_ERROR,
|
|
||||||
ANDROID_LOG_FATAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
__android_log_write(android_log_levels[severity], tag, message);
|
|
||||||
#else
|
|
||||||
(void)severity;
|
|
||||||
(void)tag;
|
|
||||||
(void)message;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
|
||||||
|
|
||||||
} // namespace google
|
|
||||||
|
|
||||||
// The following APIs are all internal.
|
// The following APIs are all internal.
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
|
|
||||||
# include "base/commandlineflags.h"
|
#include "stacktrace.h"
|
||||||
# include "stacktrace.h"
|
#include "symbolize.h"
|
||||||
# include "symbolize.h"
|
#include "base/commandlineflags.h"
|
||||||
|
|
||||||
namespace google {
|
GLOG_DEFINE_bool(symbolize_stacktrace, true,
|
||||||
|
"Symbolize the stack trace in the tombstone");
|
||||||
|
|
||||||
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
using DebugWriter = void(const char*, void*);
|
using DebugWriter = void(const char*, void*);
|
||||||
|
|
||||||
@ -127,67 +90,71 @@ using DebugWriter = void(const char*, void*);
|
|||||||
// For some environments, add two extra bytes for the leading "0x".
|
// For some environments, add two extra bytes for the leading "0x".
|
||||||
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
|
static const int kPrintfPointerFieldWidth = 2 + 2 * sizeof(void*);
|
||||||
|
|
||||||
static void DebugWriteToStderr(const char* data, void*) {
|
static void DebugWriteToStderr(const char* data, void *) {
|
||||||
// This one is signal-safe.
|
// This one is signal-safe.
|
||||||
if (write(fileno(stderr), data, strlen(data)) < 0) {
|
if (write(STDERR_FILENO, data, strlen(data)) < 0) {
|
||||||
// Ignore errors.
|
// Ignore errors.
|
||||||
}
|
}
|
||||||
AlsoErrorWrite(GLOG_FATAL,
|
#if defined(__ANDROID__)
|
||||||
glog_internal_namespace_::ProgramInvocationShortName(), data);
|
// ANDROID_LOG_FATAL as fatal error occurred and now is dumping call stack.
|
||||||
|
__android_log_write(ANDROID_LOG_FATAL,
|
||||||
|
glog_internal_namespace_::ProgramInvocationShortName(),
|
||||||
|
data);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DebugWriteToString(const char* data, void* arg) {
|
static void DebugWriteToString(const char* data, void *arg) {
|
||||||
reinterpret_cast<string*>(arg)->append(data);
|
reinterpret_cast<string*>(arg)->append(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef HAVE_SYMBOLIZE
|
#ifdef HAVE_SYMBOLIZE
|
||||||
// Print a program counter and its symbol name.
|
// Print a program counter and its symbol name.
|
||||||
static void DumpPCAndSymbol(DebugWriter* writerfn, void* arg, void* pc,
|
static void DumpPCAndSymbol(DebugWriter *writerfn, void *arg, void *pc,
|
||||||
const char* const prefix) {
|
const char * const prefix) {
|
||||||
char tmp[1024];
|
char tmp[1024];
|
||||||
const char* symbol = "(unknown)";
|
const char *symbol = "(unknown)";
|
||||||
// Symbolizes the previous address of pc because pc may be in the
|
// Symbolizes the previous address of pc because pc may be in the
|
||||||
// next function. The overrun happens when the function ends with
|
// next function. The overrun happens when the function ends with
|
||||||
// a call to a function annotated noreturn (e.g. CHECK).
|
// 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;
|
symbol = tmp;
|
||||||
}
|
}
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
std::snprintf(buf, sizeof(buf), "%s@ %*p %s\n", prefix,
|
snprintf(buf, sizeof(buf), "%s@ %*p %s\n",
|
||||||
kPrintfPointerFieldWidth, pc, symbol);
|
prefix, kPrintfPointerFieldWidth, pc, symbol);
|
||||||
writerfn(buf, arg);
|
writerfn(buf, arg);
|
||||||
}
|
}
|
||||||
# endif
|
#endif
|
||||||
|
|
||||||
static void DumpPC(DebugWriter* writerfn, void* arg, void* pc,
|
static void DumpPC(DebugWriter *writerfn, void *arg, void *pc,
|
||||||
const char* const prefix) {
|
const char * const prefix) {
|
||||||
char buf[100];
|
char buf[100];
|
||||||
std::snprintf(buf, sizeof(buf), "%s@ %*p\n", prefix, kPrintfPointerFieldWidth,
|
snprintf(buf, sizeof(buf), "%s@ %*p\n",
|
||||||
pc);
|
prefix, kPrintfPointerFieldWidth, pc);
|
||||||
writerfn(buf, arg);
|
writerfn(buf, arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Dump current stack trace as directed by writerfn
|
// 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
|
// Print stack trace
|
||||||
void* stack[32];
|
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++) {
|
for (int i = 0; i < depth; i++) {
|
||||||
# if defined(HAVE_SYMBOLIZE)
|
#if defined(HAVE_SYMBOLIZE)
|
||||||
if (FLAGS_symbolize_stacktrace) {
|
if (FLAGS_symbolize_stacktrace) {
|
||||||
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
|
DumpPCAndSymbol(writerfn, arg, stack[i], " ");
|
||||||
} else {
|
} else {
|
||||||
DumpPC(writerfn, arg, stack[i], " ");
|
DumpPC(writerfn, arg, stack[i], " ");
|
||||||
}
|
}
|
||||||
# else
|
#else
|
||||||
DumpPC(writerfn, arg, stack[i], " ");
|
DumpPC(writerfn, arg, stack[i], " ");
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
__attribute__((noreturn))
|
__attribute__((noreturn))
|
||||||
# endif
|
#endif
|
||||||
static void
|
static void
|
||||||
DumpStackTraceAndExit() {
|
DumpStackTraceAndExit() {
|
||||||
DumpStackTrace(1, DebugWriteToStderr, nullptr);
|
DumpStackTrace(1, DebugWriteToStderr, nullptr);
|
||||||
@ -196,55 +163,88 @@ DumpStackTraceAndExit() {
|
|||||||
if (IsFailureSignalHandlerInstalled()) {
|
if (IsFailureSignalHandlerInstalled()) {
|
||||||
// Set the default signal handler for SIGABRT, to avoid invoking our
|
// Set the default signal handler for SIGABRT, to avoid invoking our
|
||||||
// own signal handler installed by InstallFailureSignalHandler().
|
// own signal handler installed by InstallFailureSignalHandler().
|
||||||
# ifdef HAVE_SIGACTION
|
#ifdef HAVE_SIGACTION
|
||||||
struct sigaction sig_action;
|
struct sigaction sig_action;
|
||||||
memset(&sig_action, 0, sizeof(sig_action));
|
memset(&sig_action, 0, sizeof(sig_action));
|
||||||
sigemptyset(&sig_action.sa_mask);
|
sigemptyset(&sig_action.sa_mask);
|
||||||
sig_action.sa_handler = SIG_DFL;
|
sig_action.sa_handler = SIG_DFL;
|
||||||
sigaction(SIGABRT, &sig_action, nullptr);
|
sigaction(SIGABRT, &sig_action, nullptr);
|
||||||
# elif defined(GLOG_OS_WINDOWS)
|
#elif defined(GLOG_OS_WINDOWS)
|
||||||
signal(SIGABRT, SIG_DFL);
|
signal(SIGABRT, SIG_DFL);
|
||||||
# endif // HAVE_SIGACTION
|
#endif // HAVE_SIGACTION
|
||||||
}
|
}
|
||||||
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace google
|
_END_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
#endif // HAVE_STACKTRACE
|
#endif // HAVE_STACKTRACE
|
||||||
|
|
||||||
namespace google {
|
_START_GOOGLE_NAMESPACE_
|
||||||
|
|
||||||
inline namespace glog_internal_namespace_ {
|
namespace glog_internal_namespace_ {
|
||||||
|
|
||||||
const char* const_basename(const char* filepath) {
|
|
||||||
const char* base = strrchr(filepath, '/');
|
|
||||||
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
|
||||||
if (!base) base = strrchr(filepath, '\\');
|
|
||||||
#endif
|
|
||||||
return base ? (base + 1) : filepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* ProgramInvocationShortName() {
|
const char* ProgramInvocationShortName() {
|
||||||
if (g_program_invocation_short_name != nullptr) {
|
if (g_program_invocation_short_name != nullptr) {
|
||||||
return g_program_invocation_short_name;
|
return g_program_invocation_short_name;
|
||||||
|
} else {
|
||||||
|
// TODO(hamaji): Use /proc/self/cmdline and so?
|
||||||
|
return "UNKNOWN";
|
||||||
}
|
}
|
||||||
#if defined(HAVE_PROGRAM_INVOCATION_SHORT_NAME)
|
}
|
||||||
return program_invocation_short_name;
|
|
||||||
#elif defined(HAVE_GETPROGNAME)
|
#ifdef GLOG_OS_WINDOWS
|
||||||
return getprogname();
|
struct timeval {
|
||||||
#elif defined(HAVE___PROGNAME)
|
long tv_sec, tv_usec;
|
||||||
return __progname;
|
};
|
||||||
#elif defined(HAVE___ARGV)
|
|
||||||
return const_basename(__argv[0]);
|
// Based on: http://www.google.com/codesearch/p?hl=en#dR3YEbitojA/os_win32.c&q=GetSystemTimeAsFileTime%20license:bsd
|
||||||
#else
|
// See COPYING for copyright information.
|
||||||
return "UNKNOWN";
|
static int gettimeofday(struct timeval *tv, void* /*tz*/) {
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wlong-long"
|
||||||
#endif
|
#endif
|
||||||
|
#define EPOCHFILETIME (116444736000000000ULL)
|
||||||
|
FILETIME ft;
|
||||||
|
ULARGE_INTEGER li;
|
||||||
|
uint64 tt;
|
||||||
|
|
||||||
|
GetSystemTimeAsFileTime(&ft);
|
||||||
|
li.LowPart = ft.dwLowDateTime;
|
||||||
|
li.HighPart = ft.dwHighDateTime;
|
||||||
|
tt = (li.QuadPart - EPOCHFILETIME) / 10;
|
||||||
|
tv->tv_sec = tt / 1000000;
|
||||||
|
tv->tv_usec = tt % 1000000;
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int64 CycleClock_Now() {
|
||||||
|
// TODO(hamaji): temporary impementation - it might be too slow.
|
||||||
|
struct timeval tv;
|
||||||
|
gettimeofday(&tv, nullptr);
|
||||||
|
return static_cast<int64>(tv.tv_sec) * 1000000 + tv.tv_usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64 UsecToCycles(int64 usec) {
|
||||||
|
return usec;
|
||||||
|
}
|
||||||
|
|
||||||
|
WallTime WallTime_Now() {
|
||||||
|
// Now, cycle clock is retuning microseconds since the epoch.
|
||||||
|
return CycleClock_Now() * 0.000001;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32 g_main_thread_pid = getpid();
|
static int32 g_main_thread_pid = getpid();
|
||||||
int32 GetMainThreadPid() { return g_main_thread_pid; }
|
int32 GetMainThreadPid() {
|
||||||
|
return g_main_thread_pid;
|
||||||
|
}
|
||||||
|
|
||||||
bool PidHasChanged() {
|
bool PidHasChanged() {
|
||||||
int32 pid = getpid();
|
int32 pid = getpid();
|
||||||
@ -255,8 +255,66 @@ bool PidHasChanged() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t GetTID() {
|
||||||
|
// On Linux and MacOSX, we try to use gettid().
|
||||||
|
#if defined GLOG_OS_LINUX || defined GLOG_OS_MACOSX
|
||||||
|
#ifndef __NR_gettid
|
||||||
|
#ifdef GLOG_OS_MACOSX
|
||||||
|
#define __NR_gettid SYS_gettid
|
||||||
|
#elif ! defined __i386__
|
||||||
|
#error "Must define __NR_gettid for non-x86 platforms"
|
||||||
|
#else
|
||||||
|
#define __NR_gettid 224
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
static bool lacks_gettid = false;
|
||||||
|
if (!lacks_gettid) {
|
||||||
|
#if (defined(GLOG_OS_MACOSX) && defined(HAVE_PTHREAD_THREADID_NP))
|
||||||
|
uint64_t tid64;
|
||||||
|
const int error = pthread_threadid_np(nullptr, &tid64);
|
||||||
|
pid_t tid = error ? -1 : static_cast<pid_t>(tid64);
|
||||||
|
#else
|
||||||
|
auto tid = static_cast<pid_t>(syscall(__NR_gettid));
|
||||||
|
#endif
|
||||||
|
if (tid != -1) {
|
||||||
|
return tid;
|
||||||
|
}
|
||||||
|
// Technically, this variable has to be volatile, but there is a small
|
||||||
|
// performance penalty in accessing volatile variables and there should
|
||||||
|
// not be any serious adverse effect if a thread does not immediately see
|
||||||
|
// the value change to "true".
|
||||||
|
lacks_gettid = true;
|
||||||
|
}
|
||||||
|
#endif // GLOG_OS_LINUX || GLOG_OS_MACOSX
|
||||||
|
|
||||||
|
// If gettid() could not be used, we use one of the following.
|
||||||
|
#if defined GLOG_OS_LINUX
|
||||||
|
return getpid(); // Linux: getpid returns thread ID when gettid is absent
|
||||||
|
#elif defined GLOG_OS_WINDOWS && !defined GLOG_OS_CYGWIN
|
||||||
|
return static_cast<pid_t>(GetCurrentThreadId());
|
||||||
|
#elif defined GLOG_OS_OPENBSD
|
||||||
|
return getthrid();
|
||||||
|
#elif defined(HAVE_PTHREAD)
|
||||||
|
// If none of the techniques above worked, we use pthread_self().
|
||||||
|
return (pid_t)(uintptr_t)pthread_self();
|
||||||
|
#else
|
||||||
|
return -1;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* const_basename(const char* filepath) {
|
||||||
|
const char* base = strrchr(filepath, '/');
|
||||||
|
#ifdef GLOG_OS_WINDOWS // Look for either path separator in Windows
|
||||||
|
if (!base)
|
||||||
|
base = strrchr(filepath, '\\');
|
||||||
|
#endif
|
||||||
|
return base ? (base+1) : filepath;
|
||||||
|
}
|
||||||
|
|
||||||
static string g_my_user_name;
|
static string g_my_user_name;
|
||||||
const string& MyUserName() { return g_my_user_name; }
|
const string& MyUserName() {
|
||||||
|
return g_my_user_name;
|
||||||
|
}
|
||||||
static void MyUserNameInitializer() {
|
static void MyUserNameInitializer() {
|
||||||
// TODO(hamaji): Probably this is not portable.
|
// TODO(hamaji): Probably this is not portable.
|
||||||
#if defined(GLOG_OS_WINDOWS)
|
#if defined(GLOG_OS_WINDOWS)
|
||||||
@ -276,7 +334,7 @@ static void MyUserNameInitializer() {
|
|||||||
if (pwuid_res == 0 && result) {
|
if (pwuid_res == 0 && result) {
|
||||||
g_my_user_name = pwd.pw_name;
|
g_my_user_name = pwd.pw_name;
|
||||||
} else {
|
} else {
|
||||||
std::snprintf(buffer, sizeof(buffer), "uid%d", uid);
|
snprintf(buffer, sizeof(buffer), "uid%d", uid);
|
||||||
g_my_user_name = buffer;
|
g_my_user_name = buffer;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -287,19 +345,30 @@ static void MyUserNameInitializer() {
|
|||||||
}
|
}
|
||||||
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())
|
REGISTER_MODULE_INITIALIZER(utilities, MyUserNameInitializer())
|
||||||
|
|
||||||
|
#ifdef HAVE_STACKTRACE
|
||||||
|
void DumpStackTraceToString(string* stacktrace) {
|
||||||
|
DumpStackTrace(1, DebugWriteToString, stacktrace);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
// We use an atomic operation to prevent problems with calling CrashReason
|
// We use an atomic operation to prevent problems with calling CrashReason
|
||||||
// from inside the Mutex implementation (potentially through RAW_CHECK).
|
// from inside the Mutex implementation (potentially through RAW_CHECK).
|
||||||
static std::atomic<const logging::internal::CrashReason*> g_reason{nullptr};
|
static const CrashReason* g_reason = nullptr;
|
||||||
|
|
||||||
void SetCrashReason(const logging::internal::CrashReason* r) {
|
void SetCrashReason(const CrashReason* r) {
|
||||||
const logging::internal::CrashReason* expected = nullptr;
|
sync_val_compare_and_swap(&g_reason,
|
||||||
g_reason.compare_exchange_strong(expected, r);
|
reinterpret_cast<const CrashReason*>(0),
|
||||||
|
r);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InitGoogleLoggingUtilities(const char* argv0) {
|
void InitGoogleLoggingUtilities(const char* argv0) {
|
||||||
CHECK(!IsGoogleLoggingInitialized())
|
CHECK(!IsGoogleLoggingInitialized())
|
||||||
<< "You called InitGoogleLogging() twice!";
|
<< "You called InitGoogleLogging() twice!";
|
||||||
g_program_invocation_short_name = const_basename(argv0);
|
const char* slash = strrchr(argv0, '/');
|
||||||
|
#ifdef GLOG_OS_WINDOWS
|
||||||
|
if (!slash) slash = strrchr(argv0, '\\');
|
||||||
|
#endif
|
||||||
|
g_program_invocation_short_name = slash ? slash + 1 : argv0;
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
#ifdef HAVE_STACKTRACE
|
||||||
InstallFailureFunction(&DumpStackTraceAndExit);
|
InstallFailureFunction(&DumpStackTraceAndExit);
|
||||||
@ -308,8 +377,7 @@ void InitGoogleLoggingUtilities(const char* argv0) {
|
|||||||
|
|
||||||
void ShutdownGoogleLoggingUtilities() {
|
void ShutdownGoogleLoggingUtilities() {
|
||||||
CHECK(IsGoogleLoggingInitialized())
|
CHECK(IsGoogleLoggingInitialized())
|
||||||
<< "You called ShutdownGoogleLogging() without calling "
|
<< "You called ShutdownGoogleLogging() without calling InitGoogleLogging() first!";
|
||||||
"InitGoogleLogging() first!";
|
|
||||||
g_program_invocation_short_name = nullptr;
|
g_program_invocation_short_name = nullptr;
|
||||||
#ifdef HAVE_SYSLOG_H
|
#ifdef HAVE_SYSLOG_H
|
||||||
closelog();
|
closelog();
|
||||||
@ -318,12 +386,17 @@ void ShutdownGoogleLoggingUtilities() {
|
|||||||
|
|
||||||
} // namespace glog_internal_namespace_
|
} // namespace glog_internal_namespace_
|
||||||
|
|
||||||
#ifdef HAVE_STACKTRACE
|
_END_GOOGLE_NAMESPACE_
|
||||||
std::string GetStackTrace() {
|
|
||||||
std::string stacktrace;
|
|
||||||
DumpStackTrace(1, DebugWriteToString, &stacktrace);
|
|
||||||
return stacktrace;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} // namespace google
|
// Make an implementation of stacktrace compiled.
|
||||||
|
#ifdef STACKTRACE_H
|
||||||
|
# include STACKTRACE_H
|
||||||
|
# if 0
|
||||||
|
// For include scanners which can't handle macro expansions.
|
||||||
|
# include "stacktrace_libunwind-inl.h"
|
||||||
|
# include "stacktrace_x86-inl.h"
|
||||||
|
# include "stacktrace_x86_64-inl.h"
|
||||||
|
# include "stacktrace_powerpc-inl.h"
|
||||||
|
# include "stacktrace_generic-inl.h"
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user